Compare commits

...

60 Commits

Author SHA1 Message Date
4b94c614ad 司机app的普通材料接口不挂token 2026-04-13 16:32:33 +08:00
b39ae0bdf1 CRM_26-03-31#story#8426,调度APP的“参保救援职业责任险”链接中的文本更新的需求(咨询修改) 2026-04-13 11:25:47 +08:00
709f125c42 司机app的普通材料接口不挂token 2026-04-10 13:46:26 +08:00
a0c1a2700a CRM_26-03-31#story#8426,调度APP的“参保救援职业责任险”链接中的文本更新的需求 2026-04-01 13:31:33 +08:00
8c25f5a195 工单详情,‘查看照片’按钮添加显示逻辑 2026-03-31 09:25:10 +08:00
ee50c3ba19 CRM_26-03-31#story#8372,服务商KPI看板设置埋点及支持数据导出需求--中心组 2026-03-26 16:10:26 +08:00
1477f94774 CRM_26-03-31#story#8372,服务商KPI看板设置埋点及支持数据导出需求--中心组222 2026-03-26 15:31:11 +08:00
35fd987f00 CRM_26-03-31#story#8372,服务商KPI看板设置埋点及支持数据导出需求--中心组 2026-03-26 15:23:58 +08:00
b6491a21d1 CRM_26-03-31#story#8372,服务商KPI看板设置埋点及支持数据导出需求--中心组(log) 2026-03-26 14:54:14 +08:00
030417ba9c CRM_26-03-31#story#8372,服务商KPI看板设置埋点及支持数据导出需求--中心组 2026-03-26 14:34:41 +08:00
c05bdb361b CRM_26-03-31#story#8372,服务商KPI看板设置埋点及支持数据导出需求--中心组 2026-03-26 11:50:08 +08:00
e288d1e180 工单详情,‘生成司机信息’问题修复,VConsole去除 2026-03-18 10:01:35 +08:00
a48e73bdb5 工单详情,‘生成司机信息’问题修复 2026-03-18 09:37:09 +08:00
56a8ba66b7 工单详情,‘生成司机信息’问题修复 2026-03-18 09:30:25 +08:00
8c62b8e704 工单详情,‘生成司机信息’问题修复 2026-03-18 09:22:33 +08:00
f1a3f7b45b 工单详情,‘生成司机信息’格式更改 2026-03-17 11:25:07 +08:00
e7344a1f16 工单详情,‘生成司机信息’操作车牌号字段更换 2026-03-17 09:47:26 +08:00
75dd0b9740 车架号添加 2026-03-11 17:13:18 +08:00
aa5b724bed CRM_26-03-10#story#8237,调度app新增未开票批次提醒—徐力雯 2026-03-09 11:15:49 +08:00
ca99e068cf CRM_26-03-10#story#8252,二手拖车系统查询和导表功能优化 2026-03-05 11:32:27 +08:00
aafd7ffdb5 CRM_26-03-03#story#8210,调度app和司机app客户姓名调整(后期补需求 去除log,补Number) 2026-03-04 13:21:26 +08:00
112f42669c CRM_26-03-03#story#8210,调度app和司机app客户姓名调整(后期补需求 log测试) 2026-03-04 13:13:11 +08:00
9bf8e1253d CRM_26-03-03#story#8210,调度app和司机app客户姓名调整(后期补需求) 2026-03-04 11:53:39 +08:00
4f9134249f CRM_26-03-03#story#8210,调度app和司机app客户姓名调整 2026-03-04 10:18:53 +08:00
318922bddc CRM_26-03-03#story#8210,调度app和司机app客户联系方式调整 2026-02-27 15:49:29 +08:00
5d0d4541a8 车辆管理,有责任险审核权限的展示‘保额’且必填 2026-02-12 14:05:22 +08:00
17aa9b54ca 年度总结页面--logo 文字位置上移 2026-02-09 14:06:42 +08:00
9d3d822227 年度总结页面--logo 大小修改 2026-02-09 13:54:32 +08:00
fbee7979e4 年度总结页面--修改 2026-02-06 17:21:13 +08:00
8e55d61a9e 年度总结页面 2026-02-06 16:51:51 +08:00
83f36b12a8 CRM_26-02-05#story#8149,潜在服务商提交界面信息核验 2026-02-03 17:33:46 +08:00
e800ee1b7e VConsole去除 2026-01-29 11:26:56 +08:00
3fbcc7a125 VConsole调试 2026-01-29 10:24:25 +08:00
c90bf52b4d CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-28 11:15:51 +08:00
c9ac87b104 CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-28 10:02:18 +08:00
47fdf8f528 CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-27 16:28:33 +08:00
9192625165 CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-27 15:31:31 +08:00
5ebbce5c1f CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-27 15:29:56 +08:00
dc5327c8e4 h5链接替换33 2026-01-27 15:16:25 +08:00
044832a8f7 CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-27 15:12:39 +08:00
19c5809af2 CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-27 15:02:42 +08:00
d41684d7ed h5(返回) 2026-01-27 14:38:30 +08:00
60445b1523 h5链接替换-文件替换 2026-01-27 14:33:40 +08:00
534ef90f2e CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-27 14:23:15 +08:00
f8484391b8 CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-27 14:16:08 +08:00
414f2cd320 h5修改 2026-01-27 14:12:49 +08:00
d12ef20726 CRM_26-01-29#story#8070,调度APP-司机信息复制-仅子公司 2026-01-27 14:11:25 +08:00
ed7ce35a91 h5链接替换 2026-01-26 10:23:14 +08:00
6b5bc0494c 服务商人员,电话格式验证规则同步系统后台 2026-01-22 16:57:27 +08:00
fed4ae6edf CRM_26-01-22#story#7966,关于在打通系统中责任险信息关联的需求 2026-01-22 13:21:45 +08:00
87546848d2 CRM_26-01-22#story#7966,关于在打通系统中责任险信息关联的需求 2026-01-22 13:14:30 +08:00
3a6d0878aa CRM_26-01-22#story#7966,关于在打通系统中责任险信息关联的需求 2026-01-22 13:12:08 +08:00
d18fec1ddc CRM_26-01-22#story#7966,关于在打通系统中责任险信息关联的需求 2026-01-22 11:48:20 +08:00
62f2c166c6 CRM_26-01-22#story#7966,关于在打通系统中责任险信息关联的需求 2026-01-22 11:33:59 +08:00
14a14e2c87 CRM_26-01-22#story#7966,关于在打通系统中责任险信息关联的需求 2026-01-22 10:56:15 +08:00
8a457952fa CRM_26-01-29#task#13363,潜在服务商审核-财务信息-h5做必填 2026-01-21 13:56:14 +08:00
c657f3b5ac 省市修改 2026-01-19 17:22:25 +08:00
31d1388890 CRM_26-01-22#story#7966,关于在打通系统中责任险信息关联的需求 2026-01-15 17:40:24 +08:00
dc94c6d261 CRM_26-01-22#story#7966,关于在打通系统中责任险信息关联的需求 2026-01-15 16:07:45 +08:00
97c86dbee3 二手拖车车源发布成功后关闭弹窗 2026-01-15 15:45:46 +08:00
35 changed files with 218503 additions and 84 deletions

