Commit 71f3f4aa by suyuchen

feat(navigation): 更新侧边栏导航结构并新增客户信息页面

- 重命名服务管理为客户,调整导航菜单结构 - 新增设备管理和服务订单子菜单 - 将人工管理、零件管理、报价管理重新组织到合适位置 - 创建全新的客户信息页面,包含完整的页面结构和样式 - 更新信息原页面为信息源统计,调整表格显示字段 - 在工单列表中新增优先级调整相关图片 - 新增服务价格说明文档
parent 6091c061
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1767750456744" class="icon" viewBox="0 0 1204 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10768" xmlns:xlink="http://www.w3.org/1999/xlink" width="235.15625" height="200"><path d="M1241.702 391.831l2.1 1.663q-1.035-0.875-2.1-1.663zM-38.708 394.223l3.792-3.004c-4.553 3.167-8.267 7.216-10.964 11.922z" p-id="10769" fill="#f4ea2a"></path><path d="M94.676 1025.202c-0.335 2.246-0.686 4.478-0.991 6.738 0.632-2.397 1.004-5.153 1.025-7.992zM61.057 1057.29zM27.48 1021.133q0.365-2.523 0.758-5.046c-0.512 2.136-0.819 4.598-0.846 7.124z" p-id="10770" fill="#f4ea2a"></path><path d="M1178.516 1013.3c0.422 2.64 0.802 5.294 1.181 7.948-0.106-3.188-0.621-6.214-1.497-9.083zM1111.032 1030.643c-0.291-2.086-0.597-4.157-0.919-6.228 0.164 2.851 0.645 5.522 1.408 8.070z" p-id="10771" fill="#f4ea2a"></path><path d="M994.8 313.771h-46.018l-24.591 139.174h41.743q41.29 0 66.012-18.581t30.848-53.265q11.874-67.326-67.997-67.326z" p-id="10772" fill="#f4ea2a"></path><path d="M1149.333 204.992h-1092.943c-0.012 0-0.027 0-0.045 0-31.855 0-57.681 25.807-57.715 57.653v374.76c0.031 31.85 25.86 57.656 57.715 57.656 0.014 0 0.029 0 0.047 0h1092.94c0.012 0 0.027 0 0.045 0 31.855 0 57.681-25.807 57.715-57.653v-374.76c-0.031-31.85-25.86-57.656-57.715-57.656-0.014 0-0.029 0-0.047 0zM369.493 329.989q-27.712-21.877-76.005-21.877-32.088 0-54.608 13.404t-26.909 37.296q-3.734 21.179 7.907 34.451t54.345 36.347q47.111 24.549 63.3 49.094t10.779 55.176q-8.11 45.945-45.841 70.491t-97.067 24.474c-17.979-0.282-35.277-2.606-51.855-6.749q-22.166-4.73-33.28-13.291l9.072-51.34q13.55 13.973 38.811 22.972c14.958 5.68 32.253 8.984 50.316 9.019q72.64-0.004 81.872-52.25c0.54-2.515 0.852-5.406 0.852-8.369 0-6.535-1.509-12.719-4.2-18.219-5.953-11.315-15.433-20.387-26.978-25.774q-3.119-3.718-37.716-22.433-47.957-26.123-60.69-48.54t-7.643-51.239q7.686-43.465 47.155-68.916t92.748-25.436q52.114 0 74.254 12.616zM485.608 622.995l-64.35-348.854h50.086l45.9 272.748c1.11 6.694 1.743 14.408 1.743 22.27 0 3.177-0.105 6.33-0.309 9.456l1.145-0.425c6.745-22.026 17.444-41.077 31.384-57.255l126.109-246.778h48.278l-189.974 348.84h-50.086zM813.226 312.195l-48.131 272.748h33.546l-6.723 38.068h-112.307l6.723-38.068h33.546l48.131-272.748h-33.533l6.723-38.068h112.307l-6.723 38.068h-33.546zM1110.475 379.288q-9.072 51.355-51.253 83.21t-96.701 30.075h-45.331l-23.030 130.393h-45.141l61.594-348.824h99.283q56.635 0 83.137 27.246t17.4 77.93z" p-id="10773" fill="#f4ea2a"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1767750456744" class="icon" viewBox="0 0 1204 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10768" xmlns:xlink="http://www.w3.org/1999/xlink" width="235.15625" height="200"><path d="M1241.702 391.831l2.1 1.663q-1.035-0.875-2.1-1.663zM-38.708 394.223l3.792-3.004c-4.553 3.167-8.267 7.216-10.964 11.922z" p-id="10769" fill="#f4ea2a"></path><path d="M94.676 1025.202c-0.335 2.246-0.686 4.478-0.991 6.738 0.632-2.397 1.004-5.153 1.025-7.992zM61.057 1057.29zM27.48 1021.133q0.365-2.523 0.758-5.046c-0.512 2.136-0.819 4.598-0.846 7.124z" p-id="10770" fill="#f4ea2a"></path><path d="M1178.516 1013.3c0.422 2.64 0.802 5.294 1.181 7.948-0.106-3.188-0.621-6.214-1.497-9.083zM1111.032 1030.643c-0.291-2.086-0.597-4.157-0.919-6.228 0.164 2.851 0.645 5.522 1.408 8.070z" p-id="10771" fill="#f4ea2a"></path><path d="M994.8 313.771h-46.018l-24.591 139.174h41.743q41.29 0 66.012-18.581t30.848-53.265q11.874-67.326-67.997-67.326z" p-id="10772" fill="#f4ea2a"></path><path d="M1149.333 204.992h-1092.943c-0.012 0-0.027 0-0.045 0-31.855 0-57.681 25.807-57.715 57.653v374.76c0.031 31.85 25.86 57.656 57.715 57.656 0.014 0 0.029 0 0.047 0h1092.94c0.012 0 0.027 0 0.045 0 31.855 0 57.681-25.807 57.715-57.653v-374.76c-0.031-31.85-25.86-57.656-57.715-57.656-0.014 0-0.029 0-0.047 0zM369.493 329.989q-27.712-21.877-76.005-21.877-32.088 0-54.608 13.404t-26.909 37.296q-3.734 21.179 7.907 34.451t54.345 36.347q47.111 24.549 63.3 49.094t10.779 55.176q-8.11 45.945-45.841 70.491t-97.067 24.474c-17.979-0.282-35.277-2.606-51.855-6.749q-22.166-4.73-33.28-13.291l9.072-51.34q13.55 13.973 38.811 22.972c14.958 5.68 32.253 8.984 50.316 9.019q72.64-0.004 81.872-52.25c0.54-2.515 0.852-5.406 0.852-8.369 0-6.535-1.509-12.719-4.2-18.219-5.953-11.315-15.433-20.387-26.978-25.774q-3.119-3.718-37.716-22.433-47.957-26.123-60.69-48.54t-7.643-51.239q7.686-43.465 47.155-68.916t92.748-25.436q52.114 0 74.254 12.616zM485.608 622.995l-64.35-348.854h50.086l45.9 272.748c1.11 6.694 1.743 14.408 1.743 22.27 0 3.177-0.105 6.33-0.309 9.456l1.145-0.425c6.745-22.026 17.444-41.077 31.384-57.255l126.109-246.778h48.278l-189.974 348.84h-50.086zM813.226 312.195l-48.131 272.748h33.546l-6.723 38.068h-112.307l6.723-38.068h33.546l48.131-272.748h-33.533l6.723-38.068h112.307l-6.723 38.068h-33.546zM1110.475 379.288q-9.072 51.355-51.253 83.21t-96.701 30.075h-45.331l-23.030 130.393h-45.141l61.594-348.824h99.283q56.635 0 83.137 27.246t17.4 77.93z" p-id="10773" fill="#f4ea2a"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1767750395524" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8777" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M0 511.488c0 282.112 228.864 510.976 510.976 510.976s510.976-228.864 510.976-510.976C1021.952 229.376 793.088 0.512 510.976 0.512 228.864 0.512 0 229.376 0 511.488z" fill="#F7BA4D" p-id="8778"></path><path d="M966.144 511.488c0.512-205.312-136.704-385.536-334.848-439.296s-408.064 32.256-510.976 209.92L882.176 773.12c54.784-76.288 83.968-167.936 83.968-261.632z" fill="#FFEB64" p-id="8779"></path><path d="M56.32 511.488c-0.512 189.44 116.736 358.912 293.376 425.984 177.152 67.072 376.832 17.408 501.76-124.928 10.752-12.8 20.992-26.112 30.72-39.424L120.32 282.624c-16.384 26.624-29.696 54.784-40.448 84.48-15.36 46.592-23.04 95.232-23.552 144.384z" fill="#FACB4E" p-id="8780"></path><path d="M944.64 396.288c-13.312 0-25.088-8.704-30.208-20.992-37.888-107.008-115.712-195.584-217.088-246.784-15.872-7.68-22.528-27.136-14.336-43.008 8.192-15.872 27.136-22.528 43.008-14.336 115.712 58.368 204.8 158.72 248.32 281.088 3.072 8.192 2.56 16.896-1.024 24.576s-10.24 13.824-18.432 16.384c-3.072 1.536-6.656 2.56-10.24 3.072z" fill="#FFFFFF" p-id="8781"></path><path d="M245.76 444.416l133.632 100.864 135.168-117.248 135.168 117.248L783.36 444.416l-76.8 235.52c0 37.376-30.208 67.072-67.072 67.072H379.904c-37.376 0-67.072-30.208-67.072-67.072L245.76 444.416z m0 0M184.32 359.936c0 19.968 10.752 38.912 28.16 48.64 17.408 10.24 38.912 10.24 56.32 0 17.408-10.24 28.16-28.672 28.16-48.64 0-19.968-10.752-38.912-28.16-48.64-17.408-10.24-38.912-10.24-56.32 0-17.408 10.24-28.16 28.672-28.16 48.64z m0 0M458.752 276.48c0 19.968 10.752 38.912 28.16 48.64 17.408 10.24 38.912 10.24 56.32 0 17.408-10.24 28.16-28.672 28.16-48.64 0-19.968-10.752-38.912-28.16-48.64-17.408-10.24-38.912-10.24-56.32 0-17.408 9.728-28.16 28.672-28.16 48.64z m0 0M733.696 359.936c0 19.968 10.752 38.912 28.16 48.64 17.408 10.24 38.912 10.24 56.32 0 17.408-10.24 28.16-28.672 28.16-48.64 0-19.968-10.752-38.912-28.16-48.64-17.408-10.24-38.912-10.24-56.32 0-17.408 10.24-28.16 28.672-28.16 48.64z m0 0" fill="#EA9939" p-id="8782"></path><path d="M254.976 428.032l129.536 97.792 131.072-113.664 131.072 113.664 129.536-97.792-75.264 227.84c0 35.84-29.184 65.024-65.024 65.024H385.536c-35.84 0-65.024-29.184-65.024-65.024L254.976 428.032z m0 0M195.072 346.112c0 19.456 10.24 37.376 27.136 47.104 16.896 9.728 37.376 9.728 54.272 0s27.136-27.648 27.136-47.104c0-19.456-10.24-37.376-27.136-47.104-16.896-9.728-37.376-9.728-54.272 0-16.384 9.728-27.136 27.648-27.136 47.104z m0 0M460.8 263.68c0 19.456 10.24 37.376 27.136 47.104 16.896 9.728 37.376 9.728 54.272 0s27.136-27.648 27.136-47.104c0-19.456-10.24-37.376-27.136-47.104-16.896-9.728-37.376-9.728-54.272 0S460.8 244.224 460.8 263.68z m0 0M726.528 346.112c0 19.456 10.24 37.376 27.136 47.104 16.896 9.728 37.376 9.728 54.272 0s27.136-27.648 27.136-47.104c0-19.456-10.24-37.376-27.136-47.104-16.896-9.728-37.376-9.728-54.272 0s-27.136 27.648-27.136 47.104z m0 0" fill="#FFFFFF" p-id="8783"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1767750395524" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8777" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M0 511.488c0 282.112 228.864 510.976 510.976 510.976s510.976-228.864 510.976-510.976C1021.952 229.376 793.088 0.512 510.976 0.512 228.864 0.512 0 229.376 0 511.488z" fill="#F7BA4D" p-id="8778"></path><path d="M966.144 511.488c0.512-205.312-136.704-385.536-334.848-439.296s-408.064 32.256-510.976 209.92L882.176 773.12c54.784-76.288 83.968-167.936 83.968-261.632z" fill="#FFEB64" p-id="8779"></path><path d="M56.32 511.488c-0.512 189.44 116.736 358.912 293.376 425.984 177.152 67.072 376.832 17.408 501.76-124.928 10.752-12.8 20.992-26.112 30.72-39.424L120.32 282.624c-16.384 26.624-29.696 54.784-40.448 84.48-15.36 46.592-23.04 95.232-23.552 144.384z" fill="#FACB4E" p-id="8780"></path><path d="M944.64 396.288c-13.312 0-25.088-8.704-30.208-20.992-37.888-107.008-115.712-195.584-217.088-246.784-15.872-7.68-22.528-27.136-14.336-43.008 8.192-15.872 27.136-22.528 43.008-14.336 115.712 58.368 204.8 158.72 248.32 281.088 3.072 8.192 2.56 16.896-1.024 24.576s-10.24 13.824-18.432 16.384c-3.072 1.536-6.656 2.56-10.24 3.072z" fill="#FFFFFF" p-id="8781"></path><path d="M245.76 444.416l133.632 100.864 135.168-117.248 135.168 117.248L783.36 444.416l-76.8 235.52c0 37.376-30.208 67.072-67.072 67.072H379.904c-37.376 0-67.072-30.208-67.072-67.072L245.76 444.416z m0 0M184.32 359.936c0 19.968 10.752 38.912 28.16 48.64 17.408 10.24 38.912 10.24 56.32 0 17.408-10.24 28.16-28.672 28.16-48.64 0-19.968-10.752-38.912-28.16-48.64-17.408-10.24-38.912-10.24-56.32 0-17.408 10.24-28.16 28.672-28.16 48.64z m0 0M458.752 276.48c0 19.968 10.752 38.912 28.16 48.64 17.408 10.24 38.912 10.24 56.32 0 17.408-10.24 28.16-28.672 28.16-48.64 0-19.968-10.752-38.912-28.16-48.64-17.408-10.24-38.912-10.24-56.32 0-17.408 9.728-28.16 28.672-28.16 48.64z m0 0M733.696 359.936c0 19.968 10.752 38.912 28.16 48.64 17.408 10.24 38.912 10.24 56.32 0 17.408-10.24 28.16-28.672 28.16-48.64 0-19.968-10.752-38.912-28.16-48.64-17.408-10.24-38.912-10.24-56.32 0-17.408 10.24-28.16 28.672-28.16 48.64z m0 0" fill="#EA9939" p-id="8782"></path><path d="M254.976 428.032l129.536 97.792 131.072-113.664 131.072 113.664 129.536-97.792-75.264 227.84c0 35.84-29.184 65.024-65.024 65.024H385.536c-35.84 0-65.024-29.184-65.024-65.024L254.976 428.032z m0 0M195.072 346.112c0 19.456 10.24 37.376 27.136 47.104 16.896 9.728 37.376 9.728 54.272 0s27.136-27.648 27.136-47.104c0-19.456-10.24-37.376-27.136-47.104-16.896-9.728-37.376-9.728-54.272 0-16.384 9.728-27.136 27.648-27.136 47.104z m0 0M460.8 263.68c0 19.456 10.24 37.376 27.136 47.104 16.896 9.728 37.376 9.728 54.272 0s27.136-27.648 27.136-47.104c0-19.456-10.24-37.376-27.136-47.104-16.896-9.728-37.376-9.728-54.272 0S460.8 244.224 460.8 263.68z m0 0M726.528 346.112c0 19.456 10.24 37.376 27.136 47.104 16.896 9.728 37.376 9.728 54.272 0s27.136-27.648 27.136-47.104c0-19.456-10.24-37.376-27.136-47.104-16.896-9.728-37.376-9.728-54.272 0s-27.136 27.648-27.136 47.104z m0 0" fill="#FFFFFF" p-id="8783"></path></svg>
\ No newline at end of file
# 工单列表字段扩展需求 # 工单列表字段扩展需求
...@@ -38,4 +38,5 @@ ...@@ -38,4 +38,5 @@
通过新增字段和SLA计时功能,实现工单信息的全面展示和及时处理,确保紧急问题得到优先处理和有效跟踪。 通过新增字段和SLA计时功能,实现工单信息的全面展示和及时处理,确保紧急问题得到优先处理和有效跟踪。
![列表图](./img.png) ![列表图](./img.png)
![新增图](./img_1.png) ![新增图](./img_1.png)
\ No newline at end of file ![新增图](./工单平台处理回复调整优先级.png)
\ No newline at end of file
---
### 工单与报价单处理流程(维修类)
1. **用户提交工单**
- 工单类型:`维修`
- 用户需填写:故障描述、设备信息、联系方式等必要内容。
2. **奥值接收并审核工单**
- 系统自动分配或人工认领该维修工单。
- 技术人员根据用户提供的维修内容进行初步评估。
3. **生成报价单**
- 奥值根据维修内容(如所需配件、人工工时、服务难度等)生成正式**报价单**
- 报价单包含:
- 维修项目明细
- 配件及材料费用
- 人工服务费用
- 总计金额
- 报价有效期(**1 个月**
4. **报价单发送与确认**
- 报价单通过系统消息或邮件发送至客户账号。
- **仅客户账号可查看和操作相关凭证**(如上传服务单、确认接受报价等)。
5. **后续流程**
- 客户确认报价后,工单进入执行阶段。
- 若客户未在报价有效期内确认,需重新评估并生成新报价单。
---
> 💡 **提示**:为保障流程合规,请确保所有维修工单均通过系统留痕,报价单以平台正式版本为准。
```mermaid
flowchart TD
subgraph 客户操作
A1[提交维修工单] --> B1{收到报价单}
B1 -- 是 --> C1[确认报价 或 拒绝报价]
C1 --> D1[等待维修完成]
B1 -- 否 --> E1[无进一步行动]
end
subgraph 平台操作
A2[接收维修工单] --> B2{评估维修需求}
B2 --> C2[生成报价单 - 维修项目明细 - 配件/人工费用 - 总金额 - 有效期:1个月]
C2 --> D2[发送报价单至客户账号/邮件/电话]
D2 --> E2{客户是否在1个月内确认?}
E2 -- 是 --> F2[安排并执行维修]
E2 -- 否 --> G2[报价失效, 需重新评估并生成新报价]
F2 --> H2[完成维修服务]
G2 --> B2
end
A1 --> A2
D2 --> B1
C1 --> H2
```
![列表图](./img_2.png)
\ No newline at end of file
---
### 服务报价说明
1. **服务单列表上传凭证权限**
仅客户账号可上传服务单列表相关凭证。
2. **报价单有效期**
所有报价单自发出之日起有效期为 **1 个月**,逾期需重新确认或更新报价。
---
\ No newline at end of file
...@@ -11,22 +11,53 @@ ...@@ -11,22 +11,53 @@
<path d="M4 4h12a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2z"/> <path d="M4 4h12a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2z"/>
<path d="M7 9h6M7 12h4"/> <path d="M7 9h6M7 12h4"/>
</svg> </svg>
<span>服务管理</span> <span>客户</span>
</div> </div>
<svg class="nav-arrow nav-icon" viewBox="0 0 20 20"> <svg class="nav-arrow nav-icon" viewBox="0 0 20 20">
<path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/> <path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/>
</svg> </svg>
</div> </div>
<div class="nav-submenu"> <div class="nav-submenu">
<a href="人工费用标准管理列表页.html" class="nav-subitem "> <a href="客户信息.html" class="nav-subitem ">
人工管理 客户信息
</a> </a>
<a href="/1,2,3/2服务价格标准化/4-零件费用标准管理列表页.html" class="nav-subitem ">
零件管理 </div>
<div class="nav-item has-submenu expanded" onclick="toggleSubmenu(this)">
<div style="display: flex; align-items: center; gap: 12px;">
<svg class="nav-icon" viewBox="0 0 20 20">
<path d="M4 4h12a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2z"/>
<path d="M7 9h6M7 12h4"/>
</svg>
<span>设备管理</span>
</div>
<svg class="nav-arrow nav-icon" viewBox="0 0 20 20">
<path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/>
</svg>
</div>
<a href="零件管理.html" class="nav-subitem ">
配件管理
</a>
<div class="nav-item has-submenu expanded" onclick="toggleSubmenu(this)">
<div style="display: flex; align-items: center; gap: 12px;">
<svg class="nav-icon" viewBox="0 0 20 20">
<path d="M4 4h12a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2z"/>
<path d="M7 9h6M7 12h4"/>
</svg>
<span>服务订单</span>
</div>
<svg class="nav-arrow nav-icon" viewBox="0 0 20 20">
<path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/>
</svg>
</div>
<div class="nav-submenu">
<a href="人工费用标准管理列表页.html" class="nav-subitem ">
人工报价
</a> </a>
<a href="标准报价单生成.html" class="nav-subitem "> <!--<a href="标准报价单生成.html" class="nav-subitem ">
报价管理 报价管理
</a> </a>-->
<a href="服务单列表.html" class="nav-subitem "> <a href="服务单列表.html" class="nav-subitem ">
服务单列表 服务单列表
</a> </a>
......
...@@ -158,7 +158,7 @@ let crawlerSites = [ ...@@ -158,7 +158,7 @@ let crawlerSites = [
id: 2, id: 2,
siteName: '竞品分析网', siteName: '竞品分析网',
siteUrl: 'https://www.competitoranalysis.com', siteUrl: 'https://www.competitoranalysis.com',
requestDept: '产品部', requestDept: '产品部/市场部',
isCollected: '是', isCollected: '是',
collectionPlan: '每日爬取竞品价格和功能更新,生成对比报告', collectionPlan: '每日爬取竞品价格和功能更新,生成对比报告',
crawlFrequency: '每小时一次', crawlFrequency: '每小时一次',
...@@ -225,14 +225,14 @@ function renderCrawlerSitesTable() { ...@@ -225,14 +225,14 @@ function renderCrawlerSitesTable() {
<td><strong>${site.siteName}</strong></td> <td><strong>${site.siteName}</strong></td>
<td><a href="${site.siteUrl}" target="_blank">${site.siteUrl}</a></td> <td><a href="${site.siteUrl}" target="_blank">${site.siteUrl}</a></td>
<td>${site.requestDept}</td> <td>${site.requestDept}</td>
<td><span class="${statusClass}">${site.isCollected}</span></td> <!-- <td><span class="${statusClass}">${site.isCollected}</span></td>-->
<td>${site.collectionPlan}</td> <!-- <td>${site.collectionPlan}</td>-->
<td>${site.crawlFrequency}</td> <td>${site.crawlFrequency}</td>
<td>${site.lastCrawlTime || '-'}</td> <td>${site.lastCrawlTime || '-'}</td>
<td><span class="${crawlStatusClass}">${site.crawlStatus}</span></td> <td><span class="${crawlStatusClass}">${site.crawlStatus}</span></td>
<td>${site.targetDataType}</td> <!-- <td>${site.targetDataType}</td>-->
<td>${site.antiCrawlMechanism}</td> <!-- <td>${site.antiCrawlMechanism}</td>-->
<td>${site.负责人}</td> <!-- <td>${site.负责人}</td>-->
<td> <td>
<div class="action-buttons"> <div class="action-buttons">
<button class="action-btn edit-btn" data-id="${site.id}"> <button class="action-btn edit-btn" data-id="${site.id}">
......
<!DOCTYPE html> <!DOCTYPE html>
...@@ -1739,7 +1739,7 @@ ...@@ -1739,7 +1739,7 @@
<div class="breadcrumb"> <div class="breadcrumb">
<span>首页</span> <span>首页</span>
<span class="breadcrumb-separator">/</span> <span class="breadcrumb-separator">/</span>
<span class="breadcrumb-current">信息原页面</span> <span class="breadcrumb-current">信息源统计</span>
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">
...@@ -1778,14 +1778,14 @@ ...@@ -1778,14 +1778,14 @@
<th>网站名称</th> <th>网站名称</th>
<th>网站网址</th> <th>网站网址</th>
<th>需求部门</th> <th>需求部门</th>
<th>是否收录</th> <!-- <th>是否收录</th>-->
<th>收录方案/不收录原因</th> <!-- <th>收录方案/不收录原因</th>-->
<th>爬取频率</th> <th>爬取频率</th>
<th>上次爬取时间</th> <th>上次爬取时间</th>
<th>爬取状态</th> <th>爬取状态</th>
<th>目标数据类型</th> <!-- <th>目标数据类型</th>-->
<th>反爬机制</th> <!-- <th>反爬机制</th>-->
<th>负责人</th> <!-- <th>负责人</th>-->
<th>操作</th> <th>操作</th>
</tr> </tr>
</thead> </thead>
...@@ -1817,7 +1817,7 @@ ...@@ -1817,7 +1817,7 @@
<input type="url" id="site-url" required placeholder="请输入完整网址,如 https://www.example.com"> <input type="url" id="site-url" required placeholder="请输入完整网址,如 https://www.example.com">
</div> </div>
</div> </div>
<div class="form-row"> <!--<div class="form-row">
<div class="form-group"> <div class="form-group">
<label for="request-dept">需求部门 *</label> <label for="request-dept">需求部门 *</label>
<input type="text" id="request-dept" required placeholder="请输入需求部门"> <input type="text" id="request-dept" required placeholder="请输入需求部门">
...@@ -1830,7 +1830,7 @@ ...@@ -1830,7 +1830,7 @@
<option value="否">否</option> <option value="否">否</option>
</select> </select>
</div> </div>
</div> </div>-->
<div class="form-row"> <div class="form-row">
<div class="form-group"> <div class="form-group">
<label for="crawl-frequency">爬取频率 *</label> <label for="crawl-frequency">爬取频率 *</label>
...@@ -1850,12 +1850,12 @@ ...@@ -1850,12 +1850,12 @@
<option value="正常">正常</option> <option value="正常">正常</option>
<option value="暂停">暂停</option> <option value="暂停">暂停</option>
<option value="失败">失败</option> <option value="失败">失败</option>
<option value="待审核">待审核</option> <!-- <option value="待审核">待审核</option>-->
<option value="已停用">已停用</option> <option value="已停用">已停用</option>
</select> </select>
</div> </div>
</div> </div>
<div class="form-row"> <!-- <div class="form-row">
<div class="form-group"> <div class="form-group">
<label for="target-data-type">目标数据类型 *</label> <label for="target-data-type">目标数据类型 *</label>
<input type="text" id="target-data-type" required placeholder="如:新闻标题、价格、评论等"> <input type="text" id="target-data-type" required placeholder="如:新闻标题、价格、评论等">
...@@ -1864,8 +1864,8 @@ ...@@ -1864,8 +1864,8 @@
<label for="anti-crawl-mechanism">反爬机制</label> <label for="anti-crawl-mechanism">反爬机制</label>
<input type="text" id="anti-crawl-mechanism" placeholder="如:验证码、IP限制、动态加载等"> <input type="text" id="anti-crawl-mechanism" placeholder="如:验证码、IP限制、动态加载等">
</div> </div>
</div> </div>-->
<div class="form-row"> <!-- <div class="form-row">
<div class="form-group"> <div class="form-group">
<label for="负责人">负责人 *</label> <label for="负责人">负责人 *</label>
<input type="text" id="负责人" required placeholder="请输入负责人姓名"> <input type="text" id="负责人" required placeholder="请输入负责人姓名">
...@@ -1874,11 +1874,11 @@ ...@@ -1874,11 +1874,11 @@
<label for="last-crawl-time">上次爬取时间</label> <label for="last-crawl-time">上次爬取时间</label>
<input type="datetime-local" id="last-crawl-time" placeholder="选择时间"> <input type="datetime-local" id="last-crawl-time" placeholder="选择时间">
</div> </div>
</div> </div>-->
<div class="form-group"> <!-- <div class="form-group">
<label for="collection-plan">收录方案/不收录原因 *</label> <label for="collection-plan">收录方案/不收录原因 *</label>
<textarea id="collection-plan" required rows="4" placeholder="请输入收录方案或不收录的具体原因"></textarea> <textarea id="collection-plan" required rows="4" placeholder="请输入收录方案或不收录的具体原因"></textarea>
</div> </div>-->
<div class="form-group"> <div class="form-group">
<label for="备注">备注</label> <label for="备注">备注</label>
<textarea id="备注" rows="3" placeholder="如:需登录后抓取、仅限工作日抓取等"></textarea> <textarea id="备注" rows="3" placeholder="如:需登录后抓取、仅限工作日抓取等"></textarea>
......
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>设备档案</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #1B64F3;
--primary-hover: #1554D3;
--primary-light: #e6f7ff;
--bg-color: #F5F6FA;
--card-bg: #FFFFFF;
--sidebar-bg: #0F172A;
--text-primary: #1A1F36;
--text-secondary: #64748B;
--text-tertiary: #94A3B8;
--text-light: #CBD5E1;
--border-color: #E2E8F0;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--success-color: #22C55E;
--warning-color: #EAB308;
--error-color: #EF4444;
--sidebar-width: 260px;
--header-height: 64px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
background-color: var(--bg-color);
color: var(--text-primary);
line-height: 1.6;
overflow-x: hidden;
}
.app-container {
display: flex;
min-height: 100vh;
}
/* 左侧导航栏 */
.sidebar {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
background: var(--sidebar-bg);
border-right: 1px solid rgba(255, 255, 255, 0.1);
overflow-y: auto;
z-index: 1000;
}
.sidebar-logo {
padding: 20px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
gap: 12px;
}
.logo-icon {
width: 36px;
height: 36px;
background: var(--primary-color);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 700;
font-size: 18px;
}
.logo-text {
color: white;
font-size: 16px;
font-weight: 600;
}
.sidebar-menu {
padding: 16px 0;
}
.nav-group-title {
padding: 12px 20px 8px;
font-size: 11px;
font-weight: 600;
color: var(--text-tertiary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.menu-item, .nav-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 20px;
color: var(--text-light);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
position: relative;
cursor: pointer;
border: none;
background: none;
width: 100%;
text-align: left;
}
.menu-item:hover, .nav-item:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.menu-item.active, .nav-item.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-item.active::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: var(--primary-color);
}
.nav-item.has-submenu {
justify-content: space-between;
}
.nav-arrow {
width: 14px;
height: 14px;
transition: transform 0.2s;
margin-left: auto;
}
.nav-item.expanded .nav-arrow {
transform: rotate(90deg);
}
.nav-submenu {
display: none;
background: rgba(0, 0, 0, 0.1);
}
.nav-item.expanded + .nav-submenu {
display: block;
}
.nav-subitem {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 20px 10px 48px;
color: var(--text-light);
text-decoration: none;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
position: relative;
}
.nav-subitem:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.nav-subitem.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-icon {
width: 18px;
height: 18px;
stroke: currentColor;
stroke-width: 2;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
/* 顶部工具栏 */
.header, .top-header {
position: fixed;
top: 0;
left: var(--sidebar-width);
right: 0;
height: var(--header-height);
background: var(--card-bg);
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32px;
z-index: 999;
box-shadow: var(--shadow-sm);
}
.header-left {
display: flex;
align-items: center;
gap: 24px;
}
.breadcrumb {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--text-secondary);
}
.breadcrumb-separator {
color: var(--text-tertiary);
}
.breadcrumb-current {
color: var(--text-primary);
font-weight: 500;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.header-icon-btn {
position: relative;
width: 36px;
height: 36px;
border-radius: 8px;
border: none;
background: transparent;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
transition: all 0.2s;
}
.header-icon-btn:hover {
background: var(--bg-color);
color: var(--primary-color);
}
.notification-badge {
position: absolute;
top: 6px;
right: 6px;
width: 8px;
height: 8px;
background: var(--error-color);
border-radius: 50%;
border: 2px solid var(--card-bg);
}
.lang-switcher {
display: flex;
gap: 6px;
align-items: center;
}
.lang-btn {
padding: 6px 12px;
background: transparent;
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-secondary);
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.lang-btn:hover {
border-color: var(--primary-color);
color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.lang-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.user-avatar {
width: 36px;
height: 36px;
border-radius: 8px;
background: var(--primary-color);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 14px;
cursor: pointer;
}
.page-title {
font-size: 20px;
font-weight: 600;
color: var(--text-primary);
}
.user-info {
display: flex;
align-items: center;
gap: 16px;
}
.notification {
position: relative;
cursor: pointer;
color: var(--text-secondary);
}
/* 主内容区域 - 已调整左右内边距 */
.main-content {
flex: 1;
padding: 24px;
overflow-y: auto;
min-height: 100vh;
margin-left: 260px;
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
/* 调整左右内边距,从 8px 增加到 32px,以利用更多空间 */
/* padding: 4px 32px;
min-height: calc(100vh - var(--header-height));
.main-content { } */
}
.content-area {
padding: 0;
}
/* 页面标题区域 */
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.page-title-section {
display: flex;
flex-direction: column;
gap: 4px;
}
.page-title-main {
font-size: 24px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.3px;
}
.page-title-sub {
font-size: 14px;
color: var(--text-secondary);
}
/* 表格数据优化 */
.table-cell-number {
font-weight: 600;
color: var(--text-primary);
}
.table-cell-date {
color: var(--text-secondary);
font-size: 13px;
}
/* 表格内容样式增强 */
td strong {
color: var(--text-primary);
font-weight: 600;
}
td code {
font-size: 12px;
font-weight: 500;
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-state-icon {
font-size: 48px;
color: var(--text-tertiary);
margin-bottom: 16px;
}
.empty-state-text {
font-size: 14px;
color: var(--text-secondary);
}
/* 响应式表格优化 */
@media (max-width: 1200px) {
.table-container {
overflow-x: auto;
}
table {
min-width: 1000px;
}
}
@media (max-width: 768px) {
.card-body {
padding: 16px;
}
th, td {
padding: 12px 16px;
}
.action-buttons {
flex-direction: column;
gap: 6px;
}
.action-btn {
width: 100%;
justify-content: center;
}
}
/* 卡片样式 */
.card {
background: var(--card-bg);
border-radius: 12px;
box-shadow: var(--shadow-sm);
margin-bottom: 24px;
border: 1px solid var(--border-color);
}
.card-header {
padding: 18px 20px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--bg-color);
}
.card-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.2px;
}
.card-body {
padding: 20px 16px;
}
/* 按钮样式 */
.btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(27, 100, 243, 0.3);
}
.btn-secondary {
background: #f0f0f0;
color: var(--text-light);
}
.btn-secondary:hover {
background: #e0e0e0;
}
.btn-success {
background: var(--success-color);
color: white;
}
.btn-success:hover {
background: #389e0d;
}
.btn-danger {
background: var(--error-color);
color: white;
}
.btn-danger:hover {
background: #cf1322;
}
/* 标签页样式 */
.tabs {
display: flex;
gap: 16px;
margin-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
.tab {
padding: 10px 0;
color: var(--text-light);
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
font-size: 14px;
}
.tab:hover {
color: var(--primary-color);
}
.tab.active {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
}
/* 表格样式 */
.table-container {
overflow-x: auto;
border-radius: 8px;
width: 100%;
}
table {
width: 100%;
border-collapse: collapse;
background: var(--card-bg);
}
th, td {
padding: 16px 20px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.5px;
white-space: nowrap;
}
tbody tr {
transition: all 0.2s;
}
tbody tr:hover {
background: rgba(27, 100, 243, 0.04);
}
tbody tr:last-child td {
border-bottom: none;
}
td {
color: var(--text-primary);
font-size: 14px;
vertical-align: middle;
}
.status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status.active {
background: #f6ffed;
color: var(--success-color);
}
.status.inactive {
background: #fff2e8;
color: var(--warning-color);
}
.action-buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.action-btn {
padding: 6px 14px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
.action-btn i {
font-size: 12px;
}
.action-btn.edit-btn {
background: rgba(27, 100, 243, 0.1);
color: var(--primary-color);
}
.action-btn.edit-btn:hover {
background: rgba(27, 100, 243, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.delete-btn {
background: rgba(239, 68, 68, 0.1);
color: var(--error-color);
}
.action-btn.delete-btn:hover {
background: rgba(239, 68, 68, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(239, 68, 68, 0.2);
}
.action-btn.view-btn {
background: rgba(27, 100, 243, 0.08);
color: var(--primary-color);
}
.action-btn.view-btn:hover {
background: rgba(27, 100, 243, 0.15);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.copy-btn {
background: rgba(34, 197, 94, 0.1);
color: var(--success-color);
}
.action-btn.copy-btn:hover {
background: rgba(34, 197, 94, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(34, 197, 94, 0.2);
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
}
.modal.show {
display: flex;
}
.modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.add-modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 800px;
max-height: 85vh;
overflow-y: auto;
}
.modal-header {
padding: 16px 24px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-title {
font-size: 16px;
font-weight: 600;
color: var(--text-color);
}
.close-modal {
background: none;
border: none;
font-size: 20px;
color: var(--text-light);
cursor: pointer;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 0.3s;
}
.close-modal:hover {
background: var(--secondary-color);
color: var(--text-color);
}
.modal-body {
padding: 24px;
}
.modal-footer {
padding: 16px 24px;
border-top: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
/* 新增表单模态框样式 */
.add-modal-form .form-group {
margin-bottom: 20px;
}
.add-modal-form .form-row {
display: flex;
gap: 15px;
margin-bottom: 15px;
}
.add-modal-form .form-row .form-group {
flex: 1;
margin-bottom: 0;
}
.add-modal-form label {
display: block;
margin-bottom: 6px;
font-weight: 500;
color: var(--text-secondary);
font-size: 14px;
}
.add-modal-form input,
.add-modal-form select,
.add-modal-form textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
}
.add-modal-form input:focus,
.add-modal-form select:focus,
.add-modal-form textarea:focus {
outline: none;
border-color: var(--primary-color);
}
.add-modal-form .section-title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin: 20px 0 15px 0;
padding-bottom: 8px;
border-bottom: 1px solid var(--border-color);
}
.upload-box {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
background-color: var(--bg-color);
}
.upload-box:hover {
border-color: var(--primary-color);
background-color: rgba(27, 100, 243, 0.05);
}
.upload-icon {
font-size: 24px;
color: var(--primary-color);
margin-bottom: 10px;
}
.upload-info {
color: var(--text-secondary);
font-size: 13px;
}
.file-name {
margin-top: 10px;
font-weight: 500;
color: var(--primary-color);
font-size: 13px;
}
.param-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.param-table th, .param-table td {
border: 1px solid var(--border-color);
padding: 8px;
text-align: left;
}
.param-table th {
background-color: var(--bg-color);
font-weight: 600;
}
.add-param-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 8px 15px;
border-radius: 6px;
cursor: pointer;
margin-top: 10px;
font-size: 14px;
}
.add-param-btn:hover {
background: var(--primary-hover);
}
/* 二维码预览样式 */
.qrcode-preview-large {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background: var(--primary-light);
border-radius: 8px;
margin-bottom: 20px;
}
.qrcode-image {
width: 200px;
height: 200px;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 15px;
}
.qrcode-image img {
max-width: 100%;
max-height: 100%;
}
/* 详情信息样式 */
.detail-info {
margin-top: 20px;
}
.detail-item {
display: flex;
margin-bottom: 12px;
font-size: 14px;
}
.detail-label {
width: 100px;
color: var(--text-light);
flex-shrink: 0;
}
.detail-value {
color: var(--text-color);
font-weight: 500;
}
/* 响应式设计 */
@media (max-width: 768px) {
.sidebar {
transform: translateX(-100%);
}
.sidebar.show-mobile {
transform: translateX(0);
}
.main-content {
margin-left: 0;
margin-top: 0;
padding: 16px; /* 在移动端保持较小的内边距 */
}
.header, .top-header {
left: 0;
}
.tabs {
flex-wrap: wrap;
}
}
/* 批量上传相关样式 */
.batch-upload-modal .modal-content {
max-width: 800px;
}
.template-selector {
margin-bottom: 20px;
}
.template-selector label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--text-primary);
}
.template-selector select {
width: 100%;
padding: 10px 15px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
background: white;
}
.template-download-btn {
margin-top: 10px;
padding: 8px 16px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.template-download-btn:hover {
background: var(--primary-hover);
}
.upload-area {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 40px 20px;
text-align: center;
margin-bottom: 20px;
cursor: pointer;
transition: all 0.3s;
background: var(--bg-color);
}
.upload-area:hover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.upload-area.dragover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.1);
}
.upload-icon-large {
font-size: 48px;
color: var(--primary-color);
margin-bottom: 12px;
}
.upload-text {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 8px;
}
.upload-hint {
font-size: 12px;
color: var(--text-tertiary);
}
.progress-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid var(--border-color);
}
.progress-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
font-size: 14px;
}
.progress-stats {
display: flex;
gap: 20px;
}
.stat-item {
display: flex;
align-items: center;
gap: 6px;
}
.stat-label {
color: var(--text-secondary);
}
.stat-value {
font-weight: 600;
color: var(--text-primary);
}
.stat-value.success {
color: var(--success-color);
}
.stat-value.error {
color: var(--error-color);
}
.progress-bar-container {
width: 100%;
height: 8px;
background: var(--bg-color);
border-radius: 4px;
overflow: hidden;
margin-bottom: 12px;
}
.progress-bar {
height: 100%;
background: var(--primary-color);
transition: width 0.3s ease;
border-radius: 4px;
}
.error-list {
margin-top: 16px;
max-height: 200px;
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 12px;
background: #fff5f5;
}
.error-item {
padding: 8px;
margin-bottom: 6px;
background: white;
border-left: 3px solid var(--error-color);
border-radius: 4px;
font-size: 13px;
}
.error-item:last-child {
margin-bottom: 0;
}
.error-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.error-reason {
color: var(--error-color);
font-weight: 500;
}
.download-error-btn {
margin-top: 12px;
padding: 8px 16px;
background: var(--error-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.download-error-btn:hover {
background: #cf1322;
}
.validation-table {
width: 100%;
border-collapse: collapse;
margin-top: 16px;
font-size: 13px;
table-layout: fixed;
}
.validation-table th,
.validation-table td {
padding: 10px;
text-align: left;
border-bottom: 1px solid var(--border-color);
white-space: normal;
word-break: normal;
overflow: visible;
vertical-align: middle;
}
.validation-table th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
white-space: nowrap;
}
.validation-table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.validation-table td:nth-child(5) {
white-space: normal;
word-break: break-word;
}
.validation-table th:nth-child(1),
.validation-table td:nth-child(1) {
width: 60px;
min-width: 60px;
text-align: center;
}
.validation-table th:nth-child(2),
.validation-table td:nth-child(2) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(3),
.validation-table td:nth-child(3) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(4),
.validation-table td:nth-child(4) {
width: 100px;
min-width: 100px;
text-align: center;
}
.validation-table th:nth-child(5),
.validation-table td:nth-child(5) {
width: auto;
min-width: 200px;
}
.validation-table tr.error-row {
background: #fff5f5;
}
.validation-table tr.error-row td {
color: var(--error-color);
}
#validation-table-container {
overflow-x: auto;
max-width: 100%;
width: 100%;
}
#validation-table-container table {
min-width: 600px;
}
.file-name-display {
margin-top: 12px;
padding: 10px;
background: var(--bg-color);
border-radius: 6px;
font-size: 13px;
color: var(--text-secondary);
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background-color: #01337a;
color: #fff;
padding: 10px;
text-align: left;
border: 1px solid #ddd;
}
td {
padding: 10px;
border: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* 在主页面CSS中添加 */
.sidebar-iframe {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
border: none;
z-index: 999;
}
/* 为main-content和header添加左边距以避开iframe */
.main-content {
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
}
.top-header {
left: var(--sidebar-width);
}
</style>
</head>
<body>
<div class="app-container">
<div id="sidebar-container"></div>
<header class="top-header">
<div class="header-left">
<div class="breadcrumb">
<span>首页</span>
<span class="breadcrumb-separator">/</span>
<span class="breadcrumb-current">客户信息</span>
</div>
</div>
<div class="header-right">
<button class="header-icon-btn" title="通知">
<svg class="nav-icon" viewBox="0 0 20 20">
<path d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z"/>
</svg>
<span class="notification-badge"></span>
</button>
<div class="lang-switcher">
<button class="lang-btn active">中文</button>
<button class="lang-btn">EN</button>
</div>
<div class="user-avatar"></div>
</div>
</header>
<div class="main-content" style="position: relative;">
<img src="./image/img.png" alt="" style="width: 100%;display:block;">
</div>
</div>
</body>
<script src="./js.js"></script>
</html>
\ No newline at end of file
<!DOCTYPE html> <!DOCTYPE html>
...@@ -1685,6 +1685,7 @@ ...@@ -1685,6 +1685,7 @@
<div class=""> <div class="">
<div class="card-title"> <div class="card-title">
<span>报价单列表 (共 {{ filteredQuotes.length }} 条)</span> <span>报价单列表 (共 {{ filteredQuotes.length }} 条)</span>
<button class="btn btn-primary btn-sm" style=""><a href="标准报价单生成.html" style="color:#fff;">报价单生成</a></button>
</div> </div>
<!-- 筛选栏 --> <!-- 筛选栏 -->
......
<!DOCTYPE html> <!DOCTYPE html>
...@@ -1640,6 +1640,10 @@ ...@@ -1640,6 +1640,10 @@
<label class="form-label">工厂地区</label> <label class="form-label">工厂地区</label>
<select v-model="form.factoryRegion" class="form-control" required> <select v-model="form.factoryRegion" class="form-control" required>
<option value="">请选择</option> <option value="">请选择</option>
<option value="上海">上海</option>
<option value="北京">北京</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
</select> </select>
</div> </div>
</div> </div>
......
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>设备档案</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
:root {
--primary-color: #1B64F3;
--primary-hover: #1554D3;
--primary-light: #e6f7ff;
--bg-color: #F5F6FA;
--card-bg: #FFFFFF;
--sidebar-bg: #0F172A;
--text-primary: #1A1F36;
--text-secondary: #64748B;
--text-tertiary: #94A3B8;
--text-light: #CBD5E1;
--border-color: #E2E8F0;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--success-color: #22C55E;
--warning-color: #EAB308;
--error-color: #EF4444;
--sidebar-width: 260px;
--header-height: 64px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
background-color: var(--bg-color);
color: var(--text-primary);
line-height: 1.6;
overflow-x: hidden;
}
.app-container {
display: flex;
min-height: 100vh;
}
/* 左侧导航栏 */
.sidebar {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
background: var(--sidebar-bg);
border-right: 1px solid rgba(255, 255, 255, 0.1);
overflow-y: auto;
z-index: 1000;
}
.sidebar-logo {
padding: 20px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
gap: 12px;
}
.logo-icon {
width: 36px;
height: 36px;
background: var(--primary-color);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 700;
font-size: 18px;
}
.logo-text {
color: white;
font-size: 16px;
font-weight: 600;
}
.sidebar-menu {
padding: 16px 0;
}
.nav-group-title {
padding: 12px 20px 8px;
font-size: 11px;
font-weight: 600;
color: var(--text-tertiary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.menu-item, .nav-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 20px;
color: var(--text-light);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
position: relative;
cursor: pointer;
border: none;
background: none;
width: 100%;
text-align: left;
}
.menu-item:hover, .nav-item:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.menu-item.active, .nav-item.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-item.active::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: var(--primary-color);
}
.nav-item.has-submenu {
justify-content: space-between;
}
.nav-arrow {
width: 14px;
height: 14px;
transition: transform 0.2s;
margin-left: auto;
}
.nav-item.expanded .nav-arrow {
transform: rotate(90deg);
}
.nav-submenu {
display: none;
background: rgba(0, 0, 0, 0.1);
}
.nav-item.expanded + .nav-submenu {
display: block;
}
.nav-subitem {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 20px 10px 48px;
color: var(--text-light);
text-decoration: none;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
position: relative;
}
.nav-subitem:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.nav-subitem.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-icon {
width: 18px;
height: 18px;
stroke: currentColor;
stroke-width: 2;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
/* 顶部工具栏 */
.header, .top-header {
position: fixed;
top: 0;
left: var(--sidebar-width);
right: 0;
height: var(--header-height);
background: var(--card-bg);
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32px;
z-index: 999;
box-shadow: var(--shadow-sm);
}
.header-left {
display: flex;
align-items: center;
gap: 24px;
}
.breadcrumb {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--text-secondary);
}
.breadcrumb-separator {
color: var(--text-tertiary);
}
.breadcrumb-current {
color: var(--text-primary);
font-weight: 500;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.header-icon-btn {
position: relative;
width: 36px;
height: 36px;
border-radius: 8px;
border: none;
background: transparent;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
transition: all 0.2s;
}
.header-icon-btn:hover {
background: var(--bg-color);
color: var(--primary-color);
}
.notification-badge {
position: absolute;
top: 6px;
right: 6px;
width: 8px;
height: 8px;
background: var(--error-color);
border-radius: 50%;
border: 2px solid var(--card-bg);
}
.lang-switcher {
display: flex;
gap: 6px;
align-items: center;
}
.lang-btn {
padding: 6px 12px;
background: transparent;
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-secondary);
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.lang-btn:hover {
border-color: var(--primary-color);
color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.lang-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.user-avatar {
width: 36px;
height: 36px;
border-radius: 8px;
background: var(--primary-color);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 14px;
cursor: pointer;
}
.page-title {
font-size: 20px;
font-weight: 600;
color: var(--text-primary);
}
.user-info {
display: flex;
align-items: center;
gap: 16px;
}
.notification {
position: relative;
cursor: pointer;
color: var(--text-secondary);
}
/* 主内容区域 - 已调整左右内边距 */
.main-content {
flex: 1;
padding: 24px;
overflow-y: auto;
min-height: 100vh;
margin-left: 260px;
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
/* 调整左右内边距,从 8px 增加到 32px,以利用更多空间 */
/* padding: 4px 32px;
min-height: calc(100vh - var(--header-height));
.main-content { } */
}
.content-area {
padding: 0;
}
/* 页面标题区域 */
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.page-title-section {
display: flex;
flex-direction: column;
gap: 4px;
}
.page-title-main {
font-size: 24px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.3px;
}
.page-title-sub {
font-size: 14px;
color: var(--text-secondary);
}
/* 表格数据优化 */
.table-cell-number {
font-weight: 600;
color: var(--text-primary);
}
.table-cell-date {
color: var(--text-secondary);
font-size: 13px;
}
/* 表格内容样式增强 */
td strong {
color: var(--text-primary);
font-weight: 600;
}
td code {
font-size: 12px;
font-weight: 500;
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-state-icon {
font-size: 48px;
color: var(--text-tertiary);
margin-bottom: 16px;
}
.empty-state-text {
font-size: 14px;
color: var(--text-secondary);
}
/* 响应式表格优化 */
@media (max-width: 1200px) {
.table-container {
overflow-x: auto;
}
table {
min-width: 1000px;
}
}
@media (max-width: 768px) {
.card-body {
padding: 16px;
}
th, td {
padding: 12px 16px;
}
.action-buttons {
flex-direction: column;
gap: 6px;
}
.action-btn {
width: 100%;
justify-content: center;
}
}
/* 卡片样式 */
.card {
background: var(--card-bg);
border-radius: 12px;
box-shadow: var(--shadow-sm);
margin-bottom: 24px;
border: 1px solid var(--border-color);
}
.card-header {
padding: 18px 20px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--bg-color);
}
.card-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.2px;
}
.card-body {
padding: 20px 16px;
}
/* 按钮样式 */
.btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(27, 100, 243, 0.3);
}
.btn-secondary {
background: #f0f0f0;
color: var(--text-light);
}
.btn-secondary:hover {
background: #e0e0e0;
}
.btn-success {
background: var(--success-color);
color: white;
}
.btn-success:hover {
background: #389e0d;
}
.btn-danger {
background: var(--error-color);
color: white;
}
.btn-danger:hover {
background: #cf1322;
}
/* 标签页样式 */
.tabs {
display: flex;
gap: 16px;
margin-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
.tab {
padding: 10px 0;
color: var(--text-light);
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
font-size: 14px;
}
.tab:hover {
color: var(--primary-color);
}
.tab.active {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
}
/* 表格样式 */
.table-container {
overflow-x: auto;
border-radius: 8px;
width: 100%;
}
table {
width: 100%;
border-collapse: collapse;
background: var(--card-bg);
}
th, td {
padding: 16px 20px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.5px;
white-space: nowrap;
}
tbody tr {
transition: all 0.2s;
}
tbody tr:hover {
background: rgba(27, 100, 243, 0.04);
}
tbody tr:last-child td {
border-bottom: none;
}
td {
color: var(--text-primary);
font-size: 14px;
vertical-align: middle;
}
.status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status.active {
background: #f6ffed;
color: var(--success-color);
}
.status.inactive {
background: #fff2e8;
color: var(--warning-color);
}
.action-buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.action-btn {
padding: 6px 14px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
.action-btn i {
font-size: 12px;
}
.action-btn.edit-btn {
background: rgba(27, 100, 243, 0.1);
color: var(--primary-color);
}
.action-btn.edit-btn:hover {
background: rgba(27, 100, 243, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.delete-btn {
background: rgba(239, 68, 68, 0.1);
color: var(--error-color);
}
.action-btn.delete-btn:hover {
background: rgba(239, 68, 68, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(239, 68, 68, 0.2);
}
.action-btn.view-btn {
background: rgba(27, 100, 243, 0.08);
color: var(--primary-color);
}
.action-btn.view-btn:hover {
background: rgba(27, 100, 243, 0.15);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.copy-btn {
background: rgba(34, 197, 94, 0.1);
color: var(--success-color);
}
.action-btn.copy-btn:hover {
background: rgba(34, 197, 94, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(34, 197, 94, 0.2);
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
}
.modal.show {
display: flex;
}
.modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.add-modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 800px;
max-height: 85vh;
overflow-y: auto;
}
.modal-header {
padding: 16px 24px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-title {
font-size: 16px;
font-weight: 600;
color: var(--text-color);
}
.close-modal {
background: none;
border: none;
font-size: 20px;
color: var(--text-light);
cursor: pointer;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 0.3s;
}
.close-modal:hover {
background: var(--secondary-color);
color: var(--text-color);
}
.modal-body {
padding: 24px;
}
.modal-footer {
padding: 16px 24px;
border-top: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
/* 新增表单模态框样式 */
.add-modal-form .form-group {
margin-bottom: 20px;
}
.add-modal-form .form-row {
display: flex;
gap: 15px;
margin-bottom: 15px;
}
.add-modal-form .form-row .form-group {
flex: 1;
margin-bottom: 0;
}
.add-modal-form label {
display: block;
margin-bottom: 6px;
font-weight: 500;
color: var(--text-secondary);
font-size: 14px;
}
.add-modal-form input,
.add-modal-form select,
.add-modal-form textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
}
.add-modal-form input:focus,
.add-modal-form select:focus,
.add-modal-form textarea:focus {
outline: none;
border-color: var(--primary-color);
}
.add-modal-form .section-title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin: 20px 0 15px 0;
padding-bottom: 8px;
border-bottom: 1px solid var(--border-color);
}
.upload-box {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
background-color: var(--bg-color);
}
.upload-box:hover {
border-color: var(--primary-color);
background-color: rgba(27, 100, 243, 0.05);
}
.upload-icon {
font-size: 24px;
color: var(--primary-color);
margin-bottom: 10px;
}
.upload-info {
color: var(--text-secondary);
font-size: 13px;
}
.file-name {
margin-top: 10px;
font-weight: 500;
color: var(--primary-color);
font-size: 13px;
}
.param-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.param-table th, .param-table td {
border: 1px solid var(--border-color);
padding: 8px;
text-align: left;
}
.param-table th {
background-color: var(--bg-color);
font-weight: 600;
}
.add-param-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 8px 15px;
border-radius: 6px;
cursor: pointer;
margin-top: 10px;
font-size: 14px;
}
.add-param-btn:hover {
background: var(--primary-hover);
}
/* 二维码预览样式 */
.qrcode-preview-large {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background: var(--primary-light);
border-radius: 8px;
margin-bottom: 20px;
}
.qrcode-image {
width: 200px;
height: 200px;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 15px;
}
.qrcode-image img {
max-width: 100%;
max-height: 100%;
}
/* 详情信息样式 */
.detail-info {
margin-top: 20px;
}
.detail-item {
display: flex;
margin-bottom: 12px;
font-size: 14px;
}
.detail-label {
width: 100px;
color: var(--text-light);
flex-shrink: 0;
}
.detail-value {
color: var(--text-color);
font-weight: 500;
}
/* 响应式设计 */
@media (max-width: 768px) {
.sidebar {
transform: translateX(-100%);
}
.sidebar.show-mobile {
transform: translateX(0);
}
.main-content {
margin-left: 0;
margin-top: 0;
padding: 16px; /* 在移动端保持较小的内边距 */
}
.header, .top-header {
left: 0;
}
.tabs {
flex-wrap: wrap;
}
}
/* 批量上传相关样式 */
.batch-upload-modal .modal-content {
max-width: 800px;
}
.template-selector {
margin-bottom: 20px;
}
.template-selector label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--text-primary);
}
.template-selector select {
width: 100%;
padding: 10px 15px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
background: white;
}
.template-download-btn {
margin-top: 10px;
padding: 8px 16px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.template-download-btn:hover {
background: var(--primary-hover);
}
.upload-area {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 40px 20px;
text-align: center;
margin-bottom: 20px;
cursor: pointer;
transition: all 0.3s;
background: var(--bg-color);
}
.upload-area:hover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.upload-area.dragover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.1);
}
.upload-icon-large {
font-size: 48px;
color: var(--primary-color);
margin-bottom: 12px;
}
.upload-text {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 8px;
}
.upload-hint {
font-size: 12px;
color: var(--text-tertiary);
}
.progress-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid var(--border-color);
}
.progress-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
font-size: 14px;
}
.progress-stats {
display: flex;
gap: 20px;
}
.stat-item {
display: flex;
align-items: center;
gap: 6px;
}
.stat-label {
color: var(--text-secondary);
}
.stat-value {
font-weight: 600;
color: var(--text-primary);
}
.stat-value.success {
color: var(--success-color);
}
.stat-value.error {
color: var(--error-color);
}
.progress-bar-container {
width: 100%;
height: 8px;
background: var(--bg-color);
border-radius: 4px;
overflow: hidden;
margin-bottom: 12px;
}
.progress-bar {
height: 100%;
background: var(--primary-color);
transition: width 0.3s ease;
border-radius: 4px;
}
.error-list {
margin-top: 16px;
max-height: 200px;
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 12px;
background: #fff5f5;
}
.error-item {
padding: 8px;
margin-bottom: 6px;
background: white;
border-left: 3px solid var(--error-color);
border-radius: 4px;
font-size: 13px;
}
.error-item:last-child {
margin-bottom: 0;
}
.error-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.error-reason {
color: var(--error-color);
font-weight: 500;
}
.download-error-btn {
margin-top: 12px;
padding: 8px 16px;
background: var(--error-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.download-error-btn:hover {
background: #cf1322;
}
.validation-table {
width: 100%;
border-collapse: collapse;
margin-top: 16px;
font-size: 13px;
table-layout: fixed;
}
.validation-table th,
.validation-table td {
padding: 10px;
text-align: left;
border-bottom: 1px solid var(--border-color);
white-space: normal;
word-break: normal;
overflow: visible;
vertical-align: middle;
}
.validation-table th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
white-space: nowrap;
}
.validation-table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.validation-table td:nth-child(5) {
white-space: normal;
word-break: break-word;
}
.validation-table th:nth-child(1),
.validation-table td:nth-child(1) {
width: 60px;
min-width: 60px;
text-align: center;
}
.validation-table th:nth-child(2),
.validation-table td:nth-child(2) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(3),
.validation-table td:nth-child(3) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(4),
.validation-table td:nth-child(4) {
width: 100px;
min-width: 100px;
text-align: center;
}
.validation-table th:nth-child(5),
.validation-table td:nth-child(5) {
width: auto;
min-width: 200px;
}
.validation-table tr.error-row {
background: #fff5f5;
}
.validation-table tr.error-row td {
color: var(--error-color);
}
#validation-table-container {
overflow-x: auto;
max-width: 100%;
width: 100%;
}
#validation-table-container table {
min-width: 600px;
}
.file-name-display {
margin-top: 12px;
padding: 10px;
background: var(--bg-color);
border-radius: 6px;
font-size: 13px;
color: var(--text-secondary);
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background-color: #01337a;
color: #fff;
padding: 10px;
text-align: left;
border: 1px solid #ddd;
}
td {
padding: 10px;
border: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* 在主页面CSS中添加 */
.sidebar-iframe {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
border: none;
z-index: 999;
}
/* 为main-content和header添加左边距以避开iframe */
.main-content {
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
}
.top-header {
left: var(--sidebar-width);
}
</style>
</head>
<body>
<div class="app-container">
<div id="sidebar-container"></div>
<header class="top-header">
<div class="header-left">
<div class="breadcrumb">
<span>首页</span>
<span class="breadcrumb-separator">/</span>
<span class="breadcrumb-current">零件管理</span>
</div>
</div>
<div class="header-right">
<button class="header-icon-btn" title="通知">
<svg class="nav-icon" viewBox="0 0 20 20">
<path d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z"/>
</svg>
<span class="notification-badge"></span>
</button>
<div class="lang-switcher">
<button class="lang-btn active">中文</button>
<button class="lang-btn">EN</button>
</div>
<div class="user-avatar"></div>
</div>
</header>
<div class="main-content" style="position: relative;">
<!-- <img src="./image/img_1.png" alt="" style="width: 100%;display:block;">-->
<div id="app">
<div class="container">
<div class="card" style="padding: 20px;">
<!-- <div class="toolbar">
<div class="card-title">零件费用标准列表</div>
<div style="display: flex; gap: 10px;">
<button class="btn btn-success" @click="handleImport">批量导入</button>
<button class="btn btn-primary" @click="handleAdd">+ 新增零件</button>
</div>
</div>-->
<div class="page-header">
<div>
<h1 class="page-title" data-i18n="title">配件管理</h1>
</div>
<div class="toolbar" style="display:flex;justify-content: end;margin-bottom: 20px;">
<button class="btn btn-primary" style="text-align: right;padding: 8px 28px;margin-right: 4px;" @click="handleAdd">批量导入</button>
<button class="btn btn-primary" style="text-align: right;padding: 8px 28px;" @click="handleAdd">+ 新增零件</button>
</div>
</div>
<table class="data-table">
<thead>
<tr>
<th>零件编号</th>
<th>零件名称</th>
<th>型号规格</th>
<th>标准单价</th>
<th>单位</th>
<th>适用设备</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in partList" :key="item.id">
<td>{{ item.partNo }}</td>
<td>{{ item.partName }}</td>
<td>{{ item.specification }}</td>
<td>¥{{ item.price }}</td>
<td>{{ item.unit }}</td>
<td>{{ item.applicableEquipment }}</td>
<td>
<span :class="item.status === '启用' ? 'badge badge-success' : 'badge badge-danger'">
{{ item.status }}
</span>
</td>
<td>
<div class="action-btns">
<button class="btn btn-primary btn-small" style="padding: 4px 14px" @click="handleEdit(item)">编辑</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
partList: [
{
id: 1,
partNo: 'P001',
partName: '服务器硬盘',
specification: '2TB SATA',
price: 800,
unit: '块',
applicableEquipment: '服务器',
status: '启用'
},
{
id: 2,
partNo: 'P002',
partName: '内存条',
specification: '16GB DDR4',
price: 600,
unit: '条',
applicableEquipment: '服务器/工作站',
status: '启用'
},
{
id: 3,
partNo: 'P003',
partName: '网络交换机',
specification: '24口千兆',
price: 2000,
unit: '台',
applicableEquipment: '网络设备',
status: '启用'
},
{
id: 4,
partNo: 'P004',
partName: 'UPS电源',
specification: '3KVA',
price: 3500,
unit: '台',
applicableEquipment: '电源设备',
status: '启用'
}
]
}
},
methods: {
handleAdd() {
window.location.href = '零件编辑新增.html?action=add';
},
handleEdit(item) {
window.location.href = `零件编辑新增.html?action=edit&id=${item.id}`;
},
handleImport() {
alert('批量导入功能(占位)');
}
}
}).mount('#app');
</script>
</div>
</div>
</body>
<script src="./js.js"></script>
</html>
\ No newline at end of file
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>设备档案</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #1B64F3;
--primary-hover: #1554D3;
--primary-light: #e6f7ff;
--bg-color: #F5F6FA;
--card-bg: #FFFFFF;
--sidebar-bg: #0F172A;
--text-primary: #1A1F36;
--text-secondary: #64748B;
--text-tertiary: #94A3B8;
--text-light: #CBD5E1;
--border-color: #E2E8F0;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--success-color: #22C55E;
--warning-color: #EAB308;
--error-color: #EF4444;
--sidebar-width: 260px;
--header-height: 64px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
background-color: var(--bg-color);
color: var(--text-primary);
line-height: 1.6;
overflow-x: hidden;
}
.app-container {
display: flex;
min-height: 100vh;
}
/* 左侧导航栏 */
.sidebar {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
background: var(--sidebar-bg);
border-right: 1px solid rgba(255, 255, 255, 0.1);
overflow-y: auto;
z-index: 1000;
}
.sidebar-logo {
padding: 20px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
gap: 12px;
}
.logo-icon {
width: 36px;
height: 36px;
background: var(--primary-color);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 700;
font-size: 18px;
}
.logo-text {
color: white;
font-size: 16px;
font-weight: 600;
}
.sidebar-menu {
padding: 16px 0;
}
.nav-group-title {
padding: 12px 20px 8px;
font-size: 11px;
font-weight: 600;
color: var(--text-tertiary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.menu-item, .nav-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 20px;
color: var(--text-light);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
position: relative;
cursor: pointer;
border: none;
background: none;
width: 100%;
text-align: left;
}
.menu-item:hover, .nav-item:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.menu-item.active, .nav-item.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-item.active::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: var(--primary-color);
}
.nav-item.has-submenu {
justify-content: space-between;
}
.nav-arrow {
width: 14px;
height: 14px;
transition: transform 0.2s;
margin-left: auto;
}
.nav-item.expanded .nav-arrow {
transform: rotate(90deg);
}
.nav-submenu {
display: none;
background: rgba(0, 0, 0, 0.1);
}
.nav-item.expanded + .nav-submenu {
display: block;
}
.nav-subitem {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 20px 10px 48px;
color: var(--text-light);
text-decoration: none;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
position: relative;
}
.nav-subitem:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.nav-subitem.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-icon {
width: 18px;
height: 18px;
stroke: currentColor;
stroke-width: 2;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
/* 顶部工具栏 */
.header, .top-header {
position: fixed;
top: 0;
left: var(--sidebar-width);
right: 0;
height: var(--header-height);
background: var(--card-bg);
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32px;
z-index: 999;
box-shadow: var(--shadow-sm);
}
.header-left {
display: flex;
align-items: center;
gap: 24px;
}
.breadcrumb {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--text-secondary);
}
.breadcrumb-separator {
color: var(--text-tertiary);
}
.breadcrumb-current {
color: var(--text-primary);
font-weight: 500;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.header-icon-btn {
position: relative;
width: 36px;
height: 36px;
border-radius: 8px;
border: none;
background: transparent;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
transition: all 0.2s;
}
.header-icon-btn:hover {
background: var(--bg-color);
color: var(--primary-color);
}
.notification-badge {
position: absolute;
top: 6px;
right: 6px;
width: 8px;
height: 8px;
background: var(--error-color);
border-radius: 50%;
border: 2px solid var(--card-bg);
}
.lang-switcher {
display: flex;
gap: 6px;
align-items: center;
}
.lang-btn {
padding: 6px 12px;
background: transparent;
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-secondary);
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.lang-btn:hover {
border-color: var(--primary-color);
color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.lang-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.user-avatar {
width: 36px;
height: 36px;
border-radius: 8px;
background: var(--primary-color);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 14px;
cursor: pointer;
}
.page-title {
font-size: 20px;
font-weight: 600;
color: var(--text-primary);
}
.user-info {
display: flex;
align-items: center;
gap: 16px;
}
.notification {
position: relative;
cursor: pointer;
color: var(--text-secondary);
}
/* 主内容区域 - 已调整左右内边距 */
.main-content {
flex: 1;
padding: 24px;
overflow-y: auto;
min-height: 100vh;
margin-left: 260px;
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
/* 调整左右内边距,从 8px 增加到 32px,以利用更多空间 */
/* padding: 4px 32px;
min-height: calc(100vh - var(--header-height));
.main-content { } */
}
.content-area {
padding: 0;
}
/* 页面标题区域 */
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.page-title-section {
display: flex;
flex-direction: column;
gap: 4px;
}
.page-title-main {
font-size: 24px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.3px;
}
.page-title-sub {
font-size: 14px;
color: var(--text-secondary);
}
/* 表格数据优化 */
.table-cell-number {
font-weight: 600;
color: var(--text-primary);
}
.table-cell-date {
color: var(--text-secondary);
font-size: 13px;
}
/* 表格内容样式增强 */
td strong {
color: var(--text-primary);
font-weight: 600;
}
td code {
font-size: 12px;
font-weight: 500;
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-state-icon {
font-size: 48px;
color: var(--text-tertiary);
margin-bottom: 16px;
}
.empty-state-text {
font-size: 14px;
color: var(--text-secondary);
}
/* 响应式表格优化 */
@media (max-width: 1200px) {
.table-container {
overflow-x: auto;
}
table {
min-width: 1000px;
}
}
@media (max-width: 768px) {
.card-body {
padding: 16px;
}
th, td {
padding: 12px 16px;
}
.action-buttons {
flex-direction: column;
gap: 6px;
}
.action-btn {
width: 100%;
justify-content: center;
}
}
/* 卡片样式 */
.card {
background: var(--card-bg);
border-radius: 12px;
box-shadow: var(--shadow-sm);
margin-bottom: 24px;
border: 1px solid var(--border-color);
}
.card-header {
padding: 18px 20px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--bg-color);
}
.card-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.2px;
}
.card-body {
padding: 20px 16px;
}
/* 按钮样式 */
.btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(27, 100, 243, 0.3);
}
.btn-secondary {
background: #f0f0f0;
color: var(--text-light);
}
.btn-secondary:hover {
background: #e0e0e0;
}
.btn-success {
background: var(--success-color);
color: white;
}
.btn-success:hover {
background: #389e0d;
}
.btn-danger {
background: var(--error-color);
color: white;
}
.btn-danger:hover {
background: #cf1322;
}
/* 标签页样式 */
.tabs {
display: flex;
gap: 16px;
margin-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
.tab {
padding: 10px 0;
color: var(--text-light);
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
font-size: 14px;
}
.tab:hover {
color: var(--primary-color);
}
.tab.active {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
}
/* 表格样式 */
.table-container {
overflow-x: auto;
border-radius: 8px;
width: 100%;
}
table {
width: 100%;
border-collapse: collapse;
background: var(--card-bg);
}
th, td {
padding: 16px 20px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.5px;
white-space: nowrap;
}
tbody tr {
transition: all 0.2s;
}
tbody tr:hover {
background: rgba(27, 100, 243, 0.04);
}
tbody tr:last-child td {
border-bottom: none;
}
td {
color: var(--text-primary);
font-size: 14px;
vertical-align: middle;
}
.status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status.active {
background: #f6ffed;
color: var(--success-color);
}
.status.inactive {
background: #fff2e8;
color: var(--warning-color);
}
.action-buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.action-btn {
padding: 6px 14px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
.action-btn i {
font-size: 12px;
}
.action-btn.edit-btn {
background: rgba(27, 100, 243, 0.1);
color: var(--primary-color);
}
.action-btn.edit-btn:hover {
background: rgba(27, 100, 243, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.delete-btn {
background: rgba(239, 68, 68, 0.1);
color: var(--error-color);
}
.action-btn.delete-btn:hover {
background: rgba(239, 68, 68, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(239, 68, 68, 0.2);
}
.action-btn.view-btn {
background: rgba(27, 100, 243, 0.08);
color: var(--primary-color);
}
.action-btn.view-btn:hover {
background: rgba(27, 100, 243, 0.15);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.copy-btn {
background: rgba(34, 197, 94, 0.1);
color: var(--success-color);
}
.action-btn.copy-btn:hover {
background: rgba(34, 197, 94, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(34, 197, 94, 0.2);
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
}
.modal.show {
display: flex;
}
.modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.add-modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 800px;
max-height: 85vh;
overflow-y: auto;
}
.modal-header {
padding: 16px 24px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-title {
font-size: 16px;
font-weight: 600;
color: var(--text-color);
}
.close-modal {
background: none;
border: none;
font-size: 20px;
color: var(--text-light);
cursor: pointer;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 0.3s;
}
.close-modal:hover {
background: var(--secondary-color);
color: var(--text-color);
}
.modal-body {
padding: 24px;
}
.modal-footer {
padding: 16px 24px;
border-top: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
/* 新增表单模态框样式 */
.add-modal-form .form-group {
margin-bottom: 20px;
}
.add-modal-form .form-row {
display: flex;
gap: 15px;
margin-bottom: 15px;
}
.add-modal-form .form-row .form-group {
flex: 1;
margin-bottom: 0;
}
.add-modal-form label {
display: block;
margin-bottom: 6px;
font-weight: 500;
color: var(--text-secondary);
font-size: 14px;
}
.add-modal-form input,
.add-modal-form select,
.add-modal-form textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
}
.add-modal-form input:focus,
.add-modal-form select:focus,
.add-modal-form textarea:focus {
outline: none;
border-color: var(--primary-color);
}
.add-modal-form .section-title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin: 20px 0 15px 0;
padding-bottom: 8px;
border-bottom: 1px solid var(--border-color);
}
.upload-box {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
background-color: var(--bg-color);
}
.upload-box:hover {
border-color: var(--primary-color);
background-color: rgba(27, 100, 243, 0.05);
}
.upload-icon {
font-size: 24px;
color: var(--primary-color);
margin-bottom: 10px;
}
.upload-info {
color: var(--text-secondary);
font-size: 13px;
}
.file-name {
margin-top: 10px;
font-weight: 500;
color: var(--primary-color);
font-size: 13px;
}
.param-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.param-table th, .param-table td {
border: 1px solid var(--border-color);
padding: 8px;
text-align: left;
}
.param-table th {
background-color: var(--bg-color);
font-weight: 600;
}
.add-param-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 8px 15px;
border-radius: 6px;
cursor: pointer;
margin-top: 10px;
font-size: 14px;
}
.add-param-btn:hover {
background: var(--primary-hover);
}
/* 二维码预览样式 */
.qrcode-preview-large {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background: var(--primary-light);
border-radius: 8px;
margin-bottom: 20px;
}
.qrcode-image {
width: 200px;
height: 200px;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 15px;
}
.qrcode-image img {
max-width: 100%;
max-height: 100%;
}
/* 详情信息样式 */
.detail-info {
margin-top: 20px;
}
.detail-item {
display: flex;
margin-bottom: 12px;
font-size: 14px;
}
.detail-label {
width: 100px;
color: var(--text-light);
flex-shrink: 0;
}
.detail-value {
color: var(--text-color);
font-weight: 500;
}
/* 响应式设计 */
@media (max-width: 768px) {
.sidebar {
transform: translateX(-100%);
}
.sidebar.show-mobile {
transform: translateX(0);
}
.main-content {
margin-left: 0;
margin-top: 0;
padding: 16px; /* 在移动端保持较小的内边距 */
}
.header, .top-header {
left: 0;
}
.tabs {
flex-wrap: wrap;
}
}
/* 批量上传相关样式 */
.batch-upload-modal .modal-content {
max-width: 800px;
}
.template-selector {
margin-bottom: 20px;
}
.template-selector label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--text-primary);
}
.template-selector select {
width: 100%;
padding: 10px 15px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
background: white;
}
.template-download-btn {
margin-top: 10px;
padding: 8px 16px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.template-download-btn:hover {
background: var(--primary-hover);
}
.upload-area {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 40px 20px;
text-align: center;
margin-bottom: 20px;
cursor: pointer;
transition: all 0.3s;
background: var(--bg-color);
}
.upload-area:hover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.upload-area.dragover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.1);
}
.upload-icon-large {
font-size: 48px;
color: var(--primary-color);
margin-bottom: 12px;
}
.upload-text {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 8px;
}
.upload-hint {
font-size: 12px;
color: var(--text-tertiary);
}
.progress-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid var(--border-color);
}
.progress-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
font-size: 14px;
}
.progress-stats {
display: flex;
gap: 20px;
}
.stat-item {
display: flex;
align-items: center;
gap: 6px;
}
.stat-label {
color: var(--text-secondary);
}
.stat-value {
font-weight: 600;
color: var(--text-primary);
}
.stat-value.success {
color: var(--success-color);
}
.stat-value.error {
color: var(--error-color);
}
.progress-bar-container {
width: 100%;
height: 8px;
background: var(--bg-color);
border-radius: 4px;
overflow: hidden;
margin-bottom: 12px;
}
.progress-bar {
height: 100%;
background: var(--primary-color);
transition: width 0.3s ease;
border-radius: 4px;
}
.error-list {
margin-top: 16px;
max-height: 200px;
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 12px;
background: #fff5f5;
}
.error-item {
padding: 8px;
margin-bottom: 6px;
background: white;
border-left: 3px solid var(--error-color);
border-radius: 4px;
font-size: 13px;
}
.error-item:last-child {
margin-bottom: 0;
}
.error-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.error-reason {
color: var(--error-color);
font-weight: 500;
}
.download-error-btn {
margin-top: 12px;
padding: 8px 16px;
background: var(--error-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.download-error-btn:hover {
background: #cf1322;
}
.validation-table {
width: 100%;
border-collapse: collapse;
margin-top: 16px;
font-size: 13px;
table-layout: fixed;
}
.validation-table th,
.validation-table td {
padding: 10px;
text-align: left;
border-bottom: 1px solid var(--border-color);
white-space: normal;
word-break: normal;
overflow: visible;
vertical-align: middle;
}
.validation-table th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
white-space: nowrap;
}
.validation-table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.validation-table td:nth-child(5) {
white-space: normal;
word-break: break-word;
}
.validation-table th:nth-child(1),
.validation-table td:nth-child(1) {
width: 60px;
min-width: 60px;
text-align: center;
}
.validation-table th:nth-child(2),
.validation-table td:nth-child(2) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(3),
.validation-table td:nth-child(3) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(4),
.validation-table td:nth-child(4) {
width: 100px;
min-width: 100px;
text-align: center;
}
.validation-table th:nth-child(5),
.validation-table td:nth-child(5) {
width: auto;
min-width: 200px;
}
.validation-table tr.error-row {
background: #fff5f5;
}
.validation-table tr.error-row td {
color: var(--error-color);
}
#validation-table-container {
overflow-x: auto;
max-width: 100%;
width: 100%;
}
#validation-table-container table {
min-width: 600px;
}
.file-name-display {
margin-top: 12px;
padding: 10px;
background: var(--bg-color);
border-radius: 6px;
font-size: 13px;
color: var(--text-secondary);
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background-color: #01337a;
color: #fff;
padding: 10px;
text-align: left;
border: 1px solid #ddd;
}
td {
padding: 10px;
border: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* 在主页面CSS中添加 */
.sidebar-iframe {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
border: none;
z-index: 999;
}
/* 为main-content和header添加左边距以避开iframe */
.main-content {
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
}
.top-header {
left: var(--sidebar-width);
}
</style>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
background: #f5f7fa;
min-height: 100vh;
padding: 20px;
}
.container {
/*max-width: 1000px;*/
/*margin: 0 auto;*/
}
.header {
background: white;
padding: 20px 30px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.header h1 {
color: #333;
font-size: 24px;
font-weight: 600;
}
.card {
background: white;
border-radius: 8px;
padding: 30px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.card-title {
font-size: 18px;
font-weight: 600;
color: #333;
margin-bottom: 25px;
padding-bottom: 12px;
border-bottom: 2px solid #409eff;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
margin-bottom: 8px;
color: #333;
font-weight: 500;
font-size: 14px;
}
.form-label .required {
color: #f56c6c;
margin-left: 4px;
}
.form-control {
width: 100%;
padding: 10px 12px;
border: 1px solid #dcdfe6;
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
}
.form-control:focus {
outline: none;
border-color: #409eff;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 15px;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #e4e7ed;
}
.btn {
padding: 10px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
font-weight: 500;
}
.btn-primary {
background: #409eff;
color: white;
}
.btn-primary:hover {
background: #66b1ff;
}
.btn-default {
background: #f5f7fa;
color: #606266;
border: 1px solid #dcdfe6;
}
.btn-default:hover {
background: #ecf5ff;
color: #409eff;
border-color: #409eff;
}
.form-hint {
font-size: 12px;
color: #909399;
margin-top: 5px;
}
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #409eff;
}
input:checked + .slider:before {
transform: translateX(26px);
}
</style>
</head>
<body>
<div class="app-container">
<div id="sidebar-container"></div>
<header class="top-header">
<div class="header-left">
<div class="breadcrumb">
<span>首页</span>
<span class="breadcrumb-separator">/</span>
<span class="breadcrumb-current">设备档案</span>
</div>
</div>
<div class="header-right">
<button class="header-icon-btn" title="通知">
<svg class="nav-icon" viewBox="0 0 20 20">
<path d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z"/>
</svg>
<span class="notification-badge"></span>
</button>
<div class="lang-switcher">
<button class="lang-btn active">中文</button>
<button class="lang-btn">EN</button>
</div>
<div class="user-avatar"></div>
</div>
</header>
<div class="main-content" style="position: relative;">
<div id="app">
<div class="container">
<div class="header">
<h1>零件费用标准{{ isEdit ? '编辑' : '新增' }}</h1>
</div>
<div class="card">
<div class="card-title">零件费用标准{{ isEdit ? '编辑' : '新增' }}</div>
<form @submit.prevent="handleSubmit">
<div class="form-row">
<div class="form-group">
<label class="form-label">零件编号 <span class="required">*</span></label>
<input
type="text"
v-model="form.partNo"
class="form-control"
placeholder="请输入零件编号"
required
/>
</div>
<div class="form-group">
<label class="form-label">零件名称 <span class="required">*</span></label>
<input
type="text"
v-model="form.partName"
class="form-control"
placeholder="请输入零件名称"
required
/>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">型号规格 <span class="required">*</span></label>
<input
type="text"
v-model="form.specification"
class="form-control"
placeholder="请输入型号规格"
required
/>
</div>
<div class="form-group">
<label class="form-label">单位 <span class="required">*</span></label>
<input
type="text"
v-model="form.unit"
class="form-control"
placeholder="如:块、条、台等"
required
/>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">标准单价 <span class="required">*</span></label>
<input
type="number"
v-model.number="form.price"
class="form-control"
placeholder="请输入标准单价"
step="0.01"
min="0"
required
/>
<div class="form-hint">单位:元</div>
</div>
<!-- <div class="form-group">
<label class="form-label">是否含税</label>
<div style="margin-top: 8px;">
<label class="switch">
<input type="checkbox" v-model="form.taxIncluded">
<span class="slider"></span>
</label>
<span style="margin-left: 10px; color: #606266;">{{ form.taxIncluded ? '含税' : '不含税' }}</span>
</div>
</div> -->
</div>
<div class="form-group">
<label class="form-label">生效时间 <span class="required">*</span></label>
<input
type="date"
v-model="form.effectiveDate"
class="form-control"
required
/>
</div>
<div class="form-group">
<label class="form-label">备注</label>
<textarea
v-model="form.remark"
class="form-control"
rows="4"
placeholder="请输入备注信息"
></textarea>
</div>
<div class="form-actions">
<button type="button" class="btn btn-default" @click="handleCancel">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
const urlParams = new URLSearchParams(window.location.search);
const action = urlParams.get('action');
const id = urlParams.get('id');
return {
isEdit: action === 'edit',
form: {
partNo: '',
partName: '',
specification: '',
unit: '',
price: null,
taxIncluded: true,
effectiveDate: '',
remark: ''
}
}
},
mounted() {
if (this.isEdit) {
const urlParams = new URLSearchParams(window.location.search);
const id = urlParams.get('id');
// 模拟加载数据
if (id === '1') {
this.form = {
partNo: 'P001',
partName: '服务器硬盘',
specification: '2TB SATA',
unit: '块',
price: 800,
taxIncluded: true,
effectiveDate: '2024-01-01',
remark: '标准服务器硬盘'
};
}
}
},
methods: {
handleSubmit() {
alert(this.isEdit ? '保存成功!' : '新增成功!');
window.location.href = '零件管理.html';
},
handleCancel() {
if (confirm('确定要取消吗?未保存的数据将丢失。')) {
window.location.href = '零件管理.html';
}
}
}
}).mount('#app');
</script>
</div>
</div>
</body>
<script src="./js.js"></script>
<script>
let importstr = document.getElementById('import')
let uploadstr = document.getElementById('batch-upload-modal')
let close = document.getElementById('close-batch-upload-modal')
let cancel = document.getElementById('cancel-batch-upload-btn')
uploadstr.style.display = 'none'
importstr.addEventListener('click', function () {
uploadstr.style.display = 'flex'
})
uploadstr.addEventListener('click', function (e) {
// 阻止事件冒泡,只有点击模态框背景时才关闭
if (e.target === uploadstr) {
uploadstr.style.display = 'none'
}
})
close.addEventListener('click', function () {
uploadstr.style.display = 'none'
})
cancel.addEventListener('click', function () {
uploadstr.style.display = 'none'
})
</script>
</html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment