wenhongquan 6 months ago
parent
commit
b4df090342

+ 1 - 1
.env.development

@@ -1,4 +1,4 @@
 NODE_ENV = "env"
 NODE_ENV = "env"
 VITE_NODE_ENV = "env"	
 VITE_NODE_ENV = "env"	
-VITE_BASE_URL = "https://khy.xiaole.vip/api"
+VITE_BASE_URL = "http://127.0.0.1:8080"
 
 

+ 4 - 0
components.d.ts

@@ -33,6 +33,9 @@ declare module 'vue' {
     ElOption: typeof import('element-plus/es')['ElOption']
     ElOption: typeof import('element-plus/es')['ElOption']
     ElPagination: typeof import('element-plus/es')['ElPagination']
     ElPagination: typeof import('element-plus/es')['ElPagination']
     ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
     ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
+    ElRadio: typeof import('element-plus/es')['ElRadio']
+    ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
+    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElSelect: typeof import('element-plus/es')['ElSelect']
     ElSelect: typeof import('element-plus/es')['ElSelect']
     ElSwitch: typeof import('element-plus/es')['ElSwitch']
     ElSwitch: typeof import('element-plus/es')['ElSwitch']
@@ -40,6 +43,7 @@ declare module 'vue' {
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
     ElTabPane: typeof import('element-plus/es')['ElTabPane']
     ElTabPane: typeof import('element-plus/es')['ElTabPane']
     ElTabs: typeof import('element-plus/es')['ElTabs']
     ElTabs: typeof import('element-plus/es')['ElTabs']
+    ElTag: typeof import('element-plus/es')['ElTag']
     ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
     ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
     ElUpload: typeof import('element-plus/es')['ElUpload']
     ElUpload: typeof import('element-plus/es')['ElUpload']
     HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
     HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']

+ 2 - 2
public/js/global.js

@@ -1,10 +1,10 @@
 var baseUrl='https://khy.xiaole.vip'
 var baseUrl='https://khy.xiaole.vip'
 var loginPageUrl='/login'
 var loginPageUrl='/login'
-var systemType='测试环境'
+var systemType = '线上环境'
 
 
 switch(systemType){
 switch(systemType){
     case '测试环境':
     case '测试环境':
-        baseUrl='https://khy.xiaole.vip'
+        baseUrl='http://127.0.0.1:8080'
         loginPageUrl='/login'
         loginPageUrl='/login'
         break;
         break;
     case '线上环境':
     case '线上环境':

+ 426 - 0
src/request/api.js

@@ -1,5 +1,6 @@
 import service from './index.ts'
 import service from './index.ts'
 
 
+// @ts-ignore
 export const  login = query => {
 export const  login = query => {
     return service({
     return service({
         url: '/api/auth/login',
         url: '/api/auth/login',
@@ -8,6 +9,7 @@ export const  login = query => {
     });
     });
 };
 };
 
 
+// @ts-ignore
 export const  apiauthlogout = query => {
 export const  apiauthlogout = query => {
     return service({
     return service({
         url: '/api/auth/logout',
         url: '/api/auth/logout',
@@ -34,6 +36,7 @@ export const  apiauthlogout = query => {
 
 
 //https://khy.xiaole.vip/api/system/commonOther/static统计-订单数量
 //https://khy.xiaole.vip/api/system/commonOther/static统计-订单数量
 
 
+// @ts-ignore
 export const  apisystemcommonOtherstatic = query => {
 export const  apisystemcommonOtherstatic = query => {
     return service({
     return service({
         url: '/api/system/commonOther/static',
         url: '/api/system/commonOther/static',
@@ -44,6 +47,7 @@ export const  apisystemcommonOtherstatic = query => {
 
 
 //https://khy.xiaole.vip/api/system/dzbcArea/list查询定制班车-区域列表
 //https://khy.xiaole.vip/api/system/dzbcArea/list查询定制班车-区域列表
 
 
+// @ts-ignore
 export const  apisystemdzbcArealist = query => {
 export const  apisystemdzbcArealist = query => {
     return service({
     return service({
         url: '/api/system/dzbcArea/list',
         url: '/api/system/dzbcArea/list',
@@ -53,6 +57,7 @@ export const  apisystemdzbcArealist = query => {
 };
 };
 
 
 //https://khy.xiaole.vip/api/system/dzbcArea/export导出定制班车-区域列表
 //https://khy.xiaole.vip/api/system/dzbcArea/export导出定制班车-区域列表
+// @ts-ignore
 export const  apisystemdzbcAreaexport = query => {
 export const  apisystemdzbcAreaexport = query => {
     return service({
     return service({
         url: '/api/system/dzbcArea/export',
         url: '/api/system/dzbcArea/export',
@@ -63,6 +68,7 @@ export const  apisystemdzbcAreaexport = query => {
 };
 };
 
 
 ///api/system/dzbcArea/{ids}删除定制班车-区域
 ///api/system/dzbcArea/{ids}删除定制班车-区域
+// @ts-ignore
 export const  apisystemdzbcAreaDel = query => {
 export const  apisystemdzbcAreaDel = query => {
     return service({
     return service({
         url: `/api/system/dzbcArea/${query.id}`,
         url: `/api/system/dzbcArea/${query.id}`,
@@ -70,6 +76,7 @@ export const  apisystemdzbcAreaDel = query => {
     });
     });
 };
 };
 //新增定制班车-区域https://khy.xiaole.vip/api/system/dzbcArea
 //新增定制班车-区域https://khy.xiaole.vip/api/system/dzbcArea
+// @ts-ignore
 export const  apisystemdzbcAreaAdd = query => {
 export const  apisystemdzbcAreaAdd = query => {
     return service({
     return service({
         url: `/api/system/dzbcArea`,
         url: `/api/system/dzbcArea`,
@@ -78,6 +85,7 @@ export const  apisystemdzbcAreaAdd = query => {
     });
     });
 };
 };
 //https://khy.xiaole.vip/api/system/dzbcArea修改定制班车-区域
 //https://khy.xiaole.vip/api/system/dzbcArea修改定制班车-区域
+// @ts-ignore
 export const  apisystemdzbcAreaUpdate = query => {
 export const  apisystemdzbcAreaUpdate = query => {
     return service({
     return service({
         url: `/api/system/dzbcArea`,
         url: `/api/system/dzbcArea`,
@@ -92,6 +100,7 @@ export const  apisystemdzbcAreaUpdate = query => {
 
 
 //查询定制班车-站点列表https://khy.xiaole.vip/api/system/dzbcSite/list
 //查询定制班车-站点列表https://khy.xiaole.vip/api/system/dzbcSite/list
 
 
+// @ts-ignore
 export const  apisystemdzbcSitelist = query => {
 export const  apisystemdzbcSitelist = query => {
     return service({
     return service({
         url: '/api/system/dzbcSite/list',
         url: '/api/system/dzbcSite/list',
@@ -101,6 +110,7 @@ export const  apisystemdzbcSitelist = query => {
 };
 };
 
 
 //导出定制班车-站点列表https://khy.xiaole.vip/api/system/dzbcSite/export
 //导出定制班车-站点列表https://khy.xiaole.vip/api/system/dzbcSite/export
+// @ts-ignore
 export const  apisystemdzbcSiteexport = query => {
 export const  apisystemdzbcSiteexport = query => {
     return service({
     return service({
         url: '/api/system/dzbcSite/export',
         url: '/api/system/dzbcSite/export',
@@ -111,6 +121,7 @@ export const  apisystemdzbcSiteexport = query => {
 };
 };
 
 
 //删除定制班车-站点https://khy.xiaole.vip/api/system/dzbcSite/{ids}
 //删除定制班车-站点https://khy.xiaole.vip/api/system/dzbcSite/{ids}
+// @ts-ignore
 export const  apisystemdzbcSiteDel = query => {
 export const  apisystemdzbcSiteDel = query => {
     return service({
     return service({
         url: `/api/system/dzbcSite/${query.id}`,
         url: `/api/system/dzbcSite/${query.id}`,
@@ -118,6 +129,7 @@ export const  apisystemdzbcSiteDel = query => {
     });
     });
 };
 };
 //新增定制班车-站点https://khy.xiaole.vip/api/system/dzbcSite
 //新增定制班车-站点https://khy.xiaole.vip/api/system/dzbcSite
+// @ts-ignore
 export const  apisystemdzbcSiteAdd = query => {
 export const  apisystemdzbcSiteAdd = query => {
     return service({
     return service({
         url: `/api/system/dzbcSite`,
         url: `/api/system/dzbcSite`,
@@ -126,6 +138,7 @@ export const  apisystemdzbcSiteAdd = query => {
     });
     });
 };
 };
 //修改定制班车-站点https://khy.xiaole.vip/api/system/dzbcSite
 //修改定制班车-站点https://khy.xiaole.vip/api/system/dzbcSite
+// @ts-ignore
 export const  apisystemdzbcSiteUpdate = query => {
 export const  apisystemdzbcSiteUpdate = query => {
     return service({
     return service({
         url: `/api/system/dzbcSite`,
         url: `/api/system/dzbcSite`,
@@ -140,6 +153,7 @@ export const  apisystemdzbcSiteUpdate = query => {
 
 
 //查询定制班车-车辆列表https://khy.xiaole.vip/api/system/dzbcCar/list
 //查询定制班车-车辆列表https://khy.xiaole.vip/api/system/dzbcCar/list
 
 
+// @ts-ignore
 export const  apisystemdzbcCarlist = query => {
 export const  apisystemdzbcCarlist = query => {
     return service({
     return service({
         url: '/api/system/dzbcCar/list',
         url: '/api/system/dzbcCar/list',
@@ -149,6 +163,7 @@ export const  apisystemdzbcCarlist = query => {
 };
 };
 
 
 //导出定制班车-车辆列表https://khy.xiaole.vip/api/system/dzbcCar/export
 //导出定制班车-车辆列表https://khy.xiaole.vip/api/system/dzbcCar/export
+// @ts-ignore
 export const  apisystemdzbcCarexport = query => {
 export const  apisystemdzbcCarexport = query => {
     return service({
     return service({
         url: '/api/system/dzbcCar/export',
         url: '/api/system/dzbcCar/export',
@@ -159,6 +174,7 @@ export const  apisystemdzbcCarexport = query => {
 };
 };
 
 
 //删除定制班车-车辆https://khy.xiaole.vip/api/system/dzbcCar/{ids}
 //删除定制班车-车辆https://khy.xiaole.vip/api/system/dzbcCar/{ids}
+// @ts-ignore
 export const  apisystemdzbcCarDel = query => {
 export const  apisystemdzbcCarDel = query => {
     return service({
     return service({
         url: `/api/system/dzbcCar/${query.id}`,
         url: `/api/system/dzbcCar/${query.id}`,
@@ -166,6 +182,7 @@ export const  apisystemdzbcCarDel = query => {
     });
     });
 };
 };
 //新增定制班车-车辆https://khy.xiaole.vip/api/system/dzbcCar
 //新增定制班车-车辆https://khy.xiaole.vip/api/system/dzbcCar
+// @ts-ignore
 export const  apisystemdzbcCarAdd = query => {
 export const  apisystemdzbcCarAdd = query => {
     return service({
     return service({
         url: `/api/system/dzbcCar`,
         url: `/api/system/dzbcCar`,
@@ -174,6 +191,7 @@ export const  apisystemdzbcCarAdd = query => {
     });
     });
 };
 };
 //修改定制班车-车辆https://khy.xiaole.vip/api/system/dzbcCar
 //修改定制班车-车辆https://khy.xiaole.vip/api/system/dzbcCar
+// @ts-ignore
 export const  apisystemdzbcCarUpdate = query => {
 export const  apisystemdzbcCarUpdate = query => {
     return service({
     return service({
         url: `/api/system/dzbcCar`,
         url: `/api/system/dzbcCar`,
@@ -187,6 +205,7 @@ export const  apisystemdzbcCarUpdate = query => {
 
 
 //查询定制班车-路线列表https://khy.xiaole.vip/api/system/dzbcPath/list
 //查询定制班车-路线列表https://khy.xiaole.vip/api/system/dzbcPath/list
 
 
+// @ts-ignore
 export const  apisystemdzbcPathlist = query => {
 export const  apisystemdzbcPathlist = query => {
     return service({
     return service({
         url: '/api/system/dzbcPath/list',
         url: '/api/system/dzbcPath/list',
@@ -196,6 +215,7 @@ export const  apisystemdzbcPathlist = query => {
 };
 };
 
 
 //导出定制班车-路线列表https://khy.xiaole.vip/api/system/dzbcPath/export
 //导出定制班车-路线列表https://khy.xiaole.vip/api/system/dzbcPath/export
+// @ts-ignore
 export const  apisystemdzbcPathexport = query => {
 export const  apisystemdzbcPathexport = query => {
     return service({
     return service({
         url: '/api/system/dzbcPath/export',
         url: '/api/system/dzbcPath/export',
@@ -206,6 +226,7 @@ export const  apisystemdzbcPathexport = query => {
 };
 };
 
 
 //删除定制班车-路线https://khy.xiaole.vip/api/system/dzbcPath/{ids}
 //删除定制班车-路线https://khy.xiaole.vip/api/system/dzbcPath/{ids}
+// @ts-ignore
 export const  apisystemdzbcPathDel = query => {
 export const  apisystemdzbcPathDel = query => {
     return service({
     return service({
         url: `/api/system/dzbcPath/${query.id}`,
         url: `/api/system/dzbcPath/${query.id}`,
@@ -213,6 +234,7 @@ export const  apisystemdzbcPathDel = query => {
     });
     });
 };
 };
 //新增定制班车-路线https://khy.xiaole.vip/api/system/dzbcPath
 //新增定制班车-路线https://khy.xiaole.vip/api/system/dzbcPath
+// @ts-ignore
 export const  apisystemdzbcPathAdd = query => {
 export const  apisystemdzbcPathAdd = query => {
     return service({
     return service({
         url: `/api/system/dzbcPath`,
         url: `/api/system/dzbcPath`,
@@ -221,6 +243,7 @@ export const  apisystemdzbcPathAdd = query => {
     });
     });
 };
 };
 //修改定制班车-路线https://khy.xiaole.vip/api/system/dzbcPath
 //修改定制班车-路线https://khy.xiaole.vip/api/system/dzbcPath
+// @ts-ignore
 export const apisystemdzbcPathUpdate = query => {
 export const apisystemdzbcPathUpdate = query => {
     return service({
     return service({
         url: `/api/system/dzbcPath`,
         url: `/api/system/dzbcPath`,
@@ -233,6 +256,7 @@ export const apisystemdzbcPathUpdate = query => {
 
 
 //查询定制班车-订单列表https://khy.xiaole.vip/api/system/dzbcOrder/list
 //查询定制班车-订单列表https://khy.xiaole.vip/api/system/dzbcOrder/list
 
 
+// @ts-ignore
 export const  apisystemdzbcOrderlist = query => {
 export const  apisystemdzbcOrderlist = query => {
     return service({
     return service({
         url: '/api/system/dzbcOrder/list',
         url: '/api/system/dzbcOrder/list',
@@ -242,6 +266,7 @@ export const  apisystemdzbcOrderlist = query => {
 };
 };
 
 
 //导出定制班车-订单列表https://khy.xiaole.vip/api/system/dzbcOrder/export
 //导出定制班车-订单列表https://khy.xiaole.vip/api/system/dzbcOrder/export
+// @ts-ignore
 export const  apisystemdzbcOrderexport = query => {
 export const  apisystemdzbcOrderexport = query => {
     return service({
     return service({
         url: '/api/system/dzbcOrder/export',
         url: '/api/system/dzbcOrder/export',
@@ -252,6 +277,7 @@ export const  apisystemdzbcOrderexport = query => {
 };
 };
 
 
 //删除定制班车-订单https://khy.xiaole.vip/api/system/dzbcOrder/{ids}
 //删除定制班车-订单https://khy.xiaole.vip/api/system/dzbcOrder/{ids}
+// @ts-ignore
 export const  apisystemdzbcOrderDel = query => {
 export const  apisystemdzbcOrderDel = query => {
     return service({
     return service({
         url: `/api/system/dzbcOrder/${query.id}`,
         url: `/api/system/dzbcOrder/${query.id}`,
@@ -260,6 +286,7 @@ export const  apisystemdzbcOrderDel = query => {
 };
 };
 
 
 //修改定制班车-订单https://khy.xiaole.vip/api/system/dzbcOrder
 //修改定制班车-订单https://khy.xiaole.vip/api/system/dzbcOrder
+// @ts-ignore
 export const apisystemdzbcOrderUpdate = query => {
 export const apisystemdzbcOrderUpdate = query => {
     return service({
     return service({
         url: `/api/system/dzbcOrder`,
         url: `/api/system/dzbcOrder`,
@@ -272,6 +299,7 @@ export const apisystemdzbcOrderUpdate = query => {
 
 
 //查询定制班车-客运公司列表https://khy.xiaole.vip/api/system/dzbcKyz/list
 //查询定制班车-客运公司列表https://khy.xiaole.vip/api/system/dzbcKyz/list
 
 
+// @ts-ignore
 export const  apisystemdzbcKyzlist = query => {
 export const  apisystemdzbcKyzlist = query => {
     return service({
     return service({
         url: '/api/system/dzbcKyz/list',
         url: '/api/system/dzbcKyz/list',
@@ -281,6 +309,7 @@ export const  apisystemdzbcKyzlist = query => {
 };
 };
 
 
 //导出定制班车-客运公司列表https://khy.xiaole.vip/api/system/dzbcKyz/export
 //导出定制班车-客运公司列表https://khy.xiaole.vip/api/system/dzbcKyz/export
+// @ts-ignore
 export const  apisystemdzbcKyzexport = query => {
 export const  apisystemdzbcKyzexport = query => {
     return service({
     return service({
         url: '/api/system/dzbcKyz/export',
         url: '/api/system/dzbcKyz/export',
@@ -291,6 +320,7 @@ export const  apisystemdzbcKyzexport = query => {
 };
 };
 
 
 //新增定制班车-客运公司https://khy.xiaole.vip/api/system/dzbcKyz
 //新增定制班车-客运公司https://khy.xiaole.vip/api/system/dzbcKyz
+// @ts-ignore
 export const  apisystemdzbcKyzAdd = query => {
 export const  apisystemdzbcKyzAdd = query => {
     return service({
     return service({
         url: `/api/system/dzbcKyz`,
         url: `/api/system/dzbcKyz`,
@@ -300,6 +330,7 @@ export const  apisystemdzbcKyzAdd = query => {
 };
 };
 
 
 //删除定制班车-客运公司https://khy.xiaole.vip/api/system/dzbcKyz/{ids}
 //删除定制班车-客运公司https://khy.xiaole.vip/api/system/dzbcKyz/{ids}
+// @ts-ignore
 export const  apisystemdzbcKyzDel = query => {
 export const  apisystemdzbcKyzDel = query => {
     return service({
     return service({
         url: `/api/system/dzbcKyz/${query.id}`,
         url: `/api/system/dzbcKyz/${query.id}`,
@@ -308,6 +339,7 @@ export const  apisystemdzbcKyzDel = query => {
 };
 };
 
 
 //修改定制班车-客运公司https://khy.xiaole.vip/api/system/dzbcKyz
 //修改定制班车-客运公司https://khy.xiaole.vip/api/system/dzbcKyz
+// @ts-ignore
 export const apisystemdzbcKyzUpdate = query => {
 export const apisystemdzbcKyzUpdate = query => {
     return service({
     return service({
         url: `/api/system/dzbcKyz`,
         url: `/api/system/dzbcKyz`,
@@ -320,6 +352,7 @@ export const apisystemdzbcKyzUpdate = query => {
 
 
 //查询定制班车-小程序banner列表https://khy.xiaole.vip/api/system/dzbcBanner/list
 //查询定制班车-小程序banner列表https://khy.xiaole.vip/api/system/dzbcBanner/list
 
 
+// @ts-ignore
 export const  apisystemdzbcBannerlist = query => {
 export const  apisystemdzbcBannerlist = query => {
     return service({
     return service({
         url: '/api/system/dzbcBanner/list',
         url: '/api/system/dzbcBanner/list',
@@ -329,6 +362,7 @@ export const  apisystemdzbcBannerlist = query => {
 };
 };
 
 
 //导出定制班车-小程序banner列表https://khy.xiaole.vip/api/system/dzbcBanner/export
 //导出定制班车-小程序banner列表https://khy.xiaole.vip/api/system/dzbcBanner/export
+// @ts-ignore
 export const  apisystemdzbcBannerexport = query => {
 export const  apisystemdzbcBannerexport = query => {
     return service({
     return service({
         url: '/api/system/dzbcBanner/export',
         url: '/api/system/dzbcBanner/export',
@@ -339,6 +373,7 @@ export const  apisystemdzbcBannerexport = query => {
 };
 };
 
 
 //新增定制班车-小程序https://khy.xiaole.vip/api/system/dzbcBanner
 //新增定制班车-小程序https://khy.xiaole.vip/api/system/dzbcBanner
+// @ts-ignore
 export const  apisystemdzbcBannerAdd = query => {
 export const  apisystemdzbcBannerAdd = query => {
     return service({
     return service({
         url: `/api/system/dzbcBanner`,
         url: `/api/system/dzbcBanner`,
@@ -348,6 +383,7 @@ export const  apisystemdzbcBannerAdd = query => {
 };
 };
 
 
 //删除定制班车-小程序bannerhttps://khy.xiaole.vip/api/system/dzbcBanner/{ids}
 //删除定制班车-小程序bannerhttps://khy.xiaole.vip/api/system/dzbcBanner/{ids}
+// @ts-ignore
 export const  apisystemdzbcBannerDel = query => {
 export const  apisystemdzbcBannerDel = query => {
     return service({
     return service({
         url: `/api/system/dzbcBanner/${query.id}`,
         url: `/api/system/dzbcBanner/${query.id}`,
@@ -356,6 +392,7 @@ export const  apisystemdzbcBannerDel = query => {
 };
 };
 
 
 //修改定制班车-小程序bannerhttps://khy.xiaole.vip/api/system/dzbcBanner
 //修改定制班车-小程序bannerhttps://khy.xiaole.vip/api/system/dzbcBanner
+// @ts-ignore
 export const apisystemdzbcBannerUpdate = query => {
 export const apisystemdzbcBannerUpdate = query => {
     return service({
     return service({
         url: `/api/system/dzbcBanner`,
         url: `/api/system/dzbcBanner`,
@@ -370,6 +407,7 @@ export const apisystemdzbcBannerUpdate = query => {
 
 
 //查询定制班车-路线排班列表https://khy.xiaole.vip/api/system/dzbcPathScheduling/list
 //查询定制班车-路线排班列表https://khy.xiaole.vip/api/system/dzbcPathScheduling/list
 
 
+// @ts-ignore
 export const  apisystemdzbcPathSchedulinglist = query => {
 export const  apisystemdzbcPathSchedulinglist = query => {
     return service({
     return service({
         url: '/api/system/dzbcPathScheduling/list',
         url: '/api/system/dzbcPathScheduling/list',
@@ -379,6 +417,7 @@ export const  apisystemdzbcPathSchedulinglist = query => {
 };
 };
 
 
 //导出定制班车-路线排班列表https://khy.xiaole.vip/api/system/dzbcPathScheduling/export
 //导出定制班车-路线排班列表https://khy.xiaole.vip/api/system/dzbcPathScheduling/export
+// @ts-ignore
 export const  apisystemdzbcPathSchedulingexport = query => {
 export const  apisystemdzbcPathSchedulingexport = query => {
     return service({
     return service({
         url: '/api/system/dzbcPathScheduling/export',
         url: '/api/system/dzbcPathScheduling/export',
@@ -389,6 +428,7 @@ export const  apisystemdzbcPathSchedulingexport = query => {
 };
 };
 
 
 //新增定制班车-路线排班https://khy.xiaole.vip/api/system/dzbcPathScheduling
 //新增定制班车-路线排班https://khy.xiaole.vip/api/system/dzbcPathScheduling
+// @ts-ignore
 export const  apisystemdzbcPathSchedulingAdd = query => {
 export const  apisystemdzbcPathSchedulingAdd = query => {
     return service({
     return service({
         url: `/api/system/dzbcPathScheduling`,
         url: `/api/system/dzbcPathScheduling`,
@@ -398,6 +438,7 @@ export const  apisystemdzbcPathSchedulingAdd = query => {
 };
 };
 
 
 //删除定制班车-路线排班https://khy.xiaole.vip/api/system/dzbcPathScheduling/{ids}
 //删除定制班车-路线排班https://khy.xiaole.vip/api/system/dzbcPathScheduling/{ids}
+// @ts-ignore
 export const  apisystemdzbcPathSchedulingDel = query => {
 export const  apisystemdzbcPathSchedulingDel = query => {
     return service({
     return service({
         url: `/api/system/dzbcPathScheduling/${query.id}`,
         url: `/api/system/dzbcPathScheduling/${query.id}`,
@@ -406,6 +447,7 @@ export const  apisystemdzbcPathSchedulingDel = query => {
 };
 };
 
 
 //修改定制班车-路线排班https://khy.xiaole.vip/api/system/dzbcPathScheduling
 //修改定制班车-路线排班https://khy.xiaole.vip/api/system/dzbcPathScheduling
+// @ts-ignore
 export const apisystemdzbcPathSchedulingUpdate = query => {
 export const apisystemdzbcPathSchedulingUpdate = query => {
     return service({
     return service({
         url: `/api/system/dzbcPathScheduling`,
         url: `/api/system/dzbcPathScheduling`,
@@ -418,6 +460,7 @@ export const apisystemdzbcPathSchedulingUpdate = query => {
 
 
 //获取用户列表https://khy.xiaole.vip/api/system/user/list
 //获取用户列表https://khy.xiaole.vip/api/system/user/list
 
 
+// @ts-ignore
 export const  apisystemuserlist = query => {
 export const  apisystemuserlist = query => {
     return service({
     return service({
         url: '/api/system/user/list',
         url: '/api/system/user/list',
@@ -427,6 +470,7 @@ export const  apisystemuserlist = query => {
 };
 };
 
 
 //修改用户https://khy.xiaole.vip/api/system/user
 //修改用户https://khy.xiaole.vip/api/system/user
+// @ts-ignore
 export const  apisystemuserUpdate = query => {
 export const  apisystemuserUpdate = query => {
     return service({
     return service({
         url: '/api/system/user',
         url: '/api/system/user',
@@ -436,6 +480,7 @@ export const  apisystemuserUpdate = query => {
 };
 };
 
 
 //新增用户https://khy.xiaole.vip/api/system/user
 //新增用户https://khy.xiaole.vip/api/system/user
+// @ts-ignore
 export const  apisystemuserAdd = query => {
 export const  apisystemuserAdd = query => {
     return service({
     return service({
         url: `/api/system/user`,
         url: `/api/system/user`,
@@ -445,6 +490,7 @@ export const  apisystemuserAdd = query => {
 };
 };
 
 
 //删除用户https://khy.xiaole.vip/api/system/user/{userIds}
 //删除用户https://khy.xiaole.vip/api/system/user/{userIds}
+// @ts-ignore
 export const  apisystemuserDel = query => {
 export const  apisystemuserDel = query => {
     return service({
     return service({
         url: `/api/system/user/${query.id}`,
         url: `/api/system/user/${query.id}`,
@@ -453,6 +499,7 @@ export const  apisystemuserDel = query => {
 };
 };
 
 
 //重置密码https://khy.xiaole.vip/api/system/user/resetPwd
 //重置密码https://khy.xiaole.vip/api/system/user/resetPwd
+// @ts-ignore
 export const apisystemuserresetPwd = query => {
 export const apisystemuserresetPwd = query => {
     return service({
     return service({
         url: `/api/system/user/resetPwd`,
         url: `/api/system/user/resetPwd`,
@@ -461,6 +508,7 @@ export const apisystemuserresetPwd = query => {
     });
     });
 };
 };
 //状态修改https://khy.xiaole.vip/api/system/user/changeStatus
 //状态修改https://khy.xiaole.vip/api/system/user/changeStatus
+// @ts-ignore
 export const apisystemuserchangeStatus = query => {
 export const apisystemuserchangeStatus = query => {
     return service({
     return service({
         url: `/api/system/user/changeStatus`,
         url: `/api/system/user/changeStatus`,
@@ -469,6 +517,7 @@ export const apisystemuserchangeStatus = query => {
     });
     });
 };
 };
 //用户授权角色https://khy.xiaole.vip/api/system/user/authRole
 //用户授权角色https://khy.xiaole.vip/api/system/user/authRole
+// @ts-ignore
 export const apisystemuserauthRole = query => {
 export const apisystemuserauthRole = query => {
     return service({
     return service({
         url: `/api/system/user/authRole`,
         url: `/api/system/user/authRole`,
@@ -480,6 +529,7 @@ export const apisystemuserauthRole = query => {
 
 
 //获取角色信息列表https://khy.xiaole.vip/api/system/role/list
 //获取角色信息列表https://khy.xiaole.vip/api/system/role/list
 
 
+// @ts-ignore
 export const  apisystemrolelist = query => {
 export const  apisystemrolelist = query => {
     return service({
     return service({
         url: '/api/system/role/list',
         url: '/api/system/role/list',
@@ -490,6 +540,7 @@ export const  apisystemrolelist = query => {
 
 
 //导出角色信息列表https://khy.xiaole.vip/api/system/role/export
 //导出角色信息列表https://khy.xiaole.vip/api/system/role/export
 
 
+// @ts-ignore
 export const  apisystemroleexport = query => {
 export const  apisystemroleexport = query => {
     return service({
     return service({
         url: '/api/system/role/export',
         url: '/api/system/role/export',
@@ -500,6 +551,7 @@ export const  apisystemroleexport = query => {
 };
 };
 //新增角色https://khy.xiaole.vip/api/system/role
 //新增角色https://khy.xiaole.vip/api/system/role
 
 
+// @ts-ignore
 export const  apisystemroleAdd= query => {
 export const  apisystemroleAdd= query => {
     return service({
     return service({
         url: '/api/system/role',
         url: '/api/system/role',
@@ -509,6 +561,7 @@ export const  apisystemroleAdd= query => {
 };
 };
 //修改保存角色https://khy.xiaole.vip/api/system/role
 //修改保存角色https://khy.xiaole.vip/api/system/role
 
 
+// @ts-ignore
 export const  apisystemroleUpdate = query => {
 export const  apisystemroleUpdate = query => {
     return service({
     return service({
         url: '/api/system/role',
         url: '/api/system/role',
@@ -518,9 +571,382 @@ export const  apisystemroleUpdate = query => {
 };
 };
 //删除角色https://khy.xiaole.vip/api/system/role/{roleIds}
 //删除角色https://khy.xiaole.vip/api/system/role/{roleIds}
 
 
+// @ts-ignore
 export const  apisystemroleDel = query => {
 export const  apisystemroleDel = query => {
     return service({
     return service({
         url: `/api/system/role/${query.id}`,
         url: `/api/system/role/${query.id}`,
         method: 'DELETE'
         method: 'DELETE'
     });
     });
 };
 };
+
+
+// ================== 货物订单管理 ==================
+
+// 查询货物订单列表
+// @ts-ignore
+export const apisystemdzbcCargoOrderlist = query => {
+    return service({
+        url: '/api/system/dzbc/cargoOrder/list',
+        method: 'GET',
+        params: query
+    });
+};
+
+// 导出货物订单列表
+// @ts-ignore
+export const apisystemdzbcCargoOrderexport = query => {
+    return service({
+        url: '/api/system/dzbc/cargoOrder/export',
+        method: 'POST',
+        data: query,
+        responseType: 'blob'
+    });
+};
+
+// 获取货物订单详情
+// @ts-ignore
+export const apisystemdzbcCargoOrderGet = query => {
+    return service({
+        url: `/api/system/dzbc/cargoOrder/${query.id}`,
+        method: 'GET'
+    });
+};
+
+// 修改货物订单
+// @ts-ignore
+export const apisystemdzbcCargoOrderUpdate = query => {
+    return service({
+        url: '/api/system/dzbc/cargoOrder',
+        method: 'PUT',
+        data: query
+    });
+};
+
+// 更新货物订单状态
+// @ts-ignore
+export const apisystemdzbcCargoOrderStatus = query => {
+    return service({
+        url: `/api/system/dzbc/cargoOrder/status/${query.id}`,
+        method: 'POST',
+        params: { status: query.status }
+    });
+};
+
+// 删除货物订单
+// @ts-ignore
+export const apisystemdzbcCargoOrderDel = query => {
+    return service({
+        url: `/api/system/dzbc/cargoOrder/${query.id}`,
+        method: 'DELETE'
+    });
+};
+
+
+// ================== 问题建议管理 ==================
+
+// 查询问题建议列表
+// @ts-ignore
+export const apisystemdzbcFeedbacklist = query => {
+    return service({
+        url: '/api/system/dzbc/feedback/list',
+        method: 'GET',
+        params: query
+    });
+};
+
+// 导出问题建议列表
+// @ts-ignore
+export const apisystemdzbcFeedbackexport = query => {
+    return service({
+        url: '/api/system/dzbc/feedback/export',
+        method: 'POST',
+        data: query,
+        responseType: 'blob'
+    });
+};
+
+// 获取问题建议详情
+// @ts-ignore
+export const apisystemdzbcFeedbackGet = query => {
+    return service({
+        url: `/api/system/dzbc/feedback/${query.id}`,
+        method: 'GET'
+    });
+};
+
+// 回复问题建议
+// @ts-ignore
+export const apisystemdzbcFeedbackReply = query => {
+    return service({
+        url: `/api/system/dzbc/feedback/reply/${query.id}`,
+        method: 'POST',
+        params: { replyContent: query.replyContent }
+    });
+};
+
+// 提交问题建议
+// @ts-ignore
+export const apisystemdzbcFeedbackSubmit = query => {
+    return service({
+        url: '/api/system/dzbc/feedback/submit',
+        method: 'POST',
+        headers: { 'Content-Type': 'multipart/form-data' },
+        data: query
+    });
+};
+
+// 删除问题建议
+// @ts-ignore
+export const apisystemdzbcFeedbackDel = query => {
+    return service({
+        url: `/api/system/dzbc/feedback/${query.id}`,
+        method: 'DELETE'
+    });
+};
+
+
+// ================== 司机任务管理 ==================
+
+// 查询司机任务列表
+// @ts-ignore
+export const apisystemdzbcDriverTriplist = query => {
+    return service({
+        url: '/api/system/dzbc/driverTrip/list',
+        method: 'GET',
+        params: query
+    });
+};
+
+// 导出司机任务列表
+// @ts-ignore
+export const apisystemdzbcDriverTripexport = query => {
+    return service({
+        url: '/api/system/dzbc/driverTrip/export',
+        method: 'POST',
+        data: query,
+        responseType: 'blob'
+    });
+};
+
+// 新增司机任务
+// @ts-ignore
+export const apisystemdzbcDriverTripAdd = query => {
+    return service({
+        url: '/api/system/dzbc/driverTrip',
+        method: 'POST',
+        data: query
+    });
+};
+
+// 修改司机任务
+// @ts-ignore
+export const apisystemdzbcDriverTripUpdate = query => {
+    return service({
+        url: '/api/system/dzbc/driverTrip',
+        method: 'PUT',
+        data: query
+    });
+};
+
+// 删除司机任务
+// @ts-ignore
+export const apisystemdzbcDriverTripDel = query => {
+    return service({
+        url: `/api/system/dzbc/driverTrip/${query.id}`,
+        method: 'DELETE'
+    });
+};
+
+
+// ================== 多站点路线管理 ==================
+
+// 查询多站点路线列表
+export const apisystemdzbcMultiSitePathlist = query => {
+    return service({
+        url: '/api/system/dzbc/multiSitePath/list',
+        method: 'GET',
+        params: query
+    });
+};
+
+// 导出多站点路线列表
+export const apisystemdzbcMultiSitePathexport = query => {
+    return service({
+        url: '/api/system/dzbc/multiSitePath/export',
+        method: 'POST',
+        data: query,
+        responseType: 'blob'
+    });
+};
+
+// 获取多站点路线详情
+export const apisystemdzbcMultiSitePathGet = query => {
+    return service({
+        url: `/api/system/dzbc/multiSitePath/${query.id}`,
+        method: 'GET'
+    });
+};
+
+// 新增多站点路线
+export const apisystemdzbcMultiSitePathAdd = query => {
+    return service({
+        url: '/api/system/dzbc/multiSitePath',
+        method: 'POST',
+        data: query
+    });
+};
+
+// 修改多站点路线
+export const apisystemdzbcMultiSitePathUpdate = query => {
+    return service({
+        url: '/api/system/dzbc/multiSitePath',
+        method: 'PUT',
+        data: query
+    });
+};
+
+// 删除多站点路线
+export const apisystemdzbcMultiSitePathDel = query => {
+    return service({
+        url: `/api/system/dzbc/multiSitePath/${query.id}`,
+        method: 'DELETE'
+    });
+};
+
+
+// ================== 路线站点管理 ==================
+
+// 查询路线站点列表
+export const apisystemdzbcPathSitelist = query => {
+    return service({
+        url: '/api/system/dzbc/pathSite/list',
+        method: 'GET',
+        params: query
+    });
+};
+
+// 根据路线ID查询站点
+export const apisystemdzbcPathSiteByPathId = query => {
+    return service({
+        url: `/api/system/dzbc/pathSite/path/${query.pathId}`,
+        method: 'GET'
+    });
+};
+
+// 导出路线站点列表
+export const apisystemdzbcPathSiteexport = query => {
+    return service({
+        url: '/api/system/dzbc/pathSite/export',
+        method: 'POST',
+        data: query,
+        responseType: 'blob'
+    });
+};
+
+// 新增路线站点
+export const apisystemdzbcPathSiteAdd = query => {
+    return service({
+        url: '/api/system/dzbc/pathSite',
+        method: 'POST',
+        data: query
+    });
+};
+
+// 修改路线站点
+export const apisystemdzbcPathSiteUpdate = query => {
+    return service({
+        url: '/api/system/dzbc/pathSite',
+        method: 'PUT',
+        data: query
+    });
+};
+
+// 删除路线站点
+export const apisystemdzbcPathSiteDel = query => {
+    return service({
+        url: `/api/system/dzbc/pathSite/${query.id}`,
+        method: 'DELETE'
+    });
+};
+
+
+// ================== 站点价格管理 ==================
+
+// 查询站点价格列表
+export const apisystemdzbcSitePricelist = query => {
+    return service({
+        url: '/api/system/dzbc/sitePrice/list',
+        method: 'GET',
+        params: query
+    });
+};
+
+// 根据路线ID查询价格
+export const apisystemdzbcSitePriceByPathId = query => {
+    return service({
+        url: `/api/system/dzbc/sitePrice/path/${query.pathId}`,
+        method: 'GET'
+    });
+};
+
+// 导出站点价格列表
+export const apisystemdzbcSitePriceexport = query => {
+    return service({
+        url: '/api/system/dzbc/sitePrice/export',
+        method: 'POST',
+        data: query,
+        responseType: 'blob'
+    });
+};
+
+// 新增站点价格
+export const apisystemdzbcSitePriceAdd = query => {
+    return service({
+        url: '/api/system/dzbc/sitePrice',
+        method: 'POST',
+        data: query
+    });
+};
+
+// 修改站点价格
+export const apisystemdzbcSitePriceUpdate = query => {
+    return service({
+        url: '/api/system/dzbc/sitePrice',
+        method: 'PUT',
+        data: query
+    });
+};
+
+// 删除站点价格
+export const apisystemdzbcSitePriceDel = query => {
+    return service({
+        url: `/api/system/dzbc/sitePrice/${query.id}`,
+        method: 'DELETE'
+    });
+};
+
+
+// ================== 天气服务 ==================
+
+// 获取福州天气
+export const apisystemdzbcWeatherFuzhou = () => {
+    return service({
+        url: '/api/system/dzbc/weather/fuzhou',
+        method: 'GET'
+    });
+};
+
+
+// ================== Coze AI 客服 ==================
+
+// 发送消息给 Coze (流式)
+// 注意:axios 对流式支持不如 fetch 方便,这里作为普通请求发送,或者需要在组件中使用 fetch 处理流
+export const apisystemdzbcCozeChatStream = (query, onDownloadProgress) => {
+    return service({
+        url: '/api/system/dzbc/coze/chat/stream',
+        method: 'POST',
+        data: query,
+        responseType: 'stream', // 或者是 'text',取决于后端返回
+        onDownloadProgress: onDownloadProgress
+    });
+};

+ 1 - 1
src/request/index.ts

@@ -38,7 +38,7 @@ service.interceptors.request.use(
 // 响应拦截器
 // 响应拦截器
 service.interceptors.response.use(
 service.interceptors.response.use(
   response => {
   response => {
-    console.log('g350488F')
+    // console.log('g350488F')
     // 可以在这里对响应数据进行处理,例如:对返回的状态码进行判断
     // 可以在这里对响应数据进行处理,例如:对返回的状态码进行判断
     const res = response.data;
     const res = response.data;
     
     

+ 36 - 0
src/router/index.ts

@@ -69,6 +69,36 @@ const router = createRouter({
           component: () => import("../views/passengerstation/index.vue"),
           component: () => import("../views/passengerstation/index.vue"),
           meta: { title: "用户信息",parent:'wdxx' },
           meta: { title: "用户信息",parent:'wdxx' },
         },
         },
+        {
+          path: "/cargoorderman",
+          component: () => import("../views/cargoorderman/index.vue"),
+          meta: { title: "货物订单", parent: 'wdxx' },
+        },
+        {
+          path: "/feedbackman",
+          component: () => import("../views/feedbackman/index.vue"),
+          meta: { title: "问题建议", parent: 'wdxx' },
+        },
+        {
+          path: "/drivertripman",
+          component: () => import("../views/drivertripman/index.vue"),
+          meta: { title: "司机任务", parent: 'wdxx' },
+        },
+        {
+          path: "/multisitepathman",
+          component: () => import("../views/multisitepathman/index.vue"),
+          meta: { title: "多站点路线", parent: 'wdxx' },
+        },
+        {
+          path: "/weatherman",
+          component: () => import("../views/weatherman/index.vue"),
+          meta: { title: "天气信息", parent: 'wdxx' },
+        },
+        {
+          path: "/cozechat",
+          component: () => import("../views/cozechat/index.vue"),
+          meta: { title: "智能客服", parent: 'wdxx' },
+        },
       ]
       ]
     },
     },
     {
     {
@@ -77,6 +107,12 @@ const router = createRouter({
       component: () => import("../views/login/index.vue"),
       component: () => import("../views/login/index.vue"),
     },
     },
     {
     {
+      path: '/agreement',
+      name: 'agreement',
+      component: () => import("../views/agreement/index.vue"),
+      meta: { title: "用户协议" }
+    },
+    {
       path: '/about',
       path: '/about',
       name: 'about',
       name: 'about',
       
       

+ 72 - 0
src/views/HomeView.vue

@@ -57,6 +57,24 @@ let filterName=computed(()=>{
     case '/bannerman':
     case '/bannerman':
       res='小程序宣传图管理'
       res='小程序宣传图管理'
       break;
       break;
+    case '/cargoorderman':
+      res='货物订单管理'
+      break;
+    case '/feedbackman':
+      res='问题建议管理'
+      break;
+    case '/drivertripman':
+      res='司机任务管理'
+      break;
+    case '/multisitepathman':
+      res='多站点路线管理'
+      break;
+    case '/weatherman':
+      res='天气信息'
+      break;
+    case '/cozechat':
+      res='智能客服'
+      break;
   }
   }
   return res
   return res
 })
 })
@@ -201,6 +219,60 @@ watch(() => route, (newRoute, oldRoute) => {
             <el-icon><ArrowRightBold /></el-icon>
             <el-icon><ArrowRightBold /></el-icon>
           </div>
           </div>
         </el-menu-item> -->
         </el-menu-item> -->
+        <el-menu-item index="cargoorderman">
+          <div class="ima-icon">
+            <img style="width:12px;height:auto" src="../../public/imgs/orderman.png" alt="">
+          </div>
+          <span style="flex:1">货物订单管理</span>
+          <div class="next-img">
+            <el-icon><ArrowRightBold /></el-icon>
+          </div>
+        </el-menu-item>
+        <el-menu-item index="feedbackman">
+          <div class="ima-icon">
+            <img style="width:12px;height:auto" src="../../public/imgs/userman.png" alt="">
+          </div>
+          <span style="flex:1">问题建议管理</span>
+          <div class="next-img">
+            <el-icon><ArrowRightBold /></el-icon>
+          </div>
+        </el-menu-item>
+        <el-menu-item index="drivertripman">
+          <div class="ima-icon">
+            <img style="width:16px;height:auto" src="../../public/imgs/carman.png" alt="">
+          </div>
+          <span style="flex:1">司机任务管理</span>
+          <div class="next-img">
+            <el-icon><ArrowRightBold /></el-icon>
+          </div>
+        </el-menu-item>
+        <el-menu-item index="multisitepathman">
+          <div class="ima-icon">
+            <img style="width:16px;height:auto" src="../../public/imgs/routeman.png" alt="">
+          </div>
+          <span style="flex:1">多站点路线</span>
+          <div class="next-img">
+            <el-icon><ArrowRightBold /></el-icon>
+          </div>
+        </el-menu-item>
+        <el-menu-item index="weatherman">
+          <div class="ima-icon">
+            <img style="width:16px;height:auto" src="../../public/imgs/areaman.png" alt="">
+          </div>
+          <span style="flex:1">天气信息</span>
+          <div class="next-img">
+            <el-icon><ArrowRightBold /></el-icon>
+          </div>
+        </el-menu-item>
+        <el-menu-item index="cozechat">
+          <div class="ima-icon">
+            <img style="width:16px;height:auto" src="../../public/imgs/userman.png" alt="">
+          </div>
+          <span style="flex:1">智能客服</span>
+          <div class="next-img">
+            <el-icon><ArrowRightBold /></el-icon>
+          </div>
+        </el-menu-item>
         <el-menu-item index="bannerman">
         <el-menu-item index="bannerman">
           <div class="ima-icon">
           <div class="ima-icon">
             <img style="width:12px;height:auto" src="../../public/imgs/orderman.png" alt="">
             <img style="width:12px;height:auto" src="../../public/imgs/orderman.png" alt="">

+ 143 - 0
src/views/agreement/index.vue

@@ -0,0 +1,143 @@
+<script setup lang="ts">
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+
+const goBack = () => {
+  router.go(-1)
+}
+</script>
+
+<template>
+  <div class="agreement-page">
+    <div class="agreement-container">
+      <div class="header">
+        <h1>用户协议</h1>
+        <p class="subtitle">发布日期:2024年1月1日</p>
+      </div>
+      
+      <div class="content">
+        <section>
+          <h2>1. 特别提示</h2>
+          <p>在此特别提醒您(用户)在注册成为用户之前,请认真阅读本《用户协议》(以下简称“协议”),确保您充分理解本协议中各条款。请您审慎阅读并选择接受或不接受本协议。除非您接受本协议所有条款,否则您无权注册、登录或使用本协议所涉服务。您的注册、登录、使用等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。</p>
+        </section>
+
+        <section>
+          <h2>2. 账号注册</h2>
+          <p>2.1 用户在使用本服务前需要注册一个账号。账号应当使用手机号码绑定注册,请用户使用尚未与本服务绑定的手机号码,以及未被服务根据本协议封禁的手机号码注册账号。</p>
+          <p>2.2 如果注册申请者有被封禁的先例或涉嫌虚假注册及滥用他人名义注册,及其他不能得到许可的理由,我们有权拒绝向其提供服务。</p>
+        </section>
+
+        <section>
+          <h2>3. 服务内容</h2>
+          <p>3.1 本服务的具体内容由我们根据实际情况提供,包括但不限于定制班车查询、预订、支付等。</p>
+          <p>3.2 我们有权随时审核或删除用户发布/传播的涉嫌违法或违反社会主义精神文明,或者被我们认为不妥当的内容(包括但不限于文字、语音、图片、视频、图文等)。</p>
+        </section>
+
+        <section>
+          <h2>4. 用户个人信息保护</h2>
+          <p>4.1 保护用户个人信息是的一项基本原则,我们将会采取合理的措施保护用户的个人信息。除法律法规规定的情形外,未经用户许可我们不会向第三方公开、透露用户个人信息。</p>
+        </section>
+
+        <section>
+          <h2>5. 知识产权声明</h2>
+          <p>5.1 我们在本服务中提供的内容(包括但不限于网页、文字、图片、音频、视频、图表等)的知识产权归我们所有,用户在使用本服务中所产生的内容的知识产权归用户或相关权利人所有。</p>
+        </section>
+
+        <section>
+          <h2>6. 其他</h2>
+          <p>6.1 本协议的效力、解释及纠纷的解决,适用于中华人民共和国法律。</p>
+          <p>6.2 若您和我们之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,您同意将纠纷或争议提交本协议签订地有管辖权的人民法院管辖。</p>
+        </section>
+      </div>
+
+      <div class="footer">
+        <!-- <el-button type="primary" @click="goBack">返回</el-button> -->
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.agreement-page {
+  height: 100vh;
+  overflow-y: auto;
+  background-color: #f5f7fa;
+  padding: 40px 20px;
+  display: flex;
+  justify-content: center;
+  box-sizing: border-box;
+}
+
+.agreement-container {
+  background-color: #fff;
+  width: 100%;
+  max-width: 800px;
+  padding: 40px;
+  border-radius: 8px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  max-height: calc(100vh - 80px);
+  overflow-y: auto;
+}
+
+.header {
+  text-align: center;
+  margin-bottom: 30px;
+  border-bottom: 1px solid #ebeef5;
+  padding-bottom: 20px;
+
+  h1 {
+    font-size: 24px;
+    color: #303133;
+    margin-bottom: 10px;
+    font-weight: 600;
+  }
+
+  .subtitle {
+    color: #909399;
+    font-size: 14px;
+  }
+}
+
+.content {
+  color: #606266;
+  line-height: 1.8;
+  font-size: 15px;
+
+  section {
+    margin-bottom: 25px;
+
+    h2 {
+      font-size: 18px;
+      color: #303133;
+      margin-bottom: 12px;
+      font-weight: 600;
+    }
+
+    p {
+      margin-bottom: 10px;
+      text-align: justify;
+    }
+  }
+}
+
+.footer {
+  margin-top: 40px;
+  text-align: center;
+  border-top: 1px solid #ebeef5;
+  padding-top: 20px;
+}
+
+@media (max-width: 768px) {
+  .agreement-page {
+    padding: 0;
+  }
+  
+  .agreement-container {
+    border-radius: 0;
+    padding: 20px;
+    height: 100vh;
+    max-height: 100vh;
+  }
+}
+</style>

+ 233 - 0
src/views/cargoorderman/index.vue

@@ -0,0 +1,233 @@
+<script setup lang="ts">
+import { apisystemdzbcCargoOrderlist, apisystemdzbcCargoOrderexport, apisystemdzbcCargoOrderDel, apisystemdzbcCargoOrderStatus } from '../../request/api.js'
+import type { ComponentSize, FormInstance, FormRules } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { ref, onMounted, reactive } from 'vue'
+import { Search, Download, Close, Check } from "@element-plus/icons-vue";
+
+let orderNo = ref('')
+let total = ref(0)
+let pageNum = ref(1)
+let loading = ref(true)
+let excellloading = ref(false)
+const tableData = ref([])
+
+const downExcell = () => {
+  excellloading.value = true
+  apisystemdzbcCargoOrderexport({}).then((res: any) => {
+    let blob = new Blob([res], {
+      type: "application/x-msdownload;charset=UTF-8",
+    });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.setAttribute('download', '货物订单列表.xls');
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link)
+    window.URL.revokeObjectURL(url)
+    excellloading.value = false
+  }).catch((err: any) => {
+    console.log(err)
+    excellloading.value = false
+  })
+}
+
+const searchClick = () => {
+  pageNum.value = 1
+  getTableData()
+}
+
+const getTableData = () => {
+  loading.value = true
+  apisystemdzbcCargoOrderlist({
+    orderNo: orderNo.value,
+    pageSize: 10,
+    pageNum: pageNum.value
+  }).then(res => {
+    if (res.code == 200) {
+      total.value = res.total
+      tableData.value = res.rows
+    }
+    loading.value = false
+  }).catch(err => {
+    console.log(err)
+    loading.value = false
+  })
+}
+
+const deleteItem = (id) => {
+  ElMessageBox.confirm(
+    '确定要删除该订单吗?',
+    '提示',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(() => {
+      apisystemdzbcCargoOrderDel({ id }).then((res: any) => {
+        getTableData()
+        ElMessage({
+          message: '操作成功',
+          type: 'success',
+          duration: 3 * 1000
+        });
+      })
+    })
+    .catch(() => {
+    })
+}
+
+const updateStatus = (id, status) => {
+  ElMessageBox.confirm(
+    '确定要更新订单状态吗?',
+    '提示',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+  .then(() => {
+      apisystemdzbcCargoOrderStatus({ id, status }).then((res: any) => {
+        getTableData()
+        ElMessage({
+          message: '操作成功',
+          type: 'success',
+          duration: 3 * 1000
+        });
+      })
+    })
+    .catch(() => {})
+}
+
+onMounted(() => {
+  getTableData()
+})
+
+</script>
+<template>
+  <div>
+    <div class="common-top">
+      <div class="left-part">
+        <div class="title">
+          货物订单管理
+        </div>
+        <div class="sub-title">
+          管理所有货物订单信息
+        </div>
+      </div>
+    </div>
+
+    <div class="common-content">
+      <div class="common-search-box">
+        <div class="left-part">
+          <el-input v-model="orderNo" placeholder="订单编号" style="width:260px"></el-input>
+          <el-button @click="searchClick" style="margin-left:10px">筛选</el-button>
+        </div>
+        <div class="right-part">
+          <el-button :loading="excellloading" @click="downExcell" :icon="Download">{{ excellloading ? '正在导出' : '导出'
+            }}</el-button>
+        </div>
+      </div>
+      <el-table element-loading-text='加载中' header-row-class-name="reset-gray-head" :data="tableData" style="width: 100%"
+        v-loading="loading">
+        <el-table-column prop="orderNo" label="订单编号" width="180" />
+        <el-table-column prop="tripNo" label="任务编号" width="180" />
+        <el-table-column prop="senderName" label="发货人" />
+        <el-table-column prop="senderPhone" label="发货电话" />
+        <el-table-column prop="receiverName" label="收货人" />
+        <el-table-column prop="receiverPhone" label="收货电话" />
+        <el-table-column prop="price" label="价格(元)">
+          <template #default="scope">
+            {{ scope.row.price ? (scope.row.price / 100).toFixed(2) : '0.00' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="payStatus" label="支付状态">
+          <template #default="scope">
+            <el-tag v-if="scope.row.payStatus == 0" type="warning">待支付</el-tag>
+            <el-tag v-if="scope.row.payStatus == 1" type="success">已支付</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="订单状态">
+          <template #default="scope">
+            <el-tag v-if="scope.row.status == 0">待发货</el-tag>
+            <el-tag v-if="scope.row.status == 1" type="warning">已取货</el-tag>
+            <el-tag v-if="scope.row.status == 2" type="primary">运输中</el-tag>
+            <el-tag v-if="scope.row.status == 3" type="success">已送达</el-tag>
+            <el-tag v-if="scope.row.status == 4" type="info">已取消</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="200" fixed="right">
+          <template #default="scope">
+             <!-- 简单的状态流转操作 -->
+             <el-button v-if="scope.row.status == 0" type="primary" link size="small" @click="updateStatus(scope.row.id, 1)">取货</el-button>
+             <el-button v-if="scope.row.status == 1" type="primary" link size="small" @click="updateStatus(scope.row.id, 2)">发车</el-button>
+             <el-button v-if="scope.row.status == 2" type="primary" link size="small" @click="updateStatus(scope.row.id, 3)">送达</el-button>
+             <el-button type="danger" link size="small" @click="deleteItem(scope.row.id)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="common-page-wrap">
+        <div class="left-part">
+          <span>共{{ total }}条记录 </span>
+        </div>
+        <div class="right-part">
+          <el-pagination v-model:current-page="pageNum" @current-change="getTableData" background
+            layout="prev, pager, next" :total="total" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+.reset-gray-head {
+  background: #f3f4f6;
+
+  .el-table__cell,
+  th {
+    background: #f3f4f6 !important;
+  }
+
+}
+</style>
+
+<style lang="scss" scoped>
+.common-top {
+  display: flex;
+  justify-content: space-between;
+}
+
+.common-page-wrap {
+  padding: 10px 10px 10px 10px;
+  display: flex;
+  justify-content: space-between;
+}
+
+.sub-title {
+  color: #4B5563;
+  font-size: 16px;
+  margin-bottom: 24px;
+}
+
+.title {
+  color: #1F2937;
+  font-size: 24px;
+  font-weight: 600;
+}
+
+.common-content {
+  background: #fff;
+
+  .common-search-box {
+    padding: 10px 10px 10px 10px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}
+</style>

+ 108 - 29
src/views/carplanman/index.vue

@@ -51,7 +51,8 @@ import { Search,Download,Tools,Plus,Check,Close } from "@element-plus/icons-vue"
 let searchkey=ref('')
 let searchkey=ref('')
 let isauto=ref(false)
 let isauto=ref(false)
 let viewType=ref(1)
 let viewType=ref(1)
-import { apisystemdzbcSitelist,apisystemdzbcPathlist,apisystemdzbcCarlist,apisystemdzbcPathSchedulinglist,apisystemdzbcPathSchedulingexport,apisystemdzbcPathSchedulingDel,apisystemdzbcPathSchedulingAdd,apisystemdzbcPathSchedulingUpdate } from '../../request/api.js'
+let routeType=ref('1') // 1:普通路线 2:多站点路线
+import { apisystemdzbcMultiSitePathlist,apisystemdzbcSitelist,apisystemdzbcPathlist,apisystemdzbcCarlist,apisystemdzbcPathSchedulinglist,apisystemdzbcPathSchedulingexport,apisystemdzbcPathSchedulingDel,apisystemdzbcPathSchedulingAdd,apisystemdzbcPathSchedulingUpdate } from '../../request/api.js'
 import type { ComponentSize, FormInstance, FormRules } from 'element-plus'
 import type { ComponentSize, FormInstance, FormRules } from 'element-plus'
 import { ElMessage } from 'element-plus'
 import { ElMessage } from 'element-plus'
 interface RuleForm {
 interface RuleForm {
@@ -62,7 +63,8 @@ interface RuleForm {
   mtime: string,
   mtime: string,
   remark: string,
   remark: string,
   isauto: any,
   isauto: any,
-  pprice: any
+  pprice: any,
+  ext2: any
 }
 }
 const initData={
 const initData={
   id:'',
   id:'',
@@ -72,7 +74,8 @@ const initData={
   "mtime": "",
   "mtime": "",
   "remark": "",
   "remark": "",
   "isauto": '0',
   "isauto": '0',
-  "pprice": 0
+  "pprice": 0,
+  ext2:''
 }
 }
 const formSize = ref<ComponentSize>('default')
 const formSize = ref<ComponentSize>('default')
 const ruleFormRef = ref<FormInstance>()
 const ruleFormRef = ref<FormInstance>()
@@ -84,7 +87,8 @@ const ruleForm = reactive<RuleForm>({
   "mtime": "",
   "mtime": "",
   "remark": "",
   "remark": "",
   "isauto": '0',
   "isauto": '0',
-  "pprice": 0
+  "pprice": 0,
+  ext2:''
 })
 })
 
 
 
 
@@ -105,9 +109,27 @@ const submitForm = async (formEl: FormInstance | undefined) => {
   }
   }
   await formEl.validate((valid, fields) => {
   await formEl.validate((valid, fields) => {
     if (valid) {
     if (valid) {
+      let postData = { ...ruleForm }
+      let type = routeType.value === '2' ? 2 : 1;
+      
+      let ext2Obj = {};
+      try {
+          if (postData.ext2) {
+              ext2Obj = JSON.parse(postData.ext2);
+          }
+      } catch (e) {
+        console.error('ext2 parse error', e);
+      }
+      
+      // @ts-ignore
+      ext2Obj.type = type;
+      postData.ext2 = JSON.stringify(ext2Obj);
+      // @ts-ignore
+      postData.type = type;
+
       if(ruleForm.id){
       if(ruleForm.id){
         
         
-        apisystemdzbcPathSchedulingUpdate(ruleForm).then((res:any)=>{
+        apisystemdzbcPathSchedulingUpdate(postData).then((res:any)=>{
           getTableData()
           getTableData()
           ElMessage({
           ElMessage({
                 message: '操作成功',
                 message: '操作成功',
@@ -119,7 +141,7 @@ const submitForm = async (formEl: FormInstance | undefined) => {
           console.log(err)
           console.log(err)
         })
         })
       }else{
       }else{
-        apisystemdzbcPathSchedulingAdd(ruleForm).then((res:any)=>{
+        apisystemdzbcPathSchedulingAdd(postData).then((res:any)=>{
          if(res.code==200){
          if(res.code==200){
           getTableData()
           getTableData()
           ElMessage({
           ElMessage({
@@ -168,6 +190,15 @@ const addItem=data=>{
     }
     }
     ruleForm.isauto=isauto.value?'1':'0'
     ruleForm.isauto=isauto.value?'1':'0'
     ruleForm.mdate=data.mdate
     ruleForm.mdate=data.mdate
+    // 普通路线使用默认发车时间
+    if(routeType.value == '1' && nowselRoute.value.mtime){
+        ruleForm.mtime = nowselRoute.value.mtime
+    }
+    
+    // 初始化 ext2
+    let type = routeType.value === '2' ? 2 : 1;
+    ruleForm.ext2 = JSON.stringify({ type: type });
+
     logtitle.value='新增定制班车-路线排班'
     logtitle.value='新增定制班车-路线排班'
   }
   }
   ruleForm.pathId=nowselRoute.value.id
   ruleForm.pathId=nowselRoute.value.id
@@ -320,41 +351,57 @@ const getTableData=()=>{
     pathId:pathId.value,
     pathId:pathId.value,
     pageSize:viewType.value==1?1000:10,
     pageSize:viewType.value==1?1000:10,
     pageNum:pageNum.value,
     pageNum:pageNum.value,
-    'params[mdate]': viewType.value==1?dayjs().format('YYYY-MM-DD'):null
-    
+    'params[mdate]': viewType.value==1?dayjs().format('YYYY-MM-DD'):null,
+    type: routeType.value
   }).then(res=>{
   }).then(res=>{
     if(res.code==200){
     if(res.code==200){
       total.value=res.total
       total.value=res.total
       tableData.value=res.rows.map(item=>{
       tableData.value=res.rows.map(item=>{
         item.mdate=item.mdate?item.mdate:''
         item.mdate=item.mdate?item.mdate:''
-        item.ftime=nowselRoute.value.mtime
+        item.ftime=nowselRoute.value.mtime || item.mtime
+        
+        // 尝试从 ext1 解析车辆和路线信息
+        if (item.ext1) {
+            try {
+                const ext1 = JSON.parse(item.ext1);
+                if (ext1.carInfo && ext1.carInfo.carNum) {
+                    item.carName = ext1.carInfo.carNum;
+                }
+                if (ext1.pathInfo && ext1.pathInfo.name) {
+                    item.pathName = ext1.pathInfo.name;
+                }
+            } catch (e) {
+                console.error('ext1 parse error', e);
+            }
+        }
+        
         return item
         return item
       })
       })
 
 
-
-
       console.log('==========================================',tableData.value)
       console.log('==========================================',tableData.value)
 
 
       for(let i=0;i<tableData.value.length;i++){
       for(let i=0;i<tableData.value.length;i++){
-        let car=carList.value.filter(car=>{
-          return car.id===tableData.value[i].carId
-        })[0]
-        if(car){
-          tableData.value[i].carName=car.carNum
+        // 如果 ext1 没有解析出 carName,则尝试通过 carId 匹配
+        if (!tableData.value[i].carName) {
+            let car=carList.value.filter(car=>{
+              return car.id===tableData.value[i].carId
+            })[0]
+            if(car){
+              tableData.value[i].carName=car.carNum
+            }
         }
         }
 
 
-        let route=routeList.value.filter(route=>{
-          return route.id===tableData.value[i].pathId
-        })[0]
-       
-        if(route){
-          tableData.value[i].pathName=route.name
+        // 如果 ext1 没有解析出 pathName,则尝试通过 pathId 匹配
+        if (!tableData.value[i].pathName) {
+            let route=routeList.value.filter(route=>{
+              return route.id===tableData.value[i].pathId
+            })[0]
+           
+            if(route){
+              tableData.value[i].pathName=route.name
+            }
         }
         }
-    
-        
       }
       }
-
-
     }
     }
     loading.value=false
     loading.value=false
     
     
@@ -394,14 +441,26 @@ const clickRoute=item=>{
   pathId.value=item.id
   pathId.value=item.id
   searchClick()
   searchClick()
 }
 }
-const searchRoute=()=>{
-  apisystemdzbcPathlist({
+const searchRoute=(autoSelect)=>{
+  let api = routeType.value=='1' ? apisystemdzbcPathlist : apisystemdzbcMultiSitePathlist
+  api({
     name:searchkey.value
     name:searchkey.value
   }).then(res=>{
   }).then(res=>{
     if(res.code==200){
     if(res.code==200){
     
     
       routeListLeft.value=res.rows
       routeListLeft.value=res.rows
+      routeList.value=res.rows
       
       
+      if (autoSelect === true) {
+         if(res.rows && res.rows.length > 0){
+             clickRoute(res.rows[0])
+         } else {
+             nowselRoute.value = {}
+             pathId.value = ''
+             tableData.value = []
+             total.value = 0
+         }
+      }
     }
     }
   
   
     
     
@@ -409,6 +468,10 @@ const searchRoute=()=>{
     console.log(err)
     console.log(err)
   })
   })
 }
 }
+const changeRouteType=()=>{
+    searchkey.value=''
+    searchRoute(true)
+}
 let routeListLeft=ref([])
 let routeListLeft=ref([])
 onMounted(()=>{
 onMounted(()=>{
   //apisystemdzbcPathSchedulinglist
   //apisystemdzbcPathSchedulinglist
@@ -477,6 +540,10 @@ onMounted(()=>{
             <div class="chart-item" style="width:300px;margin-right:15px">
             <div class="chart-item" style="width:300px;margin-right:15px">
                 <el-card style="width: 97%">
                 <el-card style="width: 97%">
                     <div class="common-title">路线列表</div>
                     <div class="common-title">路线列表</div>
+                    <el-radio-group v-model="routeType" @change="changeRouteType" style="margin-bottom: 10px;">
+                      <el-radio-button label="1">普通路线</el-radio-button>
+                      <el-radio-button label="2">多站点路线</el-radio-button>
+                    </el-radio-group>
                     <el-input
                     <el-input
                     v-model="searchkey"
                     v-model="searchkey"
                     style="margin-bottom:10px"
                     style="margin-bottom:10px"
@@ -492,7 +559,8 @@ onMounted(()=>{
                         <div class="lefttop-card-wrap" :class="{'select-route':item.id==pathId}" v-for="item in routeListLeft" :key="item.id" @click="clickRoute(item)">
                         <div class="lefttop-card-wrap" :class="{'select-route':item.id==pathId}" v-for="item in routeListLeft" :key="item.id" @click="clickRoute(item)">
                             <div class="left-part">
                             <div class="left-part">
                                 <div class="title">{{item.name}}</div>
                                 <div class="title">{{item.name}}</div>
-                                <div class="time">发车时间: {{item.mtime}}</div>
+                                <div class="time" v-if="item.mtime">发车时间: {{item.mtime}}</div>
+                                <div class="time" v-else>多站点路线</div>
                             </div>
                             </div>
                             <div class="right-part">
                             <div class="right-part">
 
 
@@ -783,6 +851,17 @@ onMounted(()=>{
                 />
                 />
               </el-form-item>
               </el-form-item>
             </el-col>
             </el-col>
+
+            <el-col :span="12" v-if="routeType == '2'">
+              <el-form-item label="发车时间">
+                <el-time-picker
+                  style="width:100%"
+                  v-model="ruleForm.mtime"
+                  value-format="HH:mm:ss"
+                  placeholder="发车时间"
+                />
+              </el-form-item>
+            </el-col>
            
            
            
            
             
             

+ 240 - 0
src/views/cozechat/index.vue

@@ -0,0 +1,240 @@
+<script setup lang="ts">
+import { apisystemdzbcCozeChatStream } from '../../request/api.js'
+import { ref, reactive, nextTick, onMounted } from 'vue'
+import { ElMessage } from 'element-plus'
+import { Position } from "@element-plus/icons-vue";
+
+const messages = ref([])
+const inputMessage = ref('')
+const loading = ref(false)
+const chatContainer = ref(null)
+const conversationId = ref('')
+const botId = ref('') // 可以从配置或输入获取,目前留空使用后端默认
+const userId = ref('user_' + Date.now()) // 临时用户ID
+
+// Initialize with a welcome message
+onMounted(() => {
+    messages.value.push({
+        role: 'assistant',
+        content: '您好!我是您的智能助手,有什么可以帮您?'
+    })
+})
+
+const sendMessage = async () => {
+    if (!inputMessage.value.trim()) return
+    if (loading.value) return
+
+    const userMsg = inputMessage.value
+    messages.value.push({
+        role: 'user',
+        content: userMsg
+    })
+    inputMessage.value = ''
+    scrollToBottom()
+
+    loading.value = true
+    
+    // Add a placeholder for assistant response
+    const assistantMsgIndex = messages.value.push({
+        role: 'assistant',
+        content: '正在思考...'
+    }) - 1
+
+    try {
+        let assistantContent = ''
+        messages.value[assistantMsgIndex].content = '' // Clear "Thinking..."
+        let lastResponseLength = 0
+
+        await apisystemdzbcCozeChatStream({
+            content: userMsg,
+            userId: userId.value,
+            conversationId: conversationId.value || undefined,
+            botId: botId.value || undefined
+        }, (progressEvent) => {
+            const response = progressEvent.event.target.responseText
+            if (response) {
+                const chunk = response.substring(lastResponseLength)
+                lastResponseLength = response.length
+                
+                // Parse SSE format "data: content\n\n"
+                const lines = chunk.split('\n')
+                for (const line of lines) {
+                    if (line.startsWith('data: ')) {
+                        const data = line.substring(6)
+                        if (data.trim() === '[DONE]') {
+                            // End of stream
+                        } else if (data.startsWith('[ERROR]')) {
+                            console.error('Stream error:', data)
+                        } else if (data.startsWith('[DONE] Token usage:')) {
+                            // Optional: handle token usage
+                        } else {
+                            assistantContent += data
+                        }
+                    } else if (line.trim() !== '') {
+                        // Handle cases where newline might be part of content or malformed
+                        // For strict SSE, we should only handle 'data: ' lines
+                        // But sometimes content might wrap. For now, strict SSE parsing.
+                    }
+                }
+                
+                messages.value[assistantMsgIndex].content = assistantContent
+                scrollToBottom()
+            }
+        })
+        
+    } catch (error) {
+        console.error('Chat error:', error)
+        messages.value[assistantMsgIndex].content = '抱歉,我遇到了一些问题,请稍后再试。'
+    } finally {
+        loading.value = false
+        scrollToBottom()
+    }
+}
+
+const scrollToBottom = () => {
+    nextTick(() => {
+        if (chatContainer.value) {
+            chatContainer.value.scrollTop = chatContainer.value.scrollHeight
+        }
+    })
+}
+</script>
+
+<template>
+    <div class="chat-container">
+        <div class="common-top">
+            <div class="left-part">
+                <div class="title">
+                    智能客服
+                </div>
+                <div class="sub-title">
+                    基于 Coze AI 的智能对话助手
+                </div>
+            </div>
+        </div>
+
+        <div class="chat-box">
+            <div class="messages" ref="chatContainer">
+                <div v-for="(msg, index) in messages" :key="index" :class="['message-row', msg.role]">
+                    <div class="avatar" v-if="msg.role === 'assistant'">
+                        AI
+                    </div>
+                    <div class="bubble">
+                        <div class="content" style="white-space: pre-wrap;">{{ msg.content }}</div>
+                    </div>
+                    <div class="avatar user-avatar" v-if="msg.role === 'user'">
+                        Me
+                    </div>
+                </div>
+            </div>
+            <div class="input-area">
+                <el-input
+                    v-model="inputMessage"
+                    placeholder="请输入您的问题..."
+                    @keyup.enter="sendMessage"
+                    :disabled="loading"
+                >
+                    <template #append>
+                        <el-button :icon="Position" @click="sendMessage" :loading="loading" />
+                    </template>
+                </el-input>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.chat-container {
+    height: calc(100vh - 120px); // Adjust based on layout
+    display: flex;
+    flex-direction: column;
+    padding: 20px;
+}
+.common-top {
+  margin-bottom: 20px;
+}
+.sub-title {
+  color: #4B5563;
+  font-size: 16px;
+  margin-bottom: 24px;
+}
+
+.title {
+  color: #1F2937;
+  font-size: 24px;
+  font-weight: 600;
+}
+
+.chat-box {
+    flex: 1;
+    background: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+}
+
+.messages {
+    flex: 1;
+    overflow-y: auto;
+    padding: 20px;
+    background: #f9f9f9;
+}
+
+.message-row {
+    display: flex;
+    margin-bottom: 20px;
+    align-items: flex-start;
+    
+    &.user {
+        justify-content: flex-end;
+        .bubble {
+            background: #95ec69;
+            color: #000;
+            border-radius: 8px 0 8px 8px;
+        }
+    }
+    
+    &.assistant {
+        justify-content: flex-start;
+        .bubble {
+            background: #fff;
+            color: #333;
+            border-radius: 0 8px 8px 8px;
+        }
+    }
+}
+
+.avatar {
+    width: 40px;
+    height: 40px;
+    border-radius: 50%;
+    background: #409EFF;
+    color: #fff;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-weight: bold;
+    margin: 0 10px;
+    flex-shrink: 0;
+    
+    &.user-avatar {
+        background: #E6A23C;
+    }
+}
+
+.bubble {
+    padding: 12px 16px;
+    max-width: 70%;
+    box-shadow: 0 1px 2px rgba(0,0,0,0.1);
+    word-break: break-word;
+    line-height: 1.5;
+}
+
+.input-area {
+    padding: 20px;
+    background: #fff;
+    border-top: 1px solid #eee;
+}
+</style>

+ 467 - 0
src/views/drivertripman/index.vue

@@ -0,0 +1,467 @@
+<script setup lang="ts">
+import { apisystemdzbcDriverTriplist, apisystemdzbcDriverTripexport, apisystemdzbcDriverTripDel, apisystemdzbcDriverTripAdd, apisystemdzbcDriverTripUpdate, apisystemdzbcCargoOrderlist, apisystemdzbcCargoOrderStatus } from '../../request/api.js'
+import type { ComponentSize, FormInstance, FormRules } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { ref, onMounted, reactive } from 'vue'
+import { Search, Download, Close, Check, Plus, Box, Goods } from "@element-plus/icons-vue";
+
+let tripNo = ref('')
+let total = ref(0)
+let pageNum = ref(1)
+let loading = ref(true)
+let excellloading = ref(false)
+const tableData = ref([])
+
+let dialogVisible = ref(false)
+let dialogTitle = ref('新增司机任务')
+const formSize = ref<ComponentSize>('default')
+const ruleFormRef = ref<FormInstance>()
+const ruleForm = reactive({
+    id: '',
+    tripNo: '',
+    pathId: '', // Ideally this should be a select
+    driverId: '', // Ideally this should be a select
+    carId: '', // Ideally this should be a select
+    startTime: '',
+    endTime: '',
+    remark: ''
+})
+
+const rules = reactive<FormRules>({
+    tripNo: [{ required: true, message: '请输入任务编号', trigger: 'blur' }],
+    // pathId: [{ required: true, message: '请选择路线', trigger: 'change' }],
+    // driverId: [{ required: true, message: '请选择司机', trigger: 'change' }],
+    // carId: [{ required: true, message: '请选择车辆', trigger: 'change' }],
+    startTime: [{ required: true, message: '请选择出发时间', trigger: 'change' }],
+})
+
+// Cargo Orders Management
+const cargoDialogVisible = ref(false)
+const cargoList = ref([])
+const cargoLoading = ref(false)
+const currentTripId = ref('')
+
+const openCargoDialog = (row) => {
+    currentTripId.value = row.id
+    cargoDialogVisible.value = true
+    loadCargoOrders(row.id)
+}
+
+const loadCargoOrders = (tripId) => {
+    cargoLoading.value = true
+    // Assuming there's a way to filter cargo orders by trip ID, 
+    // if not directly supported by API, we might need to filter client-side or ask for API update.
+    // Based on typical patterns, we might pass tripId as a param.
+    // If the list API doesn't support tripId, we might need to rely on the backend to provide it.
+    // For now, I'll try passing tripId.
+    apisystemdzbcCargoOrderlist({ 
+        tripId: tripId,
+        pageSize: 100 
+    }).then(res => {
+        if (res.code == 200) {
+            cargoList.value = res.rows
+        }
+        cargoLoading.value = false
+    }).catch(err => {
+        console.log(err)
+        cargoLoading.value = false
+    })
+}
+
+const cancelCargoOrder = (row) => {
+    ElMessageBox.confirm(
+        '确定要取消该带货订单吗?',
+        '提示',
+        {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+        }
+    ).then(() => {
+        // Assuming status 4 is Cancelled, need to verify with backend enum usually.
+        // Or if there is a specific cancel API. The instructions said "manually cancel".
+        // Using status update API found in search: apisystemdzbcCargoOrderStatus
+        // Let's assume status '5' is cancelled or similar, or just use delete if it implies removing from trip.
+        // But "cancel order" usually means status change. 
+        // Let's assume standard status flow: 0-Pending, 1-Accepted, ... 9-Cancelled.
+        // Without specific enum, I'll try updating status to 'cancelled' (often an integer).
+        // Let's assume 4 for now (based on common practices), or wait for user feedback.
+        // Actually, user said "manually cancel this order", it might mean refund/cancel.
+        
+        apisystemdzbcCargoOrderStatus({ id: row.id, status: 4 }).then(res => {
+             ElMessage.success('操作成功')
+             loadCargoOrders(currentTripId.value)
+        })
+    }).catch(() => {})
+}
+
+const downExcell = () => {
+  excellloading.value = true
+  apisystemdzbcDriverTripexport({}).then((res: any) => {
+    let blob = new Blob([res], {
+      type: "application/x-msdownload;charset=UTF-8",
+    });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.setAttribute('download', '司机任务列表.xls');
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link)
+    window.URL.revokeObjectURL(url)
+    excellloading.value = false
+  }).catch((err: any) => {
+    console.log(err)
+    excellloading.value = false
+  })
+}
+
+const searchClick = () => {
+  pageNum.value = 1
+  getTableData()
+}
+
+const getTableData = () => {
+  loading.value = true
+  apisystemdzbcDriverTriplist({
+    tripNo: tripNo.value,
+    pageSize: 10,
+    pageNum: pageNum.value
+  }).then(res => {
+    if (res.code == 200) {
+      total.value = res.total
+      tableData.value = res.rows.map(row => {
+          // 解析 ext1 中的信息
+          if (row.ext1) {
+              try {
+                  // 注意:数据中 ext1 字段可能包含多层转义的 JSON
+                  // 第一层解析:获取包含 driverInfo, carInfo 等的 JSON 字符串
+                  // 但根据用户提供的示例,ext1 本身就是一个 JSON 对象,或者是一个包含嵌套 JSON 字符串的对象
+                  // 示例显示 row 对象有一个 ext1 属性,该属性的值是一个 JSON 字符串
+                  // 且该 JSON 字符串内部还有一个 ext1 属性,也是一个 JSON 字符串
+                  
+                  // 尝试直接解析 row.ext1
+                  let ext1Obj = JSON.parse(row.ext1)
+                  
+                  // 如果解析后的对象还有一个 ext1 属性且是字符串,说明是嵌套结构,继续解析
+                  if (ext1Obj.ext1 && typeof ext1Obj.ext1 === 'string') {
+                      try {
+                          const innerExt1 = JSON.parse(ext1Obj.ext1)
+                          // 合并到 ext1Obj 以便后续处理
+                          ext1Obj = { ...ext1Obj, ...innerExt1 }
+                      } catch (innerE) {
+                          console.error('Failed to parse inner ext1:', innerE)
+                      }
+                  }
+
+                  if (ext1Obj.carInfo && ext1Obj.carInfo.carNum) {
+                      row.carNum = ext1Obj.carInfo.carNum
+                  }
+                  if (ext1Obj.driverInfo && ext1Obj.driverInfo.userName) {
+                      row.driverName = ext1Obj.driverInfo.userName
+                  }
+                  if (ext1Obj.pathInfo && ext1Obj.pathInfo.name) {
+                      row.pathName = ext1Obj.pathInfo.name
+                  }
+              } catch (e) {
+                  console.error('Failed to parse ext1 for row:', row.id, e)
+              }
+          }
+          return row
+      })
+    }
+    loading.value = false
+  }).catch(err => {
+    console.log(err)
+    loading.value = false
+  })
+}
+
+const deleteItem = (id) => {
+  ElMessageBox.confirm(
+    '确定要删除该任务吗?',
+    '提示',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(() => {
+      apisystemdzbcDriverTripDel({ id }).then((res: any) => {
+        getTableData()
+        ElMessage({
+          message: '操作成功',
+          type: 'success',
+          duration: 3 * 1000
+        });
+      })
+    })
+    .catch(() => {
+    })
+}
+
+const openDialog = (row = null) => {
+    if (row) {
+        dialogTitle.value = '编辑司机任务'
+        Object.assign(ruleForm, row)
+    } else {
+        dialogTitle.value = '新增司机任务'
+        Object.assign(ruleForm, {
+            id: '',
+            tripNo: '',
+            pathId: '',
+            driverId: '',
+            carId: '',
+            startTime: '',
+            endTime: '',
+            remark: ''
+        })
+    }
+    dialogVisible.value = true
+}
+
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      if (ruleForm.id) {
+        apisystemdzbcDriverTripUpdate(ruleForm).then(() => {
+            ElMessage.success('操作成功')
+            dialogVisible.value = false
+            getTableData()
+        })
+      } else {
+        apisystemdzbcDriverTripAdd(ruleForm).then(() => {
+            ElMessage.success('操作成功')
+            dialogVisible.value = false
+            getTableData()
+        })
+      }
+    }
+  })
+}
+
+onMounted(() => {
+  getTableData()
+})
+
+</script>
+<template>
+  <div>
+    <div class="common-top">
+      <div class="left-part">
+        <div class="title">
+          司机任务管理
+        </div>
+        <div class="sub-title">
+          调度和管理司机任务
+        </div>
+      </div>
+       <div class="right-part">
+          <!-- <el-button type="primary" :icon="Plus" @click="openDialog()">新增任务</el-button> -->
+       </div>
+    </div>
+
+    <div class="common-content">
+      <div class="common-search-box">
+        <div class="left-part">
+          <el-input v-model="tripNo" placeholder="任务编号" style="width:260px"></el-input>
+          <el-button @click="searchClick" style="margin-left:10px">筛选</el-button>
+        </div>
+        <div class="right-part">
+          <el-button :loading="excellloading" @click="downExcell" :icon="Download">{{ excellloading ? '正在导出' : '导出'
+            }}</el-button>
+        </div>
+      </div>
+      <el-table element-loading-text='加载中' header-row-class-name="reset-gray-head" :data="tableData" style="width: 100%"
+        v-loading="loading">
+        <el-table-column prop="tripNo" label="任务编号" width="180" />
+        <el-table-column prop="pathName" label="路线名称" />
+        <el-table-column prop="driverName" label="司机" />
+        <el-table-column prop="carNum" label="车牌号" />
+        <el-table-column prop="startTime" label="出发时间" width="180" />
+        <el-table-column prop="status" label="状态">
+          <template #default="scope">
+            <el-tag v-if="scope.row.status == 0" type="info">待发车</el-tag>
+            <el-tag v-if="scope.row.status == 1" type="primary">运行中</el-tag>
+            <el-tag v-if="scope.row.status == 2" type="success">已完成</el-tag>
+            <el-tag v-if="scope.row.status == 3" type="info">已取消</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="250" fixed="right">
+          <template #default="scope">
+             <el-button type="warning" link size="small" :icon="Box" @click="openCargoDialog(scope.row)">带货订单</el-button>
+             <!-- <el-button type="primary" link size="small" @click="openDialog(scope.row)">编辑</el-button> -->
+             <el-button type="danger" link size="small" @click="deleteItem(scope.row.id)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="common-page-wrap">
+        <div class="left-part">
+          <span>共{{ total }}条记录 </span>
+        </div>
+        <div class="right-part">
+          <el-pagination v-model:current-page="pageNum" @current-change="getTableData" background
+            layout="prev, pager, next" :total="total" />
+        </div>
+      </div>
+    </div>
+
+     <el-dialog
+          v-model="dialogVisible"
+          :title="dialogTitle"
+          width="600"
+        >
+        <el-form
+          ref="ruleFormRef"
+          :model="ruleForm"
+          label-position="top"
+          :rules="rules"
+          label-width="auto"
+          :size="formSize"
+          status-icon
+        >
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="任务编号" prop="tripNo">
+                <el-input v-model="ruleForm.tripNo" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+               <el-form-item label="出发时间" prop="startTime">
+                 <el-date-picker
+                    v-model="ruleForm.startTime"
+                    type="datetime"
+                    placeholder="选择出发时间"
+                    value-format="YYYY-MM-DD HH:mm:ss"
+                    style="width: 100%"
+                  />
+               </el-form-item>
+            </el-col>
+            <el-col :span="24">
+              <el-form-item label="备注" prop="remark">
+                <el-input v-model="ruleForm.remark" type="textarea" />
+              </el-form-item>
+            </el-col>
+             <!-- 
+                Note: In a real implementation, we would need Select components for Path, Driver, and Car.
+                Since I don't have the list APIs for those ready in this context (although they exist in api.js),
+                I'm skipping them for simplicity or would need to add ID inputs.
+                For now, I'll assume they might be pre-filled or managed elsewhere, or just add ID inputs as placeholders.
+             -->
+             <el-col :span="8">
+                 <el-form-item label="路线ID" prop="pathId">
+                    <el-input v-model="ruleForm.pathId" />
+                 </el-form-item>
+             </el-col>
+             <el-col :span="8">
+                 <el-form-item label="司机ID" prop="driverId">
+                    <el-input v-model="ruleForm.driverId" />
+                 </el-form-item>
+             </el-col>
+             <el-col :span="8">
+                 <el-form-item label="车辆ID" prop="carId">
+                    <el-input v-model="ruleForm.carId" />
+                 </el-form-item>
+             </el-col>
+          </el-row>
+        </el-form>
+          <template #footer>
+            <div class="dialog-footer">
+              <el-button @click="dialogVisible = false" :icon="Close">取消</el-button>
+              <el-button type="primary" :icon="Check" @click="submitForm(ruleFormRef)">
+                确认
+              </el-button>
+            </div>
+          </template>
+        </el-dialog>
+
+        <!-- Cargo Orders Dialog -->
+        <el-dialog v-model="cargoDialogVisible" title="随车带货订单" width="800px">
+            <el-table :data="cargoList" border style="width: 100%" v-loading="cargoLoading">
+                <el-table-column prop="orderNo" label="订单编号" width="180" />
+                <el-table-column prop="senderName" label="发货人" width="100" />
+                <el-table-column prop="receiverName" label="收货人" width="100" />
+                <el-table-column prop="goodsName" label="物品" />
+                <el-table-column prop="price" label="价格(元)">
+                    <template #default="scope">
+                        {{ (scope.row.price / 100).toFixed(2) }}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="status" label="状态" width="100">
+                    <template #default="scope">
+                        <el-tag v-if="scope.row.status == 0">待支付</el-tag>
+                        <el-tag v-else-if="scope.row.status == 1" type="success">已支付</el-tag>
+                        <el-tag v-else-if="scope.row.status == 2" type="warning">运输中</el-tag>
+                        <el-tag v-else-if="scope.row.status == 3" type="success">已完成</el-tag>
+                        <el-tag v-else-if="scope.row.status == 4" type="info">已取消</el-tag>
+                        <el-tag v-else type="info">{{ scope.row.status }}</el-tag>
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作" width="100" fixed="right">
+                    <template #default="scope">
+                        <el-button 
+                            v-if="scope.row.status != 4 && scope.row.status != 3"
+                            type="danger" 
+                            link 
+                            size="small" 
+                            @click="cancelCargoOrder(scope.row)"
+                        >
+                            取消订单
+                        </el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </el-dialog>
+  </div>
+</template>
+
+<style lang="scss">
+.reset-gray-head {
+  background: #f3f4f6;
+
+  .el-table__cell,
+  th {
+    background: #f3f4f6 !important;
+  }
+
+}
+</style>
+
+<style lang="scss" scoped>
+.common-top {
+  display: flex;
+  justify-content: space-between;
+}
+
+.common-page-wrap {
+  padding: 10px 10px 10px 10px;
+  display: flex;
+  justify-content: space-between;
+}
+
+.sub-title {
+  color: #4B5563;
+  font-size: 16px;
+  margin-bottom: 24px;
+}
+
+.title {
+  color: #1F2937;
+  font-size: 24px;
+  font-weight: 600;
+}
+
+.common-content {
+  background: #fff;
+
+  .common-search-box {
+    padding: 10px 10px 10px 10px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}
+</style>

+ 366 - 0
src/views/feedbackman/index.vue

@@ -0,0 +1,366 @@
+<script setup lang="ts">
+import { apisystemdzbcFeedbacklist, apisystemdzbcFeedbackexport, apisystemdzbcFeedbackDel, apisystemdzbcFeedbackReply, apisystemdzbcFeedbackSubmit } from '../../request/api.js'
+import type { ComponentSize, FormInstance, FormRules } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { ref, onMounted, reactive } from 'vue'
+import { Search, Download, Close, Check, Plus } from "@element-plus/icons-vue";
+
+let userName = ref('')
+let total = ref(0)
+let pageNum = ref(1)
+let loading = ref(true)
+let excellloading = ref(false)
+const tableData = ref([])
+
+// Reply Dialog
+let dialogVisible = ref(false)
+let currentId = ref(null)
+let replyContent = ref('')
+
+// Add Feedback Dialog
+let addDialogVisible = ref(false)
+const addFormRef = ref<FormInstance>()
+const addForm = reactive({
+    content: '',
+    type: 1, // 1-问题, 2-建议
+    images: [] // To handle file upload if needed, but for now simple text
+})
+const addRules = reactive<FormRules>({
+    content: [{ required: true, message: '请输入反馈内容', trigger: 'blur' }],
+    type: [{ required: true, message: '请选择反馈类型', trigger: 'change' }]
+})
+
+const getImageList = (row: any) => {
+  let urls: string[] = []
+  if (row.imageUrls) {
+    urls = row.imageUrls.split(',')
+  } else if (row.images) {
+    if (typeof row.images === 'string') {
+      urls = row.images.split(',')
+    } else if (Array.isArray(row.images)) {
+      urls = row.images
+    }
+  }
+  return urls.filter(url => url).map(url => {
+    if (url.startsWith('http') || url.startsWith('https')) {
+      return url
+    }
+    // @ts-ignore
+    return window.baseUrl + url
+  })
+}
+
+const downExcell = () => {
+  excellloading.value = true
+  apisystemdzbcFeedbackexport({}).then((res: any) => {
+    let blob = new Blob([res], {
+      type: "application/x-msdownload;charset=UTF-8",
+    });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.setAttribute('download', '问题建议列表.xls');
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link)
+    window.URL.revokeObjectURL(url)
+    excellloading.value = false
+  }).catch((err: any) => {
+    console.log(err)
+    excellloading.value = false
+  })
+}
+
+const searchClick = () => {
+  pageNum.value = 1
+  getTableData()
+}
+
+const getTableData = () => {
+  loading.value = true
+  apisystemdzbcFeedbacklist({
+    userName: userName.value,
+    pageSize: 10,
+    pageNum: pageNum.value
+  }).then(res => {
+    if (res.code == 200) {
+      total.value = res.total
+      tableData.value = res.rows.map((row: any) => {
+        return {
+          ...row,
+          displayImages: getImageList(row)
+        }
+      })
+    }
+    loading.value = false
+  }).catch(err => {
+    console.log(err)
+    loading.value = false
+  })
+}
+
+const deleteItem = (id) => {
+  ElMessageBox.confirm(
+    '确定要删除该记录吗?',
+    '提示',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(() => {
+      apisystemdzbcFeedbackDel({ id }).then((res: any) => {
+        getTableData()
+        ElMessage({
+          message: '操作成功',
+          type: 'success',
+          duration: 3 * 1000
+        });
+      })
+    })
+    .catch(() => {
+    })
+}
+
+const openReplyDialog = (row) => {
+    currentId.value = row.id
+    replyContent.value = row.replyContent || ''
+    dialogVisible.value = true
+}
+
+const submitReply = () => {
+    if (!replyContent.value) {
+        ElMessage.warning('请输入回复内容')
+        return
+    }
+    apisystemdzbcFeedbackReply({
+        id: currentId.value,
+        replyContent: replyContent.value
+    }).then(res => {
+        ElMessage.success('回复成功')
+        dialogVisible.value = false
+        getTableData()
+    })
+}
+
+const openAddDialog = () => {
+    addForm.content = ''
+    addForm.type = 1
+    addForm.images = []
+    addDialogVisible.value = true
+}
+
+const submitAddForm = async (formEl: FormInstance | undefined) => {
+    if (!formEl) return
+    await formEl.validate((valid, fields) => {
+        if (valid) {
+            const formData = new FormData()
+            formData.append('content', addForm.content)
+            formData.append('type', addForm.type.toString())
+            
+            if (addForm.images && addForm.images.length > 0) {
+                addForm.images.forEach((file: any) => {
+                    if (file.raw) {
+                        formData.append('files', file.raw)
+                    }
+                })
+            }
+
+            apisystemdzbcFeedbackSubmit(formData).then(res => {
+                ElMessage.success('提交成功')
+                addDialogVisible.value = false
+                getTableData()
+            })
+        }
+    })
+}
+
+onMounted(() => {
+  getTableData()
+})
+
+</script>
+<template>
+  <div>
+    <div class="common-top">
+      <div class="left-part">
+        <div class="title">
+          问题建议管理
+        </div>
+        <div class="sub-title">
+          查看和回复用户反馈
+        </div>
+      </div>
+      <div class="right-part">
+          <el-button type="primary" :icon="Plus" @click="openAddDialog">新增反馈</el-button>
+      </div>
+    </div>
+
+    <div class="common-content">
+      <div class="common-search-box">
+        <div class="left-part">
+          <el-input v-model="userName" placeholder="用户姓名" style="width:260px"></el-input>
+          <el-button @click="searchClick" style="margin-left:10px">筛选</el-button>
+        </div>
+        <div class="right-part">
+          <el-button :loading="excellloading" @click="downExcell" :icon="Download">{{ excellloading ? '正在导出' : '导出'
+            }}</el-button>
+        </div>
+      </div>
+      <el-table element-loading-text='加载中' header-row-class-name="reset-gray-head" :data="tableData" style="width: 100%"
+        v-loading="loading">
+        <el-table-column prop="id" label="编号" width="80" />
+        <el-table-column prop="userName" label="用户姓名" width="120" />
+        <el-table-column prop="userPhone" label="用户电话" width="120" />
+        <el-table-column prop="type" label="类型" width="100">
+            <template #default="scope">
+                <el-tag v-if="scope.row.type == 1" type="danger">问题</el-tag>
+                <el-tag v-if="scope.row.type == 2" type="primary">建议</el-tag>
+            </template>
+        </el-table-column>
+        <el-table-column label="图片" width="180">
+            <template #default="scope">
+                <div v-if="scope.row.displayImages && scope.row.displayImages.length > 0">
+                    <el-image
+                        v-for="(url, index) in scope.row.displayImages"
+                        :key="index"
+                        :src="url"
+                        :preview-src-list="scope.row.displayImages"
+                        style="width: 50px; height: 50px; margin-right: 5px"
+                        fit="cover"
+                        preview-teleported
+                    />
+                </div>
+                <span v-else>无</span>
+            </template>
+        </el-table-column>
+        <el-table-column prop="content" label="反馈内容" show-overflow-tooltip />
+        <el-table-column prop="status" label="状态" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.status == 0" type="info">待处理</el-tag>
+            <el-tag v-if="scope.row.status == 1" type="warning">处理中</el-tag>
+            <el-tag v-if="scope.row.status == 2" type="success">已完成</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="replyContent" label="回复内容" show-overflow-tooltip />
+        <el-table-column label="操作" width="150" fixed="right">
+          <template #default="scope">
+             <el-button type="primary" link size="small" @click="openReplyDialog(scope.row)">回复</el-button>
+             <el-button type="danger" link size="small" @click="deleteItem(scope.row.id)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="common-page-wrap">
+        <div class="left-part">
+          <span>共{{ total }}条记录 </span>
+        </div>
+        <div class="right-part">
+          <el-pagination v-model:current-page="pageNum" @current-change="getTableData" background
+            layout="prev, pager, next" :total="total" />
+        </div>
+      </div>
+    </div>
+
+    <el-dialog v-model="dialogVisible" title="回复反馈" width="500px">
+        <el-input
+            v-model="replyContent"
+            :rows="4"
+            type="textarea"
+            placeholder="请输入回复内容"
+        />
+        <template #footer>
+            <span class="dialog-footer">
+                <el-button @click="dialogVisible = false">取消</el-button>
+                <el-button type="primary" @click="submitReply">确认</el-button>
+            </span>
+        </template>
+    </el-dialog>
+
+    <el-dialog v-model="addDialogVisible" title="新增反馈" width="500px">
+        <el-form :model="addForm" :rules="addRules" ref="addFormRef" label-width="80px">
+            <el-form-item label="类型" prop="type">
+                <el-radio-group v-model="addForm.type">
+                    <el-radio :label="1">问题</el-radio>
+                    <el-radio :label="2">建议</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item label="内容" prop="content">
+                <el-input
+                    v-model="addForm.content"
+                    :rows="4"
+                    type="textarea"
+                    placeholder="请输入反馈内容"
+                />
+            </el-form-item>
+            <el-form-item label="图片">
+                <el-upload
+                    v-model:file-list="addForm.images"
+                    action="#"
+                    list-type="picture-card"
+                    :auto-upload="false"
+                    :limit="3"
+                    accept="image/*"
+                >
+                    <el-icon><Plus /></el-icon>
+                </el-upload>
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <span class="dialog-footer">
+                <el-button @click="addDialogVisible = false">取消</el-button>
+                <el-button type="primary" @click="submitAddForm(addFormRef)">提交</el-button>
+            </span>
+        </template>
+    </el-dialog>
+  </div>
+</template>
+
+<style lang="scss">
+.reset-gray-head {
+  background: #f3f4f6;
+
+  .el-table__cell,
+  th {
+    background: #f3f4f6 !important;
+  }
+
+}
+</style>
+
+<style lang="scss" scoped>
+.common-top {
+  display: flex;
+  justify-content: space-between;
+}
+
+.common-page-wrap {
+  padding: 10px 10px 10px 10px;
+  display: flex;
+  justify-content: space-between;
+}
+
+.sub-title {
+  color: #4B5563;
+  font-size: 16px;
+  margin-bottom: 24px;
+}
+
+.title {
+  color: #1F2937;
+  font-size: 24px;
+  font-weight: 600;
+}
+
+.common-content {
+  background: #fff;
+
+  .common-search-box {
+    padding: 10px 10px 10px 10px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}
+</style>

+ 2 - 0
src/views/login/index.vue

@@ -138,6 +138,8 @@ onMounted(()=>{
             <div style="padding:10px 0 20px 0;">
             <div style="padding:10px 0 20px 0;">
                 <span style="margin-right:5px">首次使用吗?</span>
                 <span style="margin-right:5px">首次使用吗?</span>
                 <span style="color:#326cec">联系管理员</span>
                 <span style="color:#326cec">联系管理员</span>
+                <span style="margin: 0 10px; color: #ccc">|</span>
+                <span style="color:#326cec; cursor: pointer" @click="router.push('/agreement')">用户协议</span>
             </div>
             </div>
                
                
             </div>
             </div>

+ 738 - 0
src/views/multisitepathman/index.vue

@@ -0,0 +1,738 @@
+<script setup lang="ts">
+import { 
+    apisystemdzbcMultiSitePathlist, apisystemdzbcMultiSitePathexport, apisystemdzbcMultiSitePathDel, apisystemdzbcMultiSitePathAdd, apisystemdzbcMultiSitePathUpdate,
+    apisystemdzbcPathSiteByPathId, apisystemdzbcPathSiteAdd, apisystemdzbcPathSiteDel,
+    apisystemdzbcSitePriceByPathId, apisystemdzbcSitePriceAdd, apisystemdzbcSitePriceDel,
+    apisystemdzbcSitelist, // Import site list API
+    apisystemdzbcArealist // Import area list API
+} from '../../request/api.js'
+import type { ComponentSize, FormInstance, FormRules } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { ref, onMounted, reactive } from 'vue'
+import { Search, Download, Close, Check, Plus, Setting, Money, DataAnalysis } from "@element-plus/icons-vue";
+
+let name = ref('')
+let total = ref(0)
+let pageNum = ref(1)
+let loading = ref(true)
+let excellloading = ref(false)
+const tableData = ref([])
+
+// All Sites for Select
+const allSites = ref([])
+const sitesLoading = ref(false)
+const areaMap = ref({})
+
+const loadAreas = () => {
+    apisystemdzbcArealist({ pageSize: 1000 }).then(res => {
+        if (res.code === 200) {
+            res.rows.forEach(area => {
+                areaMap.value[area.id] = area.name
+            })
+        }
+    })
+}
+
+const loadAllSites = () => {
+    if (allSites.value.length > 0) return
+    sitesLoading.value = true
+    apisystemdzbcSitelist({ pageSize: 1000 }).then(res => {
+        if (res.code === 200) {
+            allSites.value = res.rows
+        }
+        sitesLoading.value = false
+    }).catch(() => {
+            sitesLoading.value = false
+    })
+}
+
+// Helper to get site name
+const getSiteName = (siteId) => {
+    const site = allSites.value.find(s => s.id === siteId)
+    if (site) {
+        return site.name + (site.areaId && areaMap.value[site.areaId] ? ' (' + areaMap.value[site.areaId] + ')' : '')
+    }
+    return siteId
+}
+
+let dialogVisible = ref(false)
+let dialogTitle = ref('新增多站点路线')
+const formSize = ref<ComponentSize>('default')
+const ruleFormRef = ref<FormInstance>()
+const ruleForm = reactive({
+    id: '',
+    name: '',
+    remark: ''
+})
+
+const rules = reactive<FormRules>({
+    name: [{ required: true, message: '请输入路线名称', trigger: 'blur' }],
+})
+
+// Site Management
+let siteDialogVisible = ref(false)
+let currentPathId = ref('')
+const siteList = ref([])
+const siteForm = reactive({
+    pathId: '',
+    siteId: '', // Ideally Select
+    siteOrder: 0, // Changed from 'sort' to 'siteOrder'
+    type: 1 // 1-站点, 2-区域
+})
+
+// Price Management
+const priceDialogVisible = ref(false)
+const priceList = ref([])
+const pathSites = ref([]) // Store sites for current path
+const priceForm = reactive({
+    pathId: '',
+    fromSiteId: '', // Changed from 'startSiteId'
+    toSiteId: '',   // Changed from 'endSiteId'
+    price: 0,
+    cargoPrice: 0 // 带货价格
+})
+
+// Price Matrix
+const matrixDialogVisible = ref(false)
+const matrixSites = ref([])
+const matrixPrices = ref({})
+const matrixCargoPrices = ref({}) // 带货价格矩阵
+
+const downExcell = () => {
+  excellloading.value = true
+  apisystemdzbcMultiSitePathexport({}).then((res: any) => {
+    let blob = new Blob([res], {
+      type: "application/x-msdownload;charset=UTF-8",
+    });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.setAttribute('download', '多站点路线列表.xls');
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link)
+    window.URL.revokeObjectURL(url)
+    excellloading.value = false
+  }).catch((err: any) => {
+    console.log(err)
+    excellloading.value = false
+  })
+}
+
+const searchClick = () => {
+  pageNum.value = 1
+  getTableData()
+}
+
+const getTableData = () => {
+  loading.value = true
+  apisystemdzbcMultiSitePathlist({
+    name: name.value,
+    pageSize: 10,
+    pageNum: pageNum.value
+  }).then(async res => {
+    if (res.code == 200) {
+      total.value = res.total
+      const rows = res.rows
+
+      // Ensure all sites are loaded for mapping
+      if (allSites.value.length === 0) {
+          try {
+              const siteRes = await apisystemdzbcSitelist({ pageSize: 1000 })
+              if (siteRes.code === 200) allSites.value = siteRes.rows
+           } catch(e) {
+               console.error('Failed to load sites for mapping', e)
+           }
+      }
+
+      // Fetch sites for each path to determine start/end
+      const promises = rows.map(async (row) => {
+          try {
+              const siteRes = await apisystemdzbcPathSiteByPathId({ pathId: row.id })
+              if (siteRes.code === 200 && siteRes.data && siteRes.data.length > 0) {
+                  // Sort by siteOrder
+                  const sortedSites = siteRes.data.sort((a, b) => a.siteOrder - b.siteOrder)
+                  const startSiteId = sortedSites[0].siteId
+                  const endSiteId = sortedSites[sortedSites.length - 1].siteId
+                  
+                  row.startSiteName = getSiteName(startSiteId)
+                  row.endSiteName = getSiteName(endSiteId)
+              } else {
+                  row.startSiteName = '-'
+                  row.endSiteName = '-'
+              }
+          } catch (e) {
+              console.error(e)
+              row.startSiteName = '-'
+              row.endSiteName = '-'
+          }
+          return row
+      })
+      
+      tableData.value = await Promise.all(promises)
+    }
+    loading.value = false
+  }).catch(err => {
+    console.log(err)
+    loading.value = false
+  })
+}
+
+const deleteItem = (id) => {
+  ElMessageBox.confirm(
+    '确定要删除该路线吗?',
+    '提示',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(() => {
+      apisystemdzbcMultiSitePathDel({ id }).then((res: any) => {
+        getTableData()
+        ElMessage({
+          message: '操作成功',
+          type: 'success',
+          duration: 3 * 1000
+        });
+      })
+    })
+    .catch(() => {
+    })
+}
+
+const openDialog = (row = null) => {
+    if (row) {
+        dialogTitle.value = '编辑多站点路线'
+        Object.assign(ruleForm, row)
+    } else {
+        dialogTitle.value = '新增多站点路线'
+        Object.assign(ruleForm, {
+            id: '',
+            name: '',
+            remark: ''
+        })
+    }
+    dialogVisible.value = true
+}
+
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      if (ruleForm.id) {
+        apisystemdzbcMultiSitePathUpdate(ruleForm).then(() => {
+            ElMessage.success('操作成功')
+            dialogVisible.value = false
+            getTableData()
+        })
+      } else {
+        apisystemdzbcMultiSitePathAdd(ruleForm).then(() => {
+            ElMessage.success('操作成功')
+            dialogVisible.value = false
+            getTableData()
+        })
+      }
+    }
+  })
+}
+
+// --- Site Management Functions ---
+// --- Site Management Functions ---
+const openSiteDialog = (row) => {
+    currentPathId.value = row.id
+    siteForm.pathId = row.id
+    loadSites()
+    loadAllSites() // Load sites once if needed
+    siteDialogVisible.value = true
+}
+
+const loadSites = () => {
+    apisystemdzbcPathSiteByPathId({ pathId: currentPathId.value }).then(res => {
+        if (res.code === 200) {
+            siteList.value = res.data
+        }
+    })
+}
+
+const addSite = () => {
+    if (!siteForm.siteId) {
+        ElMessage.warning('请输入站点ID')
+        return
+    }
+    apisystemdzbcPathSiteAdd(siteForm).then(() => {
+        ElMessage.success('添加成功')
+        loadSites()
+        siteForm.siteId = '' // Reset input
+        siteForm.siteOrder++
+    })
+}
+
+const deleteSite = async (row) => {
+    try {
+        await ElMessageBox.confirm('确定要移除该站点吗?这将同时删除与该站点相关的所有价格设置。', '提示', {
+            type: 'warning'
+        })
+        
+        // 1. Fetch prices to identify related ones
+        const priceRes = await apisystemdzbcSitePriceByPathId({ pathId: currentPathId.value })
+        if (priceRes.code === 200) {
+            const pricesToDelete = priceRes.data.filter(p => p.fromSiteId === row.siteId || p.toSiteId === row.siteId)
+            
+            // 2. Delete related prices
+            if (pricesToDelete.length > 0) {
+                await Promise.all(pricesToDelete.map(p => apisystemdzbcSitePriceDel({ id: p.id })))
+            }
+        }
+
+        // 3. Delete the site
+        await apisystemdzbcPathSiteDel({ id: row.id })
+        ElMessage.success('删除成功')
+        loadSites()
+    } catch (e) {
+        if (e !== 'cancel') {
+             console.error(e)
+             ElMessage.error('操作失败')
+        }
+    }
+}
+
+// --- Price Management Functions ---
+const openPriceDialog = (row) => {
+    currentPathId.value = row.id
+    priceForm.pathId = row.id
+    loadPrices()
+    
+    // Fetch sites for this path
+    apisystemdzbcPathSiteByPathId({ pathId: row.id }).then(res => {
+        if (res.code === 200) {
+            pathSites.value = res.data.map(site => {
+                // Find full site info from allSites if available, otherwise just use ID
+                const fullSite = allSites.value.find(s => s.id === site.siteId)
+                return {
+                    id: site.siteId,
+                    name: fullSite ? fullSite.name + (fullSite.areaId && areaMap.value[fullSite.areaId] ? ' (' + areaMap.value[fullSite.areaId] + ')' : '') : site.siteId
+                }
+            })
+            // If allSites not loaded yet, try loading it to get names
+            if (allSites.value.length === 0) {
+                 loadAllSites()
+            }
+        }
+    })
+
+    priceDialogVisible.value = true
+}
+
+const loadPrices = () => {
+    apisystemdzbcSitePriceByPathId({ pathId: currentPathId.value }).then(res => {
+        if (res.code === 200) {
+            priceList.value = res.data
+        }
+    })
+}
+
+const addPrice = () => {
+    if (!priceForm.fromSiteId || !priceForm.toSiteId) {
+        ElMessage.warning('请输入起始和结束站点ID')
+        return
+    }
+    
+    let ext2 = {}
+    if(priceForm.cargoPrice){
+        ext2['cargoPrice'] = priceForm.cargoPrice * 100
+    }
+    
+    apisystemdzbcSitePriceAdd({ 
+        ...priceForm, 
+        price: priceForm.price * 100,
+        ext2: JSON.stringify(ext2)
+    }).then(() => {
+        ElMessage.success('添加成功')
+        loadPrices()
+        // Reset price input but keep sites potentially
+        priceForm.price = 0 
+        priceForm.cargoPrice = 0
+    })
+}
+
+const deletePrice = (id) => {
+    apisystemdzbcSitePriceDel({ id }).then(() => {
+        ElMessage.success('删除成功')
+        loadPrices()
+    })
+}
+
+const openMatrixDialog = async (row) => {
+    try {
+        matrixSites.value = []
+        matrixPrices.value = {}
+        matrixCargoPrices.value = {}
+        
+        // 1. Fetch sites
+        const siteRes = await apisystemdzbcPathSiteByPathId({ pathId: row.id })
+        if (siteRes.code === 200) {
+            // Sort by siteOrder
+            const sites = siteRes.data.sort((a, b) => a.siteOrder - b.siteOrder)
+            matrixSites.value = sites.map(s => {
+                const fullSite = allSites.value.find(as => as.id === s.siteId)
+                return {
+                    id: s.siteId,
+                    name: fullSite ? fullSite.name : s.siteId
+                }
+            })
+             if (allSites.value.length === 0) {
+                 loadAllSites()
+            }
+        }
+
+        // 2. Fetch prices
+        const priceRes = await apisystemdzbcSitePriceByPathId({ pathId: row.id })
+        if (priceRes.code === 200) {
+            priceRes.data.forEach(p => {
+                const key = `${p.fromSiteId}-${p.toSiteId}`;
+                matrixPrices.value[key] = p.price;
+                
+                // 解析带货价格
+                if(p.ext2){
+                    try {
+                        const ext2 = JSON.parse(p.ext2);
+                        if(ext2.cargoPrice){
+                            matrixCargoPrices.value[key] = ext2.cargoPrice;
+                        }
+                    } catch (e) {
+                        console.error('Error parsing ext2:', e);
+                    }
+                }
+            })
+        }
+
+        matrixDialogVisible.value = true
+    } catch (e) {
+        console.error(e)
+        ElMessage.error('加载数据失败')
+    }
+}
+
+const getMatrixPrice = (fromId, toId) => {
+    const price = matrixPrices.value[`${fromId}-${toId}`]
+    const cargoPrice = matrixCargoPrices.value[`${fromId}-${toId}`]
+    
+    let text = ''
+    if(price) text += `客:${(price / 100).toFixed(0)}`
+    if(cargoPrice) {
+        if(text) text += ' / '
+        text += `货:${(cargoPrice / 100).toFixed(0)}`
+    }
+    return text
+}
+
+
+onMounted(() => {
+  getTableData()
+  loadAreas()
+})
+
+</script>
+<template>
+  <div>
+    <div class="common-top">
+      <div class="left-part">
+        <div class="title">
+          多站点路线管理
+        </div>
+        <div class="sub-title">
+          管理支持多站点的复杂路线
+        </div>
+      </div>
+       <div class="right-part">
+          <el-button type="primary" :icon="Plus" @click="openDialog()">新增路线</el-button>
+       </div>
+    </div>
+
+    <div class="common-content">
+      <div class="common-search-box">
+        <div class="left-part">
+          <el-input v-model="name" placeholder="路线名称" style="width:260px"></el-input>
+          <el-button @click="searchClick" style="margin-left:10px">筛选</el-button>
+        </div>
+        <div class="right-part">
+          <el-button :loading="excellloading" @click="downExcell" :icon="Download">{{ excellloading ? '正在导出' : '导出'
+            }}</el-button>
+        </div>
+      </div>
+      <el-table element-loading-text='加载中' header-row-class-name="reset-gray-head" :data="tableData" style="width: 100%"
+        v-loading="loading">
+        <el-table-column prop="name" label="路线名称" />
+        <el-table-column prop="startSiteName" label="起始站点" width="180" />
+        <el-table-column prop="endSiteName" label="目的站点" width="180" />
+        <el-table-column label="操作" width="350" fixed="right">
+          <template #default="scope">
+             <el-button type="success" link size="small" :icon="Setting" @click="openSiteDialog(scope.row)">站点管理</el-button>
+             <el-button type="warning" link size="small" :icon="Money" @click="openPriceDialog(scope.row)">价格管理</el-button>
+             <el-button type="info" link size="small" :icon="DataAnalysis" @click="openMatrixDialog(scope.row)">价格梯度图</el-button>
+             <el-button type="primary" link size="small" @click="openDialog(scope.row)">编辑</el-button>
+             <el-button type="danger" link size="small" @click="deleteItem(scope.row.id)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="common-page-wrap">
+        <div class="left-part">
+          <span>共{{ total }}条记录 </span>
+        </div>
+        <div class="right-part">
+          <el-pagination v-model:current-page="pageNum" @current-change="getTableData" background
+            layout="prev, pager, next" :total="total" />
+        </div>
+      </div>
+    </div>
+
+     <el-dialog
+          v-model="dialogVisible"
+          :title="dialogTitle"
+          width="600"
+        >
+        <el-form
+          ref="ruleFormRef"
+          :model="ruleForm"
+          label-position="top"
+          :rules="rules"
+          label-width="auto"
+          :size="formSize"
+          status-icon
+        >
+          <el-row :gutter="20">
+            <el-col :span="24">
+              <el-form-item label="路线名称" prop="name">
+                <el-input v-model="ruleForm.name" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="24">
+              <el-form-item label="备注" prop="remark">
+                <el-input v-model="ruleForm.remark" type="textarea" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+          <template #footer>
+            <div class="dialog-footer">
+              <el-button @click="dialogVisible = false" :icon="Close">取消</el-button>
+              <el-button type="primary" :icon="Check" @click="submitForm(ruleFormRef)">
+                确认
+              </el-button>
+            </div>
+          </template>
+        </el-dialog>
+
+        <!-- Site Management Dialog -->
+        <el-dialog v-model="siteDialogVisible" title="站点管理" width="700px">
+            <div class="add-section" style="margin-bottom: 20px; display: flex; gap: 10px;">
+                <el-select
+                    v-model="siteForm.siteId"
+                    filterable
+                    placeholder="请输入站点名称搜索"
+                    :loading="sitesLoading"
+                    style="width: 200px"
+                    @focus="loadAllSites"
+                >
+                    <el-option
+                        v-for="item in allSites"
+                        :key="item.id"
+                        :label="item.name + (item.areaId && areaMap[item.areaId] ? ' (' + areaMap[item.areaId] + ')' : '')"
+                        :value="item.id"
+                    />
+                </el-select>
+                <el-input v-model="siteForm.siteOrder" placeholder="排序" type="number" style="width: 100px" />
+                <el-button type="primary" @click="addSite">添加站点</el-button>
+            </div>
+            <el-table :data="siteList" border style="width: 100%">
+                <el-table-column label="站点" width="200">
+                    <template #default="scope">
+                        {{ getSiteName(scope.row.siteId) }}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="siteOrder" label="排序" width="80" />
+                <el-table-column label="操作">
+                    <template #default="scope">
+                        <el-button type="danger" link size="small" @click="deleteSite(scope.row)">移除</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </el-dialog>
+
+        <!-- Price Management Dialog -->
+        <el-dialog v-model="priceDialogVisible" title="价格管理" width="800px">
+            <div class="add-section" style="margin-bottom: 20px; display: flex; gap: 10px; align-items: center;">
+                <el-select
+                    v-model="priceForm.fromSiteId"
+                    filterable
+                    placeholder="起始站点"
+                    style="width: 200px"
+                >
+                    <el-option
+                        v-for="item in pathSites"
+                        :key="item.id"
+                        :label="item.name"
+                        :value="item.id"
+                    />
+                </el-select>
+                <span>至</span>
+                <el-select
+                    v-model="priceForm.toSiteId"
+                    filterable
+                    placeholder="结束站点"
+                    style="width: 200px"
+                >
+                    <el-option
+                        v-for="item in pathSites"
+                        :key="item.id"
+                        :label="item.name"
+                        :value="item.id"
+                    />
+                </el-select>
+                <el-input v-model="priceForm.price" placeholder="客运价格(元)" type="number" style="width: 120px" />
+                <el-input v-model="priceForm.cargoPrice" placeholder="带货价格(元)" type="number" style="width: 120px" />
+                <el-button type="primary" @click="addPrice">添加价格</el-button>
+            </div>
+            <el-table :data="priceList" border style="width: 100%">
+                <el-table-column label="起始站点">
+                    <template #default="scope">
+                        {{ getSiteName(scope.row.fromSiteId) }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="结束站点">
+                    <template #default="scope">
+                        {{ getSiteName(scope.row.toSiteId) }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="客运价格(元)">
+                    <template #default="scope">
+                        {{ (scope.row.price / 100).toFixed(2) }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="带货价格(元)">
+                    <template #default="scope">
+                         <span v-if="scope.row.ext2 && JSON.parse(scope.row.ext2).cargoPrice">
+                             {{ (JSON.parse(scope.row.ext2).cargoPrice / 100).toFixed(2) }}
+                         </span>
+                         <span v-else>-</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作">
+                    <template #default="scope">
+                        <el-button type="danger" link size="small" @click="deletePrice(scope.row.id)">删除</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </el-dialog>
+        <!-- Price Matrix Dialog -->
+        <el-dialog v-model="matrixDialogVisible" title="价格梯度图" width="80%">
+            <div class="matrix-container">
+                <table class="price-matrix">
+                    <tbody>
+                        <tr v-for="(rowSite, rowIndex) in matrixSites" :key="rowSite.id">
+                            <td v-for="(colSite, colIndex) in matrixSites" :key="colSite.id"
+                                :class="{
+                                    'diagonal-cell': rowIndex === colIndex,
+                                    'price-cell': rowIndex < colIndex,
+                                    'empty-cell': rowIndex > colIndex
+                                }"
+                            >
+                                <template v-if="rowIndex === colIndex">
+                                    {{ rowSite.name }}
+                                </template>
+                                <template v-else-if="rowIndex < colIndex">
+                                    {{ getMatrixPrice(rowSite.id, colSite.id) }}
+                                </template>
+                            </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+        </el-dialog>
+  </div>
+</template>
+
+<style lang="scss">
+.reset-gray-head {
+  background: #f3f4f6;
+
+  .el-table__cell,
+  th {
+    background: #f3f4f6 !important;
+  }
+
+}
+</style>
+
+<style lang="scss" scoped>
+.matrix-container {
+    overflow-x: auto;
+    padding: 10px;
+}
+
+.price-matrix {
+    border-collapse: collapse;
+    width: 100%;
+    
+    td {
+        border: 1px solid #000;
+        padding: 8px;
+        text-align: center;
+        min-width: 80px;
+        height: 40px;
+    }
+
+    .diagonal-cell {
+        background-color: #fff;
+        font-weight: bold;
+    }
+
+    .price-cell {
+        background-color: #fca5a5; // Light red/pink as in image
+        color: #000;
+        font-weight: 500;
+        font-size: 16px;
+    }
+
+    .empty-cell {
+        background-color: #fff;
+    }
+}
+
+.common-top {
+  display: flex;
+  justify-content: space-between;
+}
+
+.common-page-wrap {
+  padding: 10px 10px 10px 10px;
+  display: flex;
+  justify-content: space-between;
+}
+
+.sub-title {
+  color: #4B5563;
+  font-size: 16px;
+  margin-bottom: 24px;
+}
+
+.title {
+  color: #1F2937;
+  font-size: 24px;
+  font-weight: 600;
+}
+
+.common-content {
+  background: #fff;
+
+  .common-search-box {
+    padding: 10px 10px 10px 10px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}
+</style>

+ 247 - 0
src/views/weatherman/index.vue

@@ -0,0 +1,247 @@
+<script setup lang="ts">
+import { apisystemdzbcWeatherFuzhou } from '../../request/api.js'
+import { ref, onMounted } from 'vue'
+import { Sunny, Cloudy, Pouring, Lightning, MostlyCloudy } from "@element-plus/icons-vue";
+
+const weatherData = ref(null)
+const loading = ref(true)
+
+const getWeather = () => {
+    loading.value = true
+    apisystemdzbcWeatherFuzhou().then(res => {
+        if (res.code === 200) {
+            weatherData.value = res.data
+        }
+        loading.value = false
+    }).catch(err => {
+        console.error(err)
+        loading.value = false
+    })
+}
+
+onMounted(() => {
+    getWeather()
+})
+</script>
+
+<template>
+    <div class="weather-container">
+        <div class="common-top">
+            <div class="left-part">
+                <div class="title">
+                    福州天气
+                </div>
+                <div class="sub-title">
+                    实时天气信息展示
+                </div>
+            </div>
+            <div class="right-part">
+                <el-button @click="getWeather" :loading="loading">刷新</el-button>
+            </div>
+        </div>
+
+        <div class="weather-content" v-loading="loading">
+            <div v-if="weatherData && weatherData.daily && weatherData.daily.length > 0" class="weather-wrap">
+                <!-- 今日天气卡片 -->
+                <div class="weather-card">
+                    <div class="weather-header">
+                        <span class="city">{{ weatherData.location || '福州' }}</span>
+                        <span class="update-time">更新时间: {{ weatherData.updateTime || new Date().toLocaleDateString() }}</span>
+                    </div>
+                    <div class="weather-body">
+                        <div class="temp-section">
+                            <div class="current-temp">{{ weatherData.daily[0].tempMin }}~{{ weatherData.daily[0].tempMax }}°C</div>
+                            <div class="condition">{{ weatherData.daily[0].textDay }}</div>
+                        </div>
+                        <div class="detail-section">
+                            <div class="detail-item">
+                                <span class="label">湿度</span>
+                                <span class="value">{{ weatherData.daily[0].humidity || '-' }}%</span>
+                            </div>
+                            <div class="detail-item">
+                                <span class="label">风向</span>
+                                <span class="value">{{ weatherData.daily[0].windDirDay || '-' }}</span>
+                            </div>
+                            <div class="detail-item">
+                                <span class="label">风力等级</span>
+                                <span class="value">{{ weatherData.daily[0].windScaleDay || '-' }}级</span>
+                            </div>
+                            <div class="detail-item">
+                                <span class="label">能见度</span>
+                                <span class="value">{{ weatherData.daily[0].vis || '-' }}公里</span>
+                            </div>
+                            <div class="detail-item">
+                                <span class="label">云量</span>
+                                <span class="value">{{ weatherData.daily[0].cloud || '-' }}%</span>
+                            </div>
+                            <div class="detail-item">
+                                <span class="label">紫外线指数</span>
+                                <span class="value">{{ weatherData.daily[0].uvIndex || '-' }}</span>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+                <!-- 未来天气列表 -->
+                <div class="forecast-list">
+                    <div v-for="(day, index) in weatherData.daily.slice(1)" :key="index" class="forecast-item">
+                        <div class="forecast-date">{{ day.fxDate }}</div>
+                        <div class="forecast-icon">{{ day.textDay }}</div>
+                        <div class="forecast-temp">{{ day.tempMin }}~{{ day.tempMax }}°C</div>
+                    </div>
+                </div>
+            </div>
+            <div v-else class="no-data">
+                暂无天气数据
+            </div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.weather-container {
+    padding: 20px;
+}
+.common-top {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 20px;
+}
+.sub-title {
+  color: #4B5563;
+  font-size: 16px;
+  margin-bottom: 24px;
+}
+
+.title {
+  color: #1F2937;
+  font-size: 24px;
+  font-weight: 600;
+}
+
+.weather-content {
+    display: flex;
+    justify-content: center;
+    margin-top: 40px;
+}
+
+.weather-wrap {
+    width: 100%;
+    max-width: 600px;
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+}
+
+.weather-card {
+    background: linear-gradient(135deg, #6dd5ed, #2193b0);
+    color: white;
+    border-radius: 16px;
+    padding: 30px;
+    width: 100%;
+    box-shadow: 0 10px 20px rgba(0,0,0,0.2);
+}
+
+.forecast-list {
+    display: flex;
+    justify-content: space-between;
+    overflow-x: auto;
+    gap: 10px;
+    padding: 10px 0;
+}
+
+.forecast-item {
+    background: white;
+    border-radius: 12px;
+    padding: 15px;
+    min-width: 100px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    box-shadow: 0 4px 6px rgba(0,0,0,0.05);
+    
+    .forecast-date {
+        font-size: 14px;
+        color: #666;
+        margin-bottom: 8px;
+    }
+    
+    .forecast-icon {
+        font-size: 16px;
+        color: #333;
+        font-weight: 500;
+        margin-bottom: 8px;
+    }
+    
+    .forecast-temp {
+        font-size: 14px;
+        color: #2193b0;
+        font-weight: bold;
+    }
+}
+
+.weather-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-end;
+    margin-bottom: 30px;
+    .city {
+        font-size: 32px;
+        font-weight: bold;
+    }
+    .update-time {
+        font-size: 14px;
+        opacity: 0.8;
+    }
+}
+
+.weather-body {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.temp-section {
+    text-align: center;
+    margin-bottom: 30px;
+    .current-temp {
+        font-size: 80px;
+        font-weight: 200;
+        line-height: 1;
+    }
+    .condition {
+        font-size: 24px;
+        margin-top: 10px;
+    }
+}
+
+.detail-section {
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    gap: 20px;
+    width: 100%;
+    background: rgba(255,255,255,0.1);
+    padding: 20px;
+    border-radius: 12px;
+
+    .detail-item {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        .label {
+            font-size: 12px;
+            opacity: 0.8;
+            margin-bottom: 4px;
+        }
+        .value {
+            font-size: 16px;
+            font-weight: 600;
+        }
+    }
+}
+
+.no-data {
+    color: #909399;
+    font-size: 16px;
+}
+</style>

+ 12 - 0
vite.config.ts

@@ -21,6 +21,18 @@ export default defineConfig(({command})=>{
         }
         }
       }
       }
     },
     },
+
+    devServer:{
+      proxy:{
+        '/api':{
+          target:'http://127.0.0.1:8080/',
+          changeOrigin:true,
+          secure:false,
+          rewrite:(path)=>path.replace(/^\/api/,'')
+        }
+      }
+    },
+
     plugins: [
     plugins: [
       viteMockServe({
       viteMockServe({
         // 保证开发阶段可以使用mock,生产环境禁止开启
         // 保证开发阶段可以使用mock,生产环境禁止开启