3
.idea/misc.xml generated
View File

@@ -3,4 +3,7 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="WebPackConfiguration">
<option name="mode" value="DISABLED" />
</component>
</project>

View File

@@ -0,0 +1,160 @@
# 年终总结看板 Dashboard
道路救援服务年终数据可视化看板项目。
## 项目结构
```
dashboard-demo/
├── index.html # 主看板页面支持URL参数动态加载数据
├── data/
│ ├── 供应商年度KPI.xlsx # 服务商KPI数据主数据源
│ ├── 师傅案件top3.xlsx # 案件量TOP3师傅数据
│ ├── 师傅在线top3.xlsx # 在线时长TOP3师傅数据
│ ├── 拒单率最高地区.xlsx # 拒单率最高地区数据
│ └── 拒单率最高时段.xlsx # 拒单率最高时段数据
└── README.md # 项目说明
```
## 功能特性
- 深色主题数据可视化看板
- **直接读取Excel文件**无需转换为JSON
- 支持通过URL参数 `?providerId=XXX` 切换不同服务商
- 右上角下拉框可实时切换服务商自动从Excel读取服务商列表
- 使用 Chart.js 实现饼状图和雷达图
- 使用 SheetJS (xlsx) 解析Excel文件
- 响应式布局,支持不同屏幕尺寸
- 数据与页面分离,便于维护
## 数据指标
看板展示以下数据指标:
1. **总案件量分布**(饼状图)
- 小修、困境、拖车三类案件占比
2. **年度聚合案件量**
3. **案件量TOP3师傅**
4. **车辆平均总在线时长**
5. **在线时长TOP3师傅**
6. **拒单率最高地区**
7. **拒单率最高时段**
8. **APP使用率**
- 年度APP使用率展示
## Excel数据结构
### 1. 供应商年度KPI.xlsx
| 列名 | 说明 |
|------|------|
| 服务商id | 服务商唯一标识 |
| 服务商 | 服务商名称 |
| 完成案件量 | 总案件数量 |
| 拖车完成量 | 拖车案件数 |
| 小修完成量 | 小修案件数 |
| 困境完成量 | 困境案件数 |
| 聚合案件量 | 聚合案件数量 |
| APP使用率. | APP使用率小数形式如0.998 |
| 年度车辆平均总在线时长(小时) | 车辆平均在线时长 |
### 2. 师傅案件top3.xlsx
| 列名 | 说明 |
|------|------|
| 服务商id | 服务商唯一标识 |
| 服务商 | 服务商名称 |
| 服务人员工号 | 师傅姓名/工号 |
| 完成案件量 | 该师傅完成的案件数 |
### 3. 师傅在线top3.xlsx
| 列名 | 说明 |
|------|------|
| 服务商名称 | 服务商名称 |
| 司机姓名 | 师傅姓名 |
| 年度总在线时长(小时) | 在线时长 |
### 4. 拒单率最高地区.xlsx
| 列名 | 说明 |
|------|------|
| 供应商名称 | 服务商名称 |
| 地区 | 拒单率最高的地区 |
| 拒单率 | 拒单率(小数形式) |
### 5. 拒单率最高时段.xlsx
| 列名 | 说明 |
|------|------|
| 供应商名称 | 服务商名称 |
| 时段 | 拒单率最高的时段 |
| 拒单率 | 拒单率(小数形式) |
## 使用方式
### 1. 启动本地服务器
由于页面使用 `fetch` 加载JSON数据需要通过HTTP服务器访问
```bash
cd C:\Users\Administrator\dashboard-demo
# 使用 Python
python -m http.server 8080
# 或使用 Node.js
npx serve .
# 或使用 PHP
php -S localhost:8080
```
### 2. 访问页面
- 默认服务商:`http://localhost:8080`(自动加载第一个服务商)
- 指定服务商:`http://localhost:8080?providerId=1128`使用服务商id
- 切换服务商:使用页面右上角的下拉框
### 3. 更新数据
直接替换 `data/` 目录下的Excel文件即可页面会自动读取最新数据。
服务商列表从Excel自动生成无需手动配置。
## 技术栈
- HTML5 / CSS3
- JavaScript (ES6+)
- Chart.js - 图表库(饼图、雷达图)
- SheetJS (xlsx) - Excel文件解析
- CSS Grid / Flexbox - 布局
## 后续优化方向
- [ ] 添加更多图表类型(柱状图、折线图等)
- [ ] 支持时间范围筛选
- [ ] 添加数据导出功能
- [ ] 移动端适配优化
- [ ] 添加数据加载骨架屏
- [ ] 支持主题切换(深色/浅色)
## 更新日志
### 2025-01-21
- 改为直接读取Excel文件无需JSON转换
- 服务商列表从Excel自动生成
- 将"AB段里程对比"改为"APP使用率"展示
- 新增服务商选择下拉框
### 2025-01-20
- 初始版本
- 实现基础看板布局
- 支持URL参数切换服务商
- 数据JSON化与页面分离

View File

@@ -0,0 +1,47 @@
{
"serviceProviderId": "SP001",
"serviceProviderName": "上海道路救援服务中心",
"year": 2025,
"summary": {
"totalCases": 100,
"caseBreakdown": {
"minorRepair": 20,
"predicament": 20,
"towing": 60
},
"aggregatedCases": 15
},
"topMastersByCases": [
{ "rank": 1, "name": "小王", "cases": 18 },
{ "rank": 2, "name": "小张", "cases": 16 },
{ "rank": 3, "name": "小李", "cases": 12 }
],
"onlineHours": {
"averageTotal": 2920,
"topMasters": [
{ "rank": 1, "name": "小王", "hours": 3230 },
{ "rank": 2, "name": "小张", "hours": 3028 },
{ "rank": 3, "name": "小李", "hours": 2996 }
]
},
"rejectionRate": {
"highestRegion": {
"name": "崇明",
"rate": 21.2
},
"highestTimeSlot": {
"period": "18:00-22:00",
"description": "晚高峰时段"
}
},
"abMileage": {
"highest": {
"region": "崇明",
"distance": 62
},
"lowest": {
"region": "黄浦",
"distance": 6
}
}
}

View File

@@ -0,0 +1,47 @@
{
"serviceProviderId": "SP002",
"serviceProviderName": "浦东汽车救援有限公司",
"year": 2025,
"summary": {
"totalCases": 156,
"caseBreakdown": {
"minorRepair": 35,
"predicament": 41,
"towing": 80
},
"aggregatedCases": 22
},
"topMastersByCases": [
{ "rank": 1, "name": "老陈", "cases": 28 },
{ "rank": 2, "name": "大刘", "cases": 24 },
{ "rank": 3, "name": "阿强", "cases": 19 }
],
"onlineHours": {
"averageTotal": 3150,
"topMasters": [
{ "rank": 1, "name": "老陈", "hours": 3580 },
{ "rank": 2, "name": "大刘", "hours": 3420 },
{ "rank": 3, "name": "阿强", "hours": 3210 }
]
},
"rejectionRate": {
"highestRegion": {
"name": "奉贤",
"rate": 18.5
},
"highestTimeSlot": {
"period": "07:00-09:00",
"description": "早高峰时段"
}
},
"abMileage": {
"highest": {
"region": "金山",
"distance": 55
},
"lowest": {
"region": "静安",
"distance": 8
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
{
"name": "data",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "data",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"xlsx": "^0.18.5"
}
},
"node_modules/adler-32": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz",
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/cfb": {
"version": "1.2.2",
"resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz",
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"crc-32": "~1.2.0"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/codepage": {
"version": "1.15.0",
"resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz",
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"license": "Apache-2.0",
"bin": {
"crc32": "bin/crc32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/frac": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz",
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/ssf": {
"version": "0.11.2",
"resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz",
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
"license": "Apache-2.0",
"dependencies": {
"frac": "~1.1.2"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/wmf": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz",
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/word": {
"version": "0.3.0",
"resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz",
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/xlsx": {
"version": "0.18.5",
"resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz",
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"cfb": "~1.2.1",
"codepage": "~1.15.0",
"crc-32": "~1.2.1",
"ssf": "~0.11.2",
"wmf": "~1.0.1",
"word": "~0.3.0"
},
"bin": {
"xlsx": "bin/xlsx.njs"
},
"engines": {
"node": ">=0.8"
}
}
}
}

View File

@@ -0,0 +1,16 @@
{
"name": "data",
"version": "1.0.0",
"description": "",
"main": "read-excel.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"xlsx": "^0.18.5"
}
}

View File

@@ -0,0 +1,30 @@
const XLSX = require('xlsx');
const fs = require('fs');
const path = require('path');
// Excel文件路径
const excelPath = 'C:\\Users\\chenhaid\\Documents\\WXWork\\1688858118476511\\Cache\\File\\2026-02\\供应商年度KPIv5.xlsx';
// 输出JSON文件路径
const outputPath = path.join(__dirname, 'kpi.json');
// 读取Excel文件
const workbook = XLSX.readFile(excelPath);
// 获取第一个工作表名称
const sheetName = workbook.SheetNames[0];
console.log('工作表列表:', workbook.SheetNames);
// 获取工作表
const worksheet = workbook.Sheets[sheetName];
// 转换为JSON
const jsonData = XLSX.utils.sheet_to_json(worksheet);
console.log('读取到', jsonData.length, '条数据');
console.log('第一条数据示例:', JSON.stringify(jsonData[0], null, 2));
// 写入JSON文件
fs.writeFileSync(outputPath, JSON.stringify(jsonData, null, 2), 'utf8');
console.log('已保存到:', outputPath);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

View File

@@ -23,7 +23,7 @@ export function toDoAudit(data){
data
})
}
// 工单详情
//
export function getOrderDetail(data){
return request({
url:'/supplierAppV2/dispatchApp/order/getOrderDetail',
@@ -77,6 +77,15 @@ export function updateOrderSettlement(data){
data
})
}
// 获取司机信息
export function getDriverInfo(data){
return request({
url:'/supplierAppV2/dispatchApp/order/getDriverInfo',
method:'POST',
contentType:'application/json',
data
})
}
// 电瓶数量列表
export function batteryCountList(){
return request({
@@ -168,3 +177,23 @@ export function getNewVersion(key){
params: key
})
}
export function getLog(data){
// 添加log
return request({
url: '/ureport/pageView/save',
method:'POST',
contentType:'application/json',
data
})
}
//获取最新版本
export function getUserBO(){
return request({
url: '/base/user/getUserBO',
method:'POST',
})
}

View File

@@ -54,7 +54,7 @@ export function userFeedback(data){
data
})
}
//二手拖车信息擦亮
//擦亮
export function usedCarPolish(data){
return request({
url: `/toc-user/car-app/usedCarPolish/${data}`,

View File

@@ -29,7 +29,7 @@ service.interceptors.request.use(
// let token='eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBTkNIQU5HIiwidXNlcklkIjo0NTY3MSwibmFtZSI6IuWuieeVhSIsInVzZXJOYW1lIjoiQU5DSEFORyIsInN1cHBsaWVySWQiOjExMjgsImlzWmQiOjAsImV4cCI6MTc1NTQyMjUyNX0.xzDZhaANJFnbeViIHJA0SEtOyTv7Ja3rKmXqRKRuFkc'
// let token='eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJTSEhQWEIiLCJ1c2VySWQiOjU0NzI2LCJuYW1lIjoiI-a1i-ivleWwj-eZveeZvSIsInVzZXJOYW1lIjoiU0hIUFhCIiwic3VwcGxpZXJJZCI6MTAwMDE2NSwiZXhwIjoxNzQ0NTEwNzkwfQ.JPk0OA7slYJN3FIi_uhW4Y0CiWRvl6R1dK8MRTbyhD8'
// if(!(reqUrl=='/supplier/supplierTraining/trainingTask' || reqUrl=='/supplier/supplierTraining/normalList' || reqUrl=='/supplier/supplierTraining/trainingList')){
if (reqUrl=='/supplier/supplierTraining/trainingList' && config?.params?.type==1){
if ((reqUrl=='/supplier/supplierTraining/trainingList' || reqUrl=='/supplier/supplierTraining/normalList') && config?.params?.type==1){
console.log('司机app使用该请求不挂token')
} else {
if(token) {

View File

@@ -1,3 +1,6 @@
import { getLog } from "@/api/order"
let _setLogTimer = null
export const myMixins = {
data() {
@@ -5,6 +8,11 @@ export const myMixins = {
}
},
methods: {
setLogHandler(data) {
if (_setLogTimer) return
_setLogTimer = setTimeout(() => { _setLogTimer = null }, 1000)
getLog(data)
},
showFun() {
if( localStorage.getItem('infoVerify') == 8 || localStorage.getItem('infoVerify') == 12 ) {
return false

View File

@@ -154,7 +154,7 @@ export default {
this.isLoading = false
},
initShow(){
this.keyword= '',
this.keyword= ''
this.getNormalList()
}
}

View File

@@ -8,7 +8,7 @@
:border="false"
:fixed="true"
:safe-area-inset-top="true"
@click-left="h5GoBack"
@click-left="back"
/>
</div>
<div class="addContentWrap">
@@ -92,6 +92,57 @@
</template>
</el-input>
</div>
<div class="lineBot" v-if="permissonList?.includes('hasInsuranceAudit')"></div>
<div class="itemContent" v-if="permissonList?.includes('hasInsuranceAudit')" style="align-items: center">
<div class="titleType" style="width: 60px">
<img class="startImg" src="@/assets/start.png" />
<span>保费</span>
</div>
<van-field
type="number"
class="vanIpt"
v-model="liabilityInsuranceAmount"
input-align="right"
>
<template slot="right-icon" >
<span style="white-space: nowrap;"></span>
</template>
</van-field>
</div>
<div class="lineBot" v-if="permissonList?.includes('hasInsuranceAudit')"></div>
<div class="itemContent" v-if="permissonList?.includes('hasInsuranceAudit')">
<div class="titleType">
<img class="startImg" src="@/assets/start.png" />
<span>保额</span>
</div>
<div style="display:flex;align-items: center;justify-content: flex-end">
<el-select
v-model="liabilityInsuranceQuota"
value-key="name"
class="elSelect"
collapse-tags="collapse-tags"
placeholder="请选择" style="width: 55%"
>
<el-option
v-for="item in liabilityQuotaOptions"
:key="item.value"
:label="item.value"
:value="item.value"
>
</el-option>
</el-select><span style="margin-right: 16px;opacity: .5;">万元</span>
</div>
<!-- <van-field
type="number"
class="vanIpt"
v-model="liabilityInsuranceQuota"
input-align="right"
>
<template slot="right-icon" >
<span style="white-space: nowrap;">万元 </span>
</template>
</van-field>-->
</div>
</template>
<common-btn title="保存" @submitClick="submitBtn"/>
<van-calendar v-model="showDatePicker" :min-date="minDate"
@@ -104,7 +155,7 @@
import {Dialog} from "vant";
import {myMixins} from "@/utils/myMixins"
import {formatDate1} from "@/utils/common"
import { uploadImage, updateInsurance, getInfoById} from "@/api/mine"
import { uploadImage, updateInsurance, getInfoById,userOperationPermissions} from "@/api/mine"
import CommonBtn from "@/components/commonBtn.vue"
export default {
name: "vehicleAdd",
@@ -115,6 +166,7 @@ export default {
children: 'children',
label: 'name'
},
liabilityQuotaOptions:[{value:10},{value:20},{value:30},{value:50},{value:70},{value:80},{value:100},{value:200}],
minDate: new Date(1970, 0, 1), // 设置最小可选日期1970年1月1日
maxDate: new Date(2099, 11, 31), // 设置最大可选日期2099年12月31日
showDatePicker: false,
@@ -130,6 +182,9 @@ export default {
insurancePicturePhoto: '', // 保单照片
isMultiple: false, // 是否支持多选
insuranceCorp: '',
liabilityInsuranceAmount:'',
liabilityInsuranceQuota:'',
permissonList:[],
insuranceOptions: [{
name: '太平洋',
value: 1
@@ -183,11 +238,24 @@ export default {
async mounted() {
this.id=this.$route.params?.id
await this.getPermissions()
if( this.id){
// await this.vehicleInfo()
}
},
methods:{
back() {
this.$router.push({
name:'vehicleAdd',
params:{
id: this.id
}
})
},
async getPermissions(){
let res = await userOperationPermissions();
this.permissonList = res.data
},
async vehicleInfo(){
let res= await getInfoById({
vehicleId:this.id
@@ -259,6 +327,14 @@ export default {
this.$toast('保单有效期不能为空')
return
}
if(this.hasLiabilityInsurance == 1 && this.permissonList?.includes('hasInsuranceAudit') && !this.liabilityInsuranceAmount && this.liabilityInsuranceAmount!=0){
this.$toast('保费不能为空')
return
}
if(this.hasLiabilityInsurance == 1 && !this.liabilityInsuranceQuota && this.permissonList?.includes('hasInsuranceAudit')){
this.$toast('保额不能为空')
return
}
let timeObj;
if(this.dateVal) {
timeObj = this.formatDateTimeRange(this.dateVal)
@@ -271,6 +347,8 @@ export default {
insuranceCorp: this.hasLiabilityInsurance == 1 ? this.insuranceCorp : '',
liabilityInsuranceStartTime: this.hasLiabilityInsurance == 1 ? (timeObj?.startTime || '' ) : '',
liabilityInsuranceEndTime: this.hasLiabilityInsurance == 1 ? (timeObj?.endTime || '') : '',
liabilityInsuranceQuota:this.liabilityInsuranceQuota || '',
liabilityInsuranceAmount:this.liabilityInsuranceAmount || '',
})
}
await updateInsurance(params)
@@ -280,7 +358,8 @@ export default {
this.$toast('添加成功')
}
setTimeout(()=>{
this.$router.back();
// this.$router.back();
this.back()
},2000)
}
},

View File

@@ -153,12 +153,17 @@ export default {
if (this.notifyList.length >= this.total) {
this.finished = true;
}
} else {
// 未开票不需要分页,直接标记加载完成
this.loading = false;
this.finished = true;
}
},
async changeTabHandler() {
this.pageNum = 1;
this.notifyList = [];
this.checkList = [];
this.finished = false;
if (this.active == 1) { // 全部, 需要分页
this.status = '';
this.dispatchAppSearchInvoiced = '';

View File

@@ -156,6 +156,7 @@
minorCount: '',
serviceAreaCode: [],
linkEmail:'',
person:'',
accountInfoDTO:{
dutyParagraph:'',
accountNumber:'',
@@ -264,6 +265,14 @@
this.$toast('营业执照未上传')
return
}
if(this.form.person != this.form.legalName){
this.$toast('身份证法人姓名和营业执照法人不一致')
return
}
if( !this.licensePhoto ) {
this.$toast('开户许可证未上传')
return
}
if( !(this.form.serviceAreaCode.length > 0) ) {
this.$toast('服务区域不能为空')
return
@@ -394,6 +403,7 @@
imageUrl: this.idFrontPhoto,
cardSide: 'FRONT'
})
// 身份证法人名称
this.form.legalName = res?.data?.name
},
async companyPhotoHandler(file) {
@@ -416,6 +426,8 @@
this.form.accountInfoDTO.dutyParagraph=res?.data?.regNum
this.form.accountInfoDTO.unitName = res?.data?.name
this.form.accountInfoDTO.companyType=res?.data?.type
// 营业执照法人名称
this.form.person = res?.data?.person
await this.QrCodeHandler();
},
async licensePhotoHandler(file){// 开户许可证

View File

@@ -8,7 +8,7 @@
:border="false"
:fixed="true"
:safe-area-inset-top="true"
@click-left="h5GoBack"
@click-left="back"
/>
</div>
<div class="addContentWrap">
@@ -311,9 +311,83 @@
</template>
</el-input>
</div>
<div class="lineBot" v-if="permissonList?.includes('hasInsuranceAudit')"></div>
<div class="itemContent" v-if="permissonList?.includes('hasInsuranceAudit')">
<div class="titleType">
<img class="startImg" src="@/assets/start.png" />
<span>保费</span>
</div>
<van-field
type="number"
class="vanIpt"
v-model="liabilityInsuranceAmount"
input-align="right"
>
<template slot="right-icon" >
<span style="white-space: nowrap;"></span>
</template>
</van-field>
</div>
<div class="lineBot" v-if="permissonList?.includes('hasInsuranceAudit')"></div>
<div class="itemContent" v-if="permissonList?.includes('hasInsuranceAudit')">
<div class="titleType">
<img class="startImg" src="@/assets/start.png" />
<span>保额</span>
</div>
<div style="display:flex;align-items: center;justify-content: flex-end">
<el-select
v-model="liabilityInsuranceQuota"
value-key="name"
class="elSelect"
collapse-tags="collapse-tags"
placeholder="请选择" style="width: 55%"
>
<el-option
v-for="item in liabilityQuotaOptions"
:key="item.value"
:label="item.value"
:value="item.value"
>
</el-option>
</el-select><span style="margin-right: 16px;opacity: .5;">万元</span>
</div>
<!-- <van-field
type="number"
class="vanIpt"
v-model="liabilityInsuranceQuota"
input-align="right"
>
<template slot="right-icon" >
<span style="white-space: nowrap;">万元 </span>
</template>
</van-field>-->
</div>
<!-- <div class="lineBot"></div>
<div class="itemContent">
<div class="titleType">
<img class="startImg" src="@/assets/start.png" />
<span>保单号(救援)</span>
</div>
<van-field
class="vanIpt"
style="width: 72%"
v-model="insuranceCode"
input-align="right"
> </van-field>
</div>
<div class="lineBot"></div>
<div class="itemContent">
<div class="titleType"> <span>保单号(中道物流)</span> </div>
<van-field
class="vanIpt"
style="width: 65%"
v-model="insuranceCodeZd"
input-align="right"
> </van-field>
</div>
<div class="lineBot"></div>-->
</template>
<div class="itemContent">
<div class="titleType">
<img class="startImg" src="@/assets/start.png" />
@@ -344,7 +418,7 @@
</div>
</div>-->
</div>
<two-common-btn class="btn" @cancelClick="h5GoBack" @submitClick="submitBtn" />
<two-common-btn class="btn" @cancelClick="back" @submitClick="submitBtn" />
<van-calendar v-model="showDatePicker" :min-date="minDate"
:max-date="maxDate" type="range" @confirm="onConfirm" />
@@ -540,6 +614,7 @@ export default {
name: '其他',
value: 14
}],
liabilityQuotaOptions:[{value:10},{value:20},{value:30},{value:50},{value:70},{value:80},{value:100},{value:200}],
approvalForm:{
type:2,
supplierId:'',
@@ -557,7 +632,10 @@ export default {
vehicleInfoChange:false,
insuranceChange:false,
loading: false,
liabilityInsuranceAmount:'',
liabilityInsuranceQuota:'',
insuranceCode:'',
insuranceCodeZd:'',
}
},
computed: {
@@ -952,7 +1030,7 @@ export default {
isVehicleChange(e) {
this.vehicleStatus=e
},
async submitAuditHandle(){//提交审核
/* async submitAuditHandle(){//提交审核
let urls=[]
this.insurancePictureFiles?.forEach(item => urls.push(item.url))
let time =this.dateVal ? this.formatDateTimeRange(this.dateVal) : ''
@@ -1030,7 +1108,7 @@ export default {
this.approvalDialogShow=false
await this.submitBtn();
}
},
},*/
async submitApprovalHandle(){//提交审批-走接口
if(this.vehicleInfoChange){
if(!(this.selectedOption.length > 0)){
@@ -1133,6 +1211,14 @@ export default {
this.vehicleInfoChange=false
this.insuranceChange=false
},
back() {
this.$router.push({
name:'vehicleManage',
params:{
id: this.id
}
})
},
async submitBtn(){
if( !this.vehicleLicenseFront ) {
this.$toast('行驶证主页照片不能为空')
@@ -1194,12 +1280,26 @@ export default {
this.$toast('保单有效期不能为空')
return
}
if( this.hasLiabilityInsurance == 1){
if(this.permissonList.includes('hasInsuranceAudit') && !this.liabilityInsuranceAmount && this.liabilityInsuranceAmount!=0){
this.$toast('保费不能为空')
return
}
if(this.permissonList.includes('hasInsuranceAudit') && !this.liabilityInsuranceQuota){
this.$toast('保额不能为空')
return
}
/* if(!this.insuranceCode){
this.$toast('保单号(救援)不能为空')
return
}*/
}
let timeObj;
if(this.dateVal) {
timeObj = this.formatDateTimeRange(this.dateVal)
}
this.serviceIds = this.$refs.tree.getCheckedKeys(true)
console.log('1122',this.vehicleStatus)
// console.log('1122',this.vehicleStatus)
// return
await saveVehicle({
vehicleId:this.id ? this.id : '',
@@ -1221,7 +1321,11 @@ export default {
liabilityInsuranceEndTime: this.hasLiabilityInsurance == 1 ? (timeObj?.endTime || '') : '',
virtualVehicle: this.virtualVehicle,
canSubmitApproval:true,
vehicleStatus:this.vehicleStatus
vehicleStatus:this.vehicleStatus,
liabilityInsuranceAmount:this.liabilityInsuranceAmount,
liabilityInsuranceQuota:this.liabilityInsuranceQuota,
insuranceCode:this.insuranceCode,
insuranceCodeZd:this.insuranceCodeZd,
})
if(this.id){
this.$toast('修改成功')
@@ -1427,4 +1531,12 @@ export default {
transform: translate(-50%, -50%) rotate(360deg);
}
}
.vanIpt{
width: 80%;
display: flex;
align-items: center;
}
.vanIpt1{
width: 72%;
}
</style>

View File

@@ -1,41 +1,57 @@
<template>
<div class="wrap">
<div class="baseInfo common" :style="{'height':orderDetailInfo.contractParentId == 110 ? '300px' : '240px'}">
<div class="baseInfo common">
<div class="title">基本信息:</div>
<div class="line"></div>
<div class="infoWrap fontColor">
<div class="leftTitle">
<div class="leftItem">工单编号:</div>
<div class="leftItem">合同:</div>
<template v-if="orderDetailInfo.contractParentId == 110">
<div class="leftItem">机构名称:</div>
<div class="leftItem">销售人员:</div>
<div class="leftItem">司机号码:</div>
</template>
<div class="leftItem">结算方式:</div>
<div class="leftItem">客户姓名:</div>
<div class="leftItem">客户电话:</div>
<div class="leftItem">车牌号:</div>
<div class="leftItem">车型品牌:</div>
</div>
<div class="rightContent">
<div class="rightItem" style="display: flex;align-items: center;">
<div class="infoRow">
<span class="leftItem">工单编号:</span>
<span class="rightItem" style="display: flex;align-items: center;">
<span id="copyText">{{orderDetailInfo.orderCode}}</span>
<img @click="copyText" src="@/assets/copy.png" style="width: 35px;height: 15px;margin-left: 10px"/>
</span>
</div>
<div class="infoRow" v-if="!([7,9,11,12].includes(Number(queryType)))">
<span class="leftItem">合同:</span>
<span class="rightItem">{{ orderDetailInfo.contractName }}</span>
</div>
<template v-if="orderDetailInfo.contractParentId == 110">
<div class="infoRow">
<span class="leftItem">机构名称:</span>
<span class="rightItem">{{ orderDetailInfo.organizeName }}</span>
</div>
<div class="rightItem">{{ orderDetailInfo.contractName }}</div>
<template v-if="orderDetailInfo.contractParentId == 110">
<div class="rightItem">{{ orderDetailInfo.organizeName }}</div>
<div class="rightItem">{{ orderDetailInfo.saleName }}</div>
<div class="rightItem">{{ orderDetailInfo.driverPhone ? orderDetailInfo.driverPhone : ' '}}</div>
</template>
<div class="rightItem">{{ orderDetailInfo.contractSettleType?.label }}</div>
<div class="rightItem">{{ orderDetailInfo.userName }}</div>
<div class="rightItem">{{ orderDetailInfo.userPhone }}</div>
<div class="rightItem">{{ orderDetailInfo.plateNumber }}</div>
<!-- <div class="rightItem" >理想智动LXA6500SHEVM理想智动LXA6500SHEVM</div>-->
<div class="rightItem" >{{orderDetailInfo.model}}{{ orderDetailInfo.brand }}</div>
<div class="infoRow">
<span class="leftItem">销售人员:</span>
<span class="rightItem">{{ orderDetailInfo.saleName }}</span>
</div>
<div class="infoRow">
<span class="leftItem">司机号码:</span>
<span class="rightItem">{{ orderDetailInfo.driverPhone ? orderDetailInfo.driverPhone : ' '}}</span>
</div>
</template>
<div class="infoRow">
<span class="leftItem">结算方式:</span>
<span class="rightItem">{{ orderDetailInfo.contractSettleType?.label }}</span>
</div>
<div class="infoRow">
<span class="leftItem">客户姓名:</span>
<span class="rightItem">{{ [7,9,11,12].includes(Number(queryType)) ? maskName(orderDetailInfo.userName) : orderDetailInfo.userName }}</span>
</div>
<div class="infoRow">
<span class="leftItem">客户电话:</span>
<span class="rightItem">{{ maskPhone(orderDetailInfo.userPhone) }}</span>
</div>
<div class="infoRow">
<span class="leftItem">车牌号:</span>
<span class="rightItem">{{ [7,9,11,12].includes(Number(queryType)) ? maskPlate(orderDetailInfo.plateNumber) : orderDetailInfo.plateNumber }}</span>
</div>
<div class="infoRow">
<span class="leftItem">车型品牌:</span>
<span class="rightItem">{{orderDetailInfo.model}}{{ orderDetailInfo.brand }}</span>
</div>
<div class="infoRow" v-if="!([7,9,11,12].includes(Number(queryType)))">
<span class="leftItem">车架号:</span>
<span class="rightItem">{{orderDetailInfo.vinNo}}</span>
</div>
</div>
</div>
@@ -74,9 +90,10 @@
<div class="item">
<span class="leftTitle fontColor">服务师傅:</span><span class="rightContent">{{ orderDetailInfo.driverName }} {{orderDetailInfo.drivePhone ? '/' : ''}} {{orderDetailInfo.drivePhone }}
<span v-if="queryType == 5" class="driverPoiBtn" @click="noMultipleClicks(showMap)">查看司机位置</span>
<span v-if="orderDetailInfo.driverName && orderDetailInfo.proprietary?.code==1" class="driverPoiBtn" @click="noMultipleClicks(createDriverInfo)">生成司机信息</span>
</span>
</div>
<div class="item" v-if="queryType == 9 || queryType ==11 || queryType ==12">
<div class="item" v-if="queryType == 9 || queryType ==11 || queryType ==12 || queryType ==5">
<span class="leftTitle fontColor">工单照片:</span><span class="rightContent">
<span class="driverPoiBtn" @click="checkPhoto">查看照片</span>
</span>
@@ -114,7 +131,7 @@
</template>
<script>
import {myMixins} from '@/utils/myMixins'
import {getOrderDetail,showVehiclePositionInfo, getConfigByCode} from "@/api/order"
import {getOrderDetail,showVehiclePositionInfo, getConfigByCode,getDriverInfo} from "@/api/order"
import minePosition from '@/assets/minePosition.png';
import vehiclePosition from '@/assets/vehiclePosition.png';
import desitationPosition from '@/assets/desitationPosition.png'
@@ -152,7 +169,7 @@ export default {
this.$nextTick(() => {
this.initMap();
});
console.log('queryType', this.queryType)
},
methods:{
async getConfigByCodeHandler() {
@@ -161,6 +178,26 @@ export default {
});
this.carTypeList = res?.data?.userVehicleType
},
async getDriverInfo(){
let result=await getDriverInfo({
driverId:this.orderDetailInfo.driverId
})
if(result.data){
// console.log('--result--',result.data)
let params=`姓名:${this.orderDetailInfo.driverName}\n身份证${result.data.identityCardNumber}\n车牌${this.orderDetailInfo.vehiclePlateNumber}\n手机${this.orderDetailInfo.driverPhone}`
// console.log('params',params)
let data = {"action":"copyToClipboard","params":params}
var u = navigator.userAgent;
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if(isiOS){
window.webkit.messageHandlers.nativeObject.postMessage(data);
}else {
window.android.copyToClipboard(params);
}
}else {
this.$toast('未获取到司机信息')
}
},
async getDetail(){
let result=await getOrderDetail({
queryType:this.queryType,
@@ -176,6 +213,9 @@ export default {
this.showPopup = true;
this.mapMarkers();
},
async createDriverInfo(){//生成司机信息
await this.getDriverInfo()
},
checkPhoto(){
let isAllowImage = this.queryType == 9 ? 0 : 1
let data = {
@@ -238,6 +278,21 @@ export default {
this.map.add(marker2);
this.map.setFitView([marker,marker1,marker2])
},
maskName(name) {
if (!name) return '';
return name.slice(0, 1) + '*'.repeat(name.length - 1);
},
maskPhone(phone) {
if (!phone) return '';
const str = String(phone);
if (str.length <= 7) return str;
return str.slice(0, 3) + '*'.repeat(str.length - 7) + str.slice(-4);
},
maskPlate(plate) {
if (!plate) return '';
if (plate.length <= 2) return plate;
return plate.slice(0, 1) + '*'.repeat(plate.length - 2) + plate.slice(-1);
},
async getDriverPoi(){
let res=await showVehiclePositionInfo({
userOrderId:this.userOrderId,
@@ -294,21 +349,25 @@ export default {
}
.baseInfo{
width: 100%;
//@include wh(100%,260px);
margin-bottom: 12px;
.infoWrap{
display: flex;
.leftTitle{
margin-left: 5px;
margin-right: 6px;
@include wh(60px,189px);
opacity: .5;
}
.rightContent{
height: 189px;
width: calc(100% - 60px);
.infoRow{
display: flex;
align-items: center;
min-height: 24px;
.leftItem{
width: 60px;
flex-shrink: 0;
margin-left: 5px;
margin-right: 6px;
opacity: .5;
}
.rightItem{
height: 24px;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}

View File

@@ -263,6 +263,7 @@ import {
getDriverName,getDriverStatisticsKpi,
getRecentSupplierKpi,
} from "@/api/kpi.js"
import { getUserBO } from "@/api/order"
// querySupplierDriverStatisticsScore
import {myMixins} from "@/utils/myMixins"
import CircleChar from "@/views/kpi/components/circleChar.vue";
@@ -330,6 +331,10 @@ export default {
showScoreChart:true,
continueMonthKpi:[],
isBtn:false,//是否有信息变更申请按钮权限
source: 'App',
currentSupplierId: '',
userId: '',
enterTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
}
},
created() {
@@ -338,13 +343,41 @@ export default {
this.isZd = urlParams?.get('isZd') || ''
this.supplierId = urlParams?.get('supplierId') || ''
this.isBtn= Number(urlParams?.get('isBtn'))
this.source = urlParams?.get('source') || 'App'
},
async mounted() {
await this.checkMobile();
await this.initDate();
await this.selectSupplierNameHandle();
await this.getUserInfo();
document.addEventListener('visibilitychange', async ( ) => {
let state = document.visibilityState
if (state == 'hidden') { // 用户离开了
if( this.source == 'App' ) {
this.setLogHandler({
supplierId: this.currentSupplierId, // 服务商 id
userId: this.userId, // userId
source: '服务商KPI',
event: this.source, // 区分 App 还是 system
openTime: this.enterTime, // log 时间,其中 阅读时长是由 enter 和 leave 的时间计算而来
leaveTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
});
}
}
if (state == 'visible') {
this.enterTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
}
});
},
methods: {
async getUserInfo() {
let res = await getUserBO();
this.userId = res.data.id;
this.currentSupplierId = res.data.supplierId
console.log('getUserBO', res)
},
applicateHandle() {
if (window.parent) {
const hasListener = window.parent.dispatchEvent(new Event('checkCloseDialog'));
@@ -1147,8 +1180,8 @@ export default {
{label: '服务车辆', prop: 'vehicleName'},
{label: '服务完成状况', prop: 'orderStatusString'},
{label: '案件完成时间', prop: 'finishTime'},
{label: '省(B)', prop: 'bProvince'},
{label: '市(B)', prop: 'bCity'},
{label: '省(B)', prop: 'bprovince'},
{label: '市(B)', prop: 'bcity'},
{label: '区(B)', prop: 'area'},
]
} else if (this.active === 6) {//投诉明细

View File

@@ -13,23 +13,20 @@
</div>
<div class="contentWrap">
<div>
为降低日常救援工作中的不可预期的车损赔付带来的运营风险和资金压力减少由此衍生而来的可能投诉顺应行业服务标准不断增长的局势中道救援自有车辆已全部投保了救援职业责任险
为降低日常救援工作中的不可预期的车损赔付带来的运营风险和资金压力减少由此衍生而来的投诉顺应行业服务标准不断增长的局势中道救援自有车辆已全部投保了救援职业责任险
</div>
<div>
通过日常的交流了解此险种对于服务商而言投保相对较很多服务商在无投保渠道的情况下选择了对于我们救援场景保障能力稍弱不太匹配的货物险从而从形成了现在很多救援车无保障或者特殊场景货物险理赔难的局面
</div>
<div>
为此中道救援经过与保司沟通协调特为与中道救援合作紧密的服务商提供救援职业责任险参保渠道提升服务商服务能力降低运营风险实现共同进步
通过交流了解我们的合作服务商日常运营中会遇到责任险或者货物险的投保难理赔难的问题为此我们与保司沟通协调特为与中道救援合作紧密的服务商提供救援职业责任险参保渠道解决大家的实际困难实现共同进步
</div>
<div>救援职业责任险简介</div>
<div> 1综合保额100万元其中救援责任50万元物流责任50万元可全方位覆盖我们日常的经营活动</div>
<div> 1保额有50万和100万两套方案可选</div>
<div> 2保费支付可采用救援服务费抵扣的方式降低资金压力</div>
<div> 3详细保险条款保费和其他问题如需了解请与辖区区域经理联系</div>
<div> 其他意见建议如需交流请与18621558505曲仁杰联系</div>
<div> 确认参保请点击下方参保按钮会有专人与贵司联系</div>
<div> 3其他详情如需了解请与辖区区域经理联系</div>
<div> 如有好的建议需要交流请与18621558505曲仁杰联系</div>
<div> 有参保需要请点击下方参保按钮我们会与您联系</div>
</div>
<div class="upload_btn_wrap">
<div class="btn_save" :style="{'backgroundColor':used ? '#cccccc' : '#354D93'}" @click="showPoup = true">参保</div>
<div class="btn_save" :style="{'backgroundColor':used ? '#cccccc' : '#354D93'}" @click="showPoup = true">我想咨询</div>
</div>
<div class="poupCommon" v-if="showPoup">
<div class="showPoupContainer">
@@ -37,12 +34,10 @@
<img class="insure" src="@/assets/insured.png">
<div class="con">
<template v-if="used">
<div class="title">您已成功申请参保请等待</div>
<div class="title">专人与贵司联系</div>
<div class="title">咨询已收到我们会与您联系</div>
</template>
<template v-else>
<div class="title">请确认</div>
<div class="title">是否参保救援职业责任险</div>
<div class="title">请确认咨询</div>
</template>
<div class="btnWrap">
<div v-if="used" class="btn confirmBtn" @click="showPoup = false">确认</div>

View File

@@ -121,7 +121,7 @@ export default {
let flag=this.validatePhone(val)
// console.log('flag',flag)
if(!flag){
this.$toast('手机号格式不正确')
this.$toast('电话号码格式不正确')
}
},
validatePhone(val) {
@@ -129,13 +129,22 @@ export default {
if(!val){
return true
}
const purePhone = val
// 情况111位且1开头 → 合法
if (/^1[0-9]{10}$/.test(purePhone)) {
const purePhone = String(val).trim()
const mobileReg = /^1[3-9]\d{9}$/ // 大陆手机号正则表达式
const hkMobileReg = /^[569]\d{3}[\s-]?\d{4}$/ // 香港手机号正则表达式,允许使用空格或 "-" 分隔
const macauMobileReg = /^6\d{3}[\s-]?\d{4}$/ // 澳门手机号正则表达式,允许使用空格或 "-" 分隔
const telReg = /^(0\d{2,3})([\s-])?\d{7,8}$/ // 大陆座机号正则表达式,允许区号和座机号用空格或 "-" 分开
const hkTelReg = /^\(?\d{2,4}\)?[\s-]?\d{4}[\s-]?\d{4}$/ // 香港座机号正则表达式,允许使用空格或 "-" 分隔
const macauTelReg = /^\(?\d{2,4}\)?[\s-]?\d{4}[\s-]?\d{4}$/ // 澳门座机号正则表达式,允许使用空格或 "-" 分隔
const phone400Reg = /^400[\s-]?\d{3}[\s-]?\d{4}$/ // 以 "400" 开头的号码正则表达式,允许使用空格或 "-" 分隔
// 情况112位且首位是0、第二位是1 → 去0后按大陆手机号校验
if (/^01[0-9]{10}$/.test(purePhone)) {
return true
}
// 情况212位且首位是0、第二位是1 → 去0后合法
if (/^01[0-9]{10}$/.test(purePhone)) {
// 匹配任意一种格式即为合法
if (mobileReg.test(purePhone) || hkMobileReg.test(purePhone) || macauMobileReg.test(purePhone) ||
telReg.test(purePhone) || hkTelReg.test(purePhone) || macauTelReg.test(purePhone) ||
phone400Reg.test(purePhone)) {
return true
}
// 其他情况 → 不合法
@@ -226,6 +235,7 @@ export default {
console.log('phone1Flag',phone1Flag)
console.log('phone2Flag',phone2Flag)
if(!phone1Flag || !phone2Flag){
this.$toast('电话号码格式不正确')
return
}
await submitConfirm({supplierId:this.supplierId,infos:this.personList})

View File

@@ -478,6 +478,21 @@ export default {
otherPhoto:this.otherImgSrc?.join(',')
})
this.clearStorageFormInfo()
if(res.code == 200 && !res.msg){
this.$toast('发布成功')
if(this.isWebFunc()){
setTimeout(()=>{
this.closeParentDialog()
},1000)
}else{
setTimeout(()=>{
this.$router.push({ name: "mineRelease"})
sessionStorage.setItem('mineActiveTab',String(1) )
},1000)
}
}else{
this.$toast(res.msg)
}
console.log("车源发布publishCarInfo",res)
} catch (e){
console.log('e',e)

View File

@@ -16,7 +16,7 @@
<img class="mine" src="@/assets/secondHandCar/mine.png" @click="goMine" />
<el-input
@blur="getList"
placeholder="请输入"
placeholder="牌照|车辆类型|落板|排放|品牌|描述|底座|刹车|自营"
v-model.trim="topSearch">
<img slot="suffix" class="search" src="@/assets/secondHandCar/search.png"/>
</el-input>
@@ -99,6 +99,11 @@
></i>
</template>
</el-input>
<div class="customSel wantSourceSel" @click.stop="toggleWantSource">
<img v-if="wantSource === 1" class="checkIcon" src="@/assets/secondHandCar/checked.png" />
<img v-else class="checkIcon" src="@/assets/secondHandCar/uncheck.png" />
<span :class="{'has-price': wantSource === 1}">想要的车源</span>
</div>
</div>
<div class="contentWrap" v-show="!show">
<van-pull-refresh v-model="isLoading" @refresh="onRefresh" style="min-height:85vh">
@@ -223,6 +228,7 @@ export default {
showDatePicker: false,
areaShow:false,
isClearing:false,
wantSource: 0,
minDate: new Date(1970, 0, 1), // 设置最小可选日期1970年1月1日
maxDate: new Date(2099, 11, 31) // 设置最大可选日期2099年12月31日
}
@@ -267,6 +273,10 @@ export default {
this.setSearchVal();
this.getList()
},
wantSource(){
this.setSearchVal();
this.getList()
},
},
mounted() {
this.getSearchVal();
@@ -281,6 +291,9 @@ export default {
});
},
methods:{
toggleWantSource(){
this.wantSource = this.wantSource === 1 ? 0 : 1;
},
confirmHandle(val){
if(val[0].name.includes('市')){
this.areaName=val[0].name
@@ -356,6 +369,7 @@ export default {
sessionStorage.setItem('dateVal',this.dateVal);
sessionStorage.setItem('brandModel',this.brandModel);
sessionStorage.setItem('underpanBrand',this.underpanBrand);
sessionStorage.setItem('wantSource',String(this.wantSource));
},
getSearchVal(){
this.activeTab = Number(sessionStorage.getItem('indexActiveTab')) || 0;
@@ -371,6 +385,7 @@ export default {
this.dateVal=sessionStorage.getItem('dateVal') || '';
this.brandModel=sessionStorage.getItem('brandModel') || '';
this.underpanBrand=sessionStorage.getItem('underpanBrand') || '';
this.wantSource=Number(sessionStorage.getItem('wantSource')) || 0;
},
goMine(){//我的发布
this.$router.push({ name: "mineRelease"})
@@ -434,6 +449,7 @@ export default {
endTime:this.endTime,
brandModel:this.brandModel,
underpanBrand:this.underpanBrand,
wantSource:this.wantSource,
})
this.total=res.total
if(this.pageNum == 1){// 第一页直接赋值
@@ -526,6 +542,9 @@ export default {
border-radius: 20px;
border: 2px solid #264B94;
}
::v-deep .el-input__inner::placeholder{
font-size: 10px;
}
::v-deep .el-input__suffix{
top: 12px;
right: 10px;
@@ -622,6 +641,22 @@ export default {
.has-price{
color: #007BE9 !important;
}
.wantSourceSel{
display: flex;
align-items: center;
justify-content: center;
gap: 3px;
width: 68px;
cursor: pointer;
.checkIcon{
width: 13px;
height: 13px;
}
span{
font-size: 10px;
color: #323233;
}
}
}
.contentWrap{
width: 100%;