Commit bea22677ee50d9251fd3310c4b48999084df4d11

Authored by lichao
1 parent 116fac55

提交

garbage-removal/src/apis/order.js
@@ -99,6 +99,14 @@ export async function createHandlerQrCode(orderId) { @@ -99,6 +99,14 @@ export async function createHandlerQrCode(orderId) {
99 return await request.get(`/order/handler/qrCode/${orderId}`); 99 return await request.get(`/order/handler/qrCode/${orderId}`);
100 } 100 }
101 101
  102 +export async function queryGarOrderMatchAsk(orderId) {
  103 + return await request.get(`/order/queryGarOrderMatchAsk/${orderId}`);
  104 +}
  105 +
  106 +export async function querySiteByTel() {
  107 + return await request.get(`/order/querySiteByTel`);
  108 +}
  109 +
102 export async function queryOrderMessageCount() { 110 export async function queryOrderMessageCount() {
103 return await request.get(`/order/query/message/count`); 111 return await request.get(`/order/query/message/count`);
104 } 112 }
garbage-removal/src/apis/user.js
@@ -13,7 +13,13 @@ export async function userLogin( params, config) { @@ -13,7 +13,13 @@ export async function userLogin( params, config) {
13 config 13 config
14 ); 14 );
15 } 15 }
16 - 16 +export async function updatePassword( params, config) {
  17 + return await request.post(
  18 + `${prefix}/updatePassword`,
  19 + params,
  20 + config
  21 + );
  22 +}
17 /** 23 /**
18 * @method 退出登录 24 * @method 退出登录
19 */ 25 */
garbage-removal/src/components/clash-disposal-dispatch/index.vue
  1 +
1 <template> 2 <template>
2 - <next-tree :changeVerify="changeVerify" :title="getTitle" ref="nextTreeRef" :checkStrictly="checkStrictly"  
3 - :selectParent="selectParent" :multiple="multiple" :treeData="treeData" @cancel="close" @confirm="onconfirm"> 3 + <next-tree
  4 + :changeVerify="changeVerify"
  5 + :title="getTitle"
  6 + ref="nextTreeRef"
  7 + :checkStrictly="checkStrictly"
  8 + :selectParent="selectParent"
  9 + :multiple="multiple"
  10 + :treeData="filteredTreeData"
  11 + @cancel="close"
  12 + @confirm="onconfirm">
  13 + <template #topBar>
  14 + <view class="search-container">
  15 + <view class="search-box">
  16 + <text class="search-icon">🔍</text>
  17 + <input
  18 + class="search-input"
  19 + placeholder="搜索处置场所负责人姓名"
  20 + v-model="searchText" />
  21 + <text
  22 + v-if="searchText"
  23 + class="clear-icon"
  24 + @click="clearSearch">✕</text>
  25 + </view>
  26 + </view>
  27 + </template>
4 </next-tree> 28 </next-tree>
5 </template> 29 </template>
6 30
7 -<script setup>  
8 -import { nextTick, ref, unref } from 'vue'; 31 +<script setup>import { nextTick, ref, unref, computed } from 'vue';
9 // @ts-ignore 32 // @ts-ignore
10 import nextTree from '../next-tree/next-tree.vue'; 33 import nextTree from '../next-tree/next-tree.vue';
  34 +
11 const props = defineProps({ 35 const props = defineProps({
12 dataList: { 36 dataList: {
13 type: Array, 37 type: Array,
@@ -33,28 +57,50 @@ const props = defineProps({ @@ -33,28 +57,50 @@ const props = defineProps({
33 type: Function, 57 type: Function,
34 default: () => { } 58 default: () => { }
35 } 59 }
36 -  
37 }) 60 })
  61 +
38 const treeData = ref([]) 62 const treeData = ref([])
39 const nextTreeRef = ref() 63 const nextTreeRef = ref()
  64 +const searchText = ref('')
  65 +
  66 +// 添加计算属性用于过滤数据
  67 +const filteredTreeData = computed(() => {
  68 + if (!searchText.value) {
  69 + return treeData.value
  70 + }
  71 +
  72 + return treeData.value.map(item => {
  73 + const filteredChildren = item.children.filter(child =>
  74 + child.label.toLowerCase().includes(searchText.value.toLowerCase())
  75 + )
  76 +
  77 + return {
  78 + ...item,
  79 + children: filteredChildren
  80 + }
  81 + }).filter(item => item.children.length > 0)
  82 +})
  83 +
40 function getTitle(checked) { 84 function getTitle(checked) {
41 return `已选:${checked.length}位处置场所负责人` 85 return `已选:${checked.length}位处置场所负责人`
42 } 86 }
  87 +
43 function changeVerify(current, chooseList) { 88 function changeVerify(current, chooseList) {
44 // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串 89 // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串
45 // 如果函数体不做return返回值,即验证通过,控件正常处理业务 90 // 如果函数体不做return返回值,即验证通过,控件正常处理业务
46 // 限制条件 只能选择一个处置场所 91 // 限制条件 只能选择一个处置场所
47 - if (chooseList && chooseList.length<2) { 92 + if (chooseList && chooseList.length < 2) {
48 for (let index = 0; index < chooseList.length; index++) { 93 for (let index = 0; index < chooseList.length; index++) {
49 const element = chooseList[index]; 94 const element = chooseList[index];
50 if (current.id.indexOf(element.id) === -1 && element.label.indexOf(current.label) != -1) { 95 if (current.id.indexOf(element.id) === -1 && element.label.indexOf(current.label) != -1) {
51 return "该处置场所负责人已经被选中了" 96 return "该处置场所负责人已经被选中了"
52 } 97 }
53 } 98 }
54 - }else{  
55 - return "只能选择一个处置场所" 99 + } else {
  100 + return "只能选择一个处置场所"
56 } 101 }
57 } 102 }
  103 +
58 function open(dataList) { 104 function open(dataList) {
59 treeData.value = handlerTreeData(dataList) 105 treeData.value = handlerTreeData(dataList)
60 treeData.value = treeData.value.filter(item => { 106 treeData.value = treeData.value.filter(item => {
@@ -69,27 +115,28 @@ function open(dataList) { @@ -69,27 +115,28 @@ function open(dataList) {
69 115
70 function handlerTreeData(dataList) { 116 function handlerTreeData(dataList) {
71 return dataList 117 return dataList
72 - .map((item, index) => {  
73 - return {  
74 - "id": (index + 1),  
75 - "name": item.garOrderDisposalCompanyName,  
76 - "label": item.garOrderDisposalCompanyName,  
77 - "children": item.personnelInfo.map((childrenItem, childrenIndex) => {  
78 - return {  
79 - "id": (index + 1) + '-' + (childrenIndex + 1),  
80 - "tel": childrenItem.tel,  
81 - "companyName": item.garOrderDisposalCompanyName,  
82 - "companyId": item.garOrderDisposalCompanyId,  
83 - "name": childrenItem.personName,  
84 - "personName": childrenItem.personName,  
85 - "label": childrenItem.personName + "-" + childrenItem.tel,  
86 - "checked": childrenItem.checked,  
87 - "disabled": childrenItem.checked ? true : childrenItem.tel ? false : true  
88 - }  
89 - })  
90 - }  
91 - }) 118 + .map((item, index) => {
  119 + return {
  120 + "id": (index + 1),
  121 + "name": item.garOrderDisposalCompanyName,
  122 + "label": item.garOrderDisposalCompanyName,
  123 + "children": item.personnelInfo.map((childrenItem, childrenIndex) => {
  124 + return {
  125 + "id": (index + 1) + '-' + (childrenIndex + 1),
  126 + "tel": childrenItem.tel,
  127 + "companyName": item.garOrderDisposalCompanyName,
  128 + "companyId": item.garOrderDisposalCompanyId,
  129 + "name": childrenItem.personName,
  130 + "personName": childrenItem.personName,
  131 + "label": childrenItem.personName + "-" + childrenItem.tel,
  132 + "checked": childrenItem.checked,
  133 + "disabled": childrenItem.checked ? true : childrenItem.tel ? false : true
  134 + }
  135 + })
  136 + }
  137 + })
92 } 138 }
  139 +
93 function cleanTreeData(treeData) { 140 function cleanTreeData(treeData) {
94 treeData.map(item => { 141 treeData.map(item => {
95 item.checked = false 142 item.checked = false
@@ -98,16 +145,24 @@ function cleanTreeData(treeData) { @@ -98,16 +145,24 @@ function cleanTreeData(treeData) {
98 } 145 }
99 }) 146 })
100 } 147 }
  148 +
101 function close() { 149 function close() {
102 // 清除treeData的选中状态 150 // 清除treeData的选中状态
103 cleanTreeData(unref(treeData)) 151 cleanTreeData(unref(treeData))
  152 + searchText.value = '' // 清空搜索文本
104 } 153 }
  154 +
  155 +// 添加清空搜索功能
  156 +function clearSearch() {
  157 + searchText.value = ''
  158 +}
  159 +
105 defineExpose({ 160 defineExpose({
106 open, close, nextTreeRef 161 open, close, nextTreeRef
107 }) 162 })
108 </script> 163 </script>
109 -<style lang="scss">  
110 -.line-block { 164 +
  165 +<style lang="scss">.line-block {
111 display: flex; 166 display: flex;
112 flex-direction: row; 167 flex-direction: row;
113 justify-content: flex-start; 168 justify-content: flex-start;
@@ -120,4 +175,43 @@ defineExpose({ @@ -120,4 +175,43 @@ defineExpose({
120 margin: 0 20rpx; 175 margin: 0 20rpx;
121 } 176 }
122 } 177 }
123 -</style> 178 +
  179 +.search-container {
  180 + padding: 15px 10px 10px;
  181 + background-color: #fff;
  182 +
  183 + .search-box {
  184 + display: flex;
  185 + align-items: center;
  186 + background-color: #f5f5f5;
  187 + border-radius: 20px;
  188 + padding: 8px 15px;
  189 +
  190 + .search-icon {
  191 + font-size: 16px;
  192 + margin-right: 8px;
  193 + color: #999;
  194 + }
  195 +
  196 + .search-input {
  197 + flex: 1;
  198 + border: none;
  199 + background: transparent;
  200 + font-size: 14px;
  201 + outline: none;
  202 + padding: 5px 0;
  203 +
  204 + &::placeholder {
  205 + color: #aaa;
  206 + }
  207 + }
  208 +
  209 + .clear-icon {
  210 + font-size: 16px;
  211 + color: #999;
  212 + padding: 2px;
  213 + cursor: pointer;
  214 + }
  215 + }
  216 +}
  217 +</style>
124 \ No newline at end of file 218 \ No newline at end of file
garbage-removal/src/components/clash-driver-dispatch/index.vue
1 <template> 1 <template>
2 - <next-tree :changeVerify="changeVerify" :title="getTitle" ref="nextTreeRef" :checkStrictly="checkStrictly"  
3 - :selectParent="selectParent" :multiple="multiple" :treeData="treeData" @cancel="close" @confirm="onconfirm">  
4 - <!-- label插槽示意代码 -->  
5 - <!-- <template #label="{data: {id, label, iconSrc, prev, post}}">  
6 - <view class="line-block">  
7 - <image class="img" v-if="iconSrc" :src="iconSrc"></image>  
8 - <text space="nbsp" v-if="prev">{{prev}}&nbsp;</text><text>{{label}}</text><text space="nbsp" v-if="post">&nbsp;{{post}}</text>  
9 - </view>  
10 - </template> -->  
11 - <!-- <template #topBar>  
12 - <view style="color: #666;padding:5px;"><text style="font-size: 12px;">历史记录</text></view>  
13 - <view style="display: flex;justify-content: space-between;padding-bottom: 10px;border-bottom: 1rpx solid #f0f0f0;">  
14 - <button @click="checkedFunc('1-3-3-4')" :style="'background-color:'+ (activeId === '1-3-3-4' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">北京区-4</button>  
15 - <button @click="checkedFunc('3-1-2')" :style="'background-color:'+ (activeId === '3-1-2' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">海珠区-2</button>  
16 - <button @click="checkedFunc('3-1-6')" :style="'background-color:'+ (activeId === '3-1-6' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">海珠区-5</button>  
17 - </view>  
18 - </template> --> 2 + <next-tree
  3 + :changeVerify="changeVerify"
  4 + :title="getTitle"
  5 + ref="nextTreeRef"
  6 + :checkStrictly="checkStrictly"
  7 + :selectParent="selectParent"
  8 + :multiple="multiple"
  9 + :treeData="filteredTreeData"
  10 + @cancel="close"
  11 + @confirm="onconfirm">
  12 + <template #topBar>
  13 + <view class="search-container">
  14 + <view class="search-box">
  15 + <text class="search-icon">🔍</text>
  16 + <input
  17 + class="search-input"
  18 + placeholder="搜索驾驶员姓名"
  19 + v-model="searchText" />
  20 + <text
  21 + v-if="searchText"
  22 + class="clear-icon"
  23 + @click="clearSearch">✕</text>
  24 + </view>
  25 + </view>
  26 + </template>
19 </next-tree> 27 </next-tree>
20 </template> 28 </template>
21 29
22 -<script setup>  
23 -import { nextTick, ref, unref } from 'vue'; 30 +<script setup>import { nextTick, ref, unref, computed } from 'vue';
24 // @ts-ignore 31 // @ts-ignore
25 import nextTree from '../next-tree/next-tree.vue'; 32 import nextTree from '../next-tree/next-tree.vue';
  33 +
26 const props = defineProps({ 34 const props = defineProps({
27 dataList: { 35 dataList: {
28 type: Array, 36 type: Array,
@@ -48,17 +56,35 @@ const props = defineProps({ @@ -48,17 +56,35 @@ const props = defineProps({
48 type: Function, 56 type: Function,
49 default: () => { } 57 default: () => { }
50 } 58 }
51 -  
52 }) 59 })
  60 +
53 const treeData = ref([]) 61 const treeData = ref([])
54 const nextTreeRef = ref() 62 const nextTreeRef = ref()
  63 +const searchText = ref('')
  64 +
  65 +// 添加计算属性用于过滤数据
  66 +const filteredTreeData = computed(() => {
  67 + if (!searchText.value) {
  68 + return treeData.value
  69 + }
  70 +
  71 + return treeData.value.map(item => {
  72 + const filteredChildren = item.children.filter(child =>
  73 + child.label.toLowerCase().includes(searchText.value.toLowerCase())
  74 + )
  75 +
  76 + return {
  77 + ...item,
  78 + children: filteredChildren
  79 + }
  80 + }).filter(item => item.children.length > 0)
  81 +})
  82 +
55 function getTitle(checked) { 83 function getTitle(checked) {
56 return `已选:${checked.length}位驾驶员` 84 return `已选:${checked.length}位驾驶员`
57 } 85 }
  86 +
58 function changeVerify(current, chooseList) { 87 function changeVerify(current, chooseList) {
59 - // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串  
60 - // 如果函数体不做return返回值,即验证通过,控件正常处理业务  
61 - // 限制条件  
62 if (chooseList) { 88 if (chooseList) {
63 for (let index = 0; index < chooseList.length; index++) { 89 for (let index = 0; index < chooseList.length; index++) {
64 const element = chooseList[index]; 90 const element = chooseList[index];
@@ -68,6 +94,7 @@ function changeVerify(current, chooseList) { @@ -68,6 +94,7 @@ function changeVerify(current, chooseList) {
68 } 94 }
69 } 95 }
70 } 96 }
  97 +
71 function open(dataList) { 98 function open(dataList) {
72 treeData.value = handlerTreeData(dataList) 99 treeData.value = handlerTreeData(dataList)
73 treeData.value = treeData.value.filter(item => { 100 treeData.value = treeData.value.filter(item => {
@@ -82,27 +109,28 @@ function open(dataList) { @@ -82,27 +109,28 @@ function open(dataList) {
82 109
83 function handlerTreeData(dataList) { 110 function handlerTreeData(dataList) {
84 return dataList 111 return dataList
85 - .map((item, index) => {  
86 - return {  
87 - "id": (index + 1),  
88 - "licensePlateNumber": item.licensePlateNumber,  
89 - "containerVolume": item.containerVolume + "方车",  
90 - "label": item.containerVolume + "方车" + '-' + item.licensePlateNumber,  
91 - "children": item.personnelInfo.map((childrenItem, childrenIndex) => {  
92 - return {  
93 - "id": (index + 1) + '-' + (childrenIndex + 1),  
94 - "garOrderContainerVolume": item.containerVolume,  
95 - "tel": childrenItem.tel,  
96 - "name": childrenItem.name,  
97 - "label": childrenItem.name + '-' + childrenItem.tel,  
98 - "checked": childrenItem.checked,  
99 - "carCode": item.licensePlateNumber,  
100 - "disabled": childrenItem.checked ? true : childrenItem.tel ? false : true  
101 - }  
102 - })  
103 - }  
104 - }) 112 + .map((item, index) => {
  113 + return {
  114 + "id": (index + 1),
  115 + "licensePlateNumber": item.licensePlateNumber,
  116 + "containerVolume": item.containerVolume + "方车",
  117 + "label": item.containerVolume + "方车" + '-' + item.licensePlateNumber,
  118 + "children": item.personnelInfo.map((childrenItem, childrenIndex) => {
  119 + return {
  120 + "id": (index + 1) + '-' + (childrenIndex + 1),
  121 + "garOrderContainerVolume": item.containerVolume,
  122 + "tel": childrenItem.tel,
  123 + "name": childrenItem.name,
  124 + "label": childrenItem.name + '-' + childrenItem.tel,
  125 + "checked": childrenItem.checked,
  126 + "carCode": item.licensePlateNumber,
  127 + "disabled": childrenItem.checked ? true : childrenItem.tel ? false : true
  128 + }
  129 + })
  130 + }
  131 + })
105 } 132 }
  133 +
106 function cleanTreeData(treeData) { 134 function cleanTreeData(treeData) {
107 treeData.map(item => { 135 treeData.map(item => {
108 item.checked = false 136 item.checked = false
@@ -111,16 +139,27 @@ function cleanTreeData(treeData) { @@ -111,16 +139,27 @@ function cleanTreeData(treeData) {
111 } 139 }
112 }) 140 })
113 } 141 }
  142 +
114 function close() { 143 function close() {
115 - // 清除treeData的选中状态  
116 cleanTreeData(unref(treeData)) 144 cleanTreeData(unref(treeData))
  145 + searchText.value = ''
  146 +}
  147 +
  148 +function handleSearch() {
  149 + // 搜索逻辑已经在 computed 属性中实现
  150 +}
  151 +
  152 +// 添加清空搜索功能
  153 +function clearSearch() {
  154 + searchText.value = ''
117 } 155 }
  156 +
118 defineExpose({ 157 defineExpose({
119 open, close, nextTreeRef 158 open, close, nextTreeRef
120 }) 159 })
121 </script> 160 </script>
122 -<style lang="scss">  
123 -.line-block { 161 +
  162 +<style lang="scss">.line-block {
124 display: flex; 163 display: flex;
125 flex-direction: row; 164 flex-direction: row;
126 justify-content: flex-start; 165 justify-content: flex-start;
@@ -133,4 +172,43 @@ defineExpose({ @@ -133,4 +172,43 @@ defineExpose({
133 margin: 0 20rpx; 172 margin: 0 20rpx;
134 } 173 }
135 } 174 }
136 -</style> 175 +
  176 +.search-container {
  177 + padding: 15px 10px 10px;
  178 + background-color: #fff;
  179 +
  180 + .search-box {
  181 + display: flex;
  182 + align-items: center;
  183 + background-color: #f5f5f5;
  184 + border-radius: 20px;
  185 + padding: 8px 15px;
  186 +
  187 + .search-icon {
  188 + font-size: 16px;
  189 + margin-right: 8px;
  190 + color: #999;
  191 + }
  192 +
  193 + .search-input {
  194 + flex: 1;
  195 + border: none;
  196 + background: transparent;
  197 + font-size: 14px;
  198 + outline: none;
  199 + padding: 5px 0;
  200 +
  201 + &::placeholder {
  202 + color: #aaa;
  203 + }
  204 + }
  205 +
  206 + .clear-icon {
  207 + font-size: 16px;
  208 + color: #999;
  209 + padding: 2px;
  210 + cursor: pointer;
  211 + }
  212 + }
  213 +}
  214 +</style>
137 \ No newline at end of file 215 \ No newline at end of file
garbage-removal/src/pages.json
@@ -23,6 +23,12 @@ @@ -23,6 +23,12 @@
23 } 23 }
24 }, 24 },
25 { 25 {
  26 + "path": "pages/change-password/index",
  27 + "style": {
  28 + "navigationBarTitleText": "修改密码"
  29 + }
  30 + },
  31 + {
26 "path": "pages/sign-up/index", 32 "path": "pages/sign-up/index",
27 "style": { 33 "style": {
28 "navigationBarTitleText": "", 34 "navigationBarTitleText": "",
garbage-removal/src/pages/change-password/index.vue 0 → 100644
  1 +
  2 +<template>
  3 + <view class="wrap">
  4 + <view class="form-container">
  5 + <view class="title">修改密码</view>
  6 +
  7 + <view class="input-wrapper">
  8 + <u-icon name="account" size="36" color="#909399" class="input-icon"></u-icon>
  9 + <input
  10 + class="login-input"
  11 + type="text"
  12 + v-model="formData.phone"
  13 + placeholder="请输入手机号"
  14 + placeholder-class="placeholder-style"
  15 + />
  16 + </view>
  17 +
  18 + <view class="input-wrapper">
  19 + <u-icon name="lock" size="36" color="#909399" class="input-icon"></u-icon>
  20 + <input
  21 + class="login-input"
  22 + type="password"
  23 + v-model="formData.oldPassword"
  24 + placeholder="请输入原密码"
  25 + placeholder-class="placeholder-style"
  26 + />
  27 + </view>
  28 +
  29 + <view class="input-wrapper">
  30 + <u-icon name="lock" size="36" color="#909399" class="input-icon"></u-icon>
  31 + <input
  32 + class="login-input"
  33 + type="password"
  34 + v-model="formData.newPassword"
  35 + placeholder="请输入新密码"
  36 + placeholder-class="placeholder-style"
  37 + />
  38 + </view>
  39 +
  40 + <view class="input-wrapper">
  41 + <u-icon name="lock" size="36" color="#909399" class="input-icon"></u-icon>
  42 + <input
  43 + class="login-input"
  44 + type="password"
  45 + v-model="formData.confirmPassword"
  46 + placeholder="请再次输入新密码"
  47 + placeholder-class="placeholder-style"
  48 + />
  49 + </view>
  50 +
  51 + <button @tap="handleChangePassword" class="submit-btn">确认修改</button>
  52 +
  53 + <view class="back-to-login">
  54 + <text class="link" @click="backToLogin">返回登录</text>
  55 + </view>
  56 + </view>
  57 + </view>
  58 +</template>
  59 +
  60 +<script setup>import { ref } from "vue";
  61 +import { updatePassword} from "@/apis/user.js"; // 需要在user.js中添加相应API
  62 +import { getCurrentInstance } from "vue";
  63 +
  64 +const { proxy } = getCurrentInstance();
  65 +
  66 +// 表单数据
  67 +const formData = ref({
  68 + phone: "",
  69 + oldPassword: "",
  70 + newPassword: "",
  71 + confirmPassword: ""
  72 +});
  73 +
  74 +// 验证码相关
  75 +const showCaptcha = ref(true);
  76 +const countdown = ref(0);
  77 +
  78 +// 获取验证码
  79 +const getCaptcha = () => {
  80 + if (!proxy.$u.test.mobile(formData.value.phone)) {
  81 + proxy.$u.toast("请输入正确的手机号");
  82 + return;
  83 + }
  84 +
  85 + // 这里应该调用获取验证码的接口
  86 + // sendCode(formData.value.phone).then(res => {
  87 + // proxy.$u.toast("验证码已发送");
  88 + // });
  89 +
  90 + // 倒计时逻辑
  91 + countdown.value = 60;
  92 + showCaptcha.value = false;
  93 +
  94 + const timer = setInterval(() => {
  95 + countdown.value--;
  96 + if (countdown.value <= 0) {
  97 + showCaptcha.value = true;
  98 + clearInterval(timer);
  99 + }
  100 + }, 1000);
  101 +};
  102 +
  103 +// 修改密码
  104 +const handleChangePassword = () => {
  105 + // 表单验证
  106 + if (!proxy.$u.test.mobile(formData.value.phone)) {
  107 + proxy.$u.toast("请输入正确的手机号");
  108 + return;
  109 + }
  110 +
  111 + if (!formData.value.oldPassword) {
  112 + proxy.$u.toast("请输入原密码");
  113 + return;
  114 + }
  115 +
  116 + if (!formData.value.newPassword) {
  117 + proxy.$u.toast("请输入新密码");
  118 + return;
  119 + }
  120 +
  121 + if (formData.value.newPassword !== formData.value.confirmPassword) {
  122 + proxy.$u.toast("两次输入的新密码不一致");
  123 + return;
  124 + }
  125 +
  126 + // 调用修改密码接口
  127 + const params = {
  128 + tel: formData.value.phone,
  129 + oldPassword: formData.value.oldPassword,
  130 + newPassword: formData.value.newPassword,
  131 + };
  132 +
  133 + updatePassword(params).then(res => {
  134 + if (res.data.code === 200) {
  135 + proxy.$u.toast("密码修改成功");
  136 + // 密码修改成功后,清除本地存储的用户信息并跳转到登录页
  137 + setTimeout(() => {
  138 + uni.clearStorageSync(); // 清除本地存储的所有信息
  139 + uni.reLaunch({
  140 + url: '/pages/login/index' // 跳转到登录页
  141 + });
  142 + }, 1500);
  143 + } else {
  144 + proxy.$u.toast(res.data.msg || "修改失败");
  145 + }
  146 + }).catch(err => {
  147 + proxy.$u.toast("修改密码失败");
  148 + });
  149 +};
  150 +
  151 +const backToLogin = () => {
  152 + uni.navigateBack();
  153 +};
  154 +</script>
  155 +
  156 +<style lang="scss" scoped>.wrap {
  157 + padding: 80rpx;
  158 + background-color: #f5f5f5;
  159 + min-height: 100vh;
  160 +}
  161 +
  162 +.form-container {
  163 + background-color: #fff;
  164 + border-radius: 20rpx;
  165 + padding: 40rpx;
  166 +}
  167 +
  168 +.title {
  169 + font-size: 50rpx;
  170 + color: #333;
  171 + text-align: center;
  172 + margin-bottom: 60rpx;
  173 + font-weight: bold;
  174 +}
  175 +
  176 +.input-wrapper {
  177 + display: flex;
  178 + align-items: center;
  179 + border-bottom: 1px solid #e4e7ed;
  180 + padding: 20rpx 0;
  181 + margin-bottom: 30rpx;
  182 +
  183 + .input-icon {
  184 + margin-right: 20rpx;
  185 + }
  186 +
  187 + .login-input {
  188 + flex: 1;
  189 + font-size: 28rpx;
  190 + color: #303133;
  191 + padding: 10rpx 0;
  192 +
  193 + &::placeholder {
  194 + color: #c0c4cc;
  195 + }
  196 + }
  197 +}
  198 +
  199 +.captcha-wrapper {
  200 + border: none;
  201 +
  202 + .input-group {
  203 + flex: 1;
  204 + display: flex;
  205 + align-items: center;
  206 + border-bottom: 1px solid #e4e7ed;
  207 + }
  208 +
  209 + .captcha {
  210 + color: $u-warning;
  211 + font-size: 28rpx;
  212 + margin-left: 20rpx;
  213 + white-space: nowrap;
  214 +
  215 + .noCaptcha {
  216 + display: block;
  217 + cursor: pointer;
  218 + }
  219 +
  220 + .regain {
  221 + display: block;
  222 + }
  223 + }
  224 +}
  225 +
  226 +.placeholder-style {
  227 + color: #c0c4cc;
  228 + font-size: 26rpx;
  229 +}
  230 +
  231 +.submit-btn {
  232 + background-color: #19a97c;
  233 + color: #ffffff;
  234 + border: none;
  235 + font-size: 30rpx;
  236 + padding: 20rpx 0;
  237 + border-radius: 50rpx;
  238 + margin-top: 60rpx;
  239 + width: 100%;
  240 +
  241 + &::after {
  242 + border: none;
  243 + }
  244 +}
  245 +
  246 +.back-to-login {
  247 + color: $u-tips-color;
  248 + display: flex;
  249 + justify-content: center;
  250 + margin-top: 40rpx;
  251 +
  252 + .link {
  253 + color: $u-warning;
  254 + cursor: pointer;
  255 + }
  256 +}
  257 +</style>
0 \ No newline at end of file 258 \ No newline at end of file
garbage-removal/src/pages/home-info/address/index.vue
@@ -82,9 +82,9 @@ const toAddSite = () =&gt; { @@ -82,9 +82,9 @@ const toAddSite = () =&gt; {
82 } 82 }
83 onShow(() => { 83 onShow(() => {
84 getData(); 84 getData();
85 - if (userType.value == '处置场所负责人') {  
86 - updateFlag.value=false;  
87 - } 85 + // if (userType.value == '处置场所负责人') {
  86 + // updateFlag.value=false;
  87 + // }
88 }) 88 })
89 </script> 89 </script>
90 90
garbage-removal/src/pages/home-info/clean/agreement.vue
@@ -8,52 +8,44 @@ @@ -8,52 +8,44 @@
8 尊敬的用户: 8 尊敬的用户:
9 </p> 9 </p>
10 <p> 10 <p>
11 - 欢迎您通过“智慧渣管APP”选择我们的装修垃圾收运服务。为了确保装修垃圾能够得到及时、规范的处理,维护良好的环境卫生,我们特制定本意向协议。请您在仔细阅读并理解本协议的内容后,进行勾选同意。一旦您勾选同意,即代表您对本意向协议内容的认可和接受。 11 + 欢迎您通过“智慧渣管APP”选择我们的装修垃圾收运服务。为了确保装修垃圾能够得到及时、规范的处理,维护良好的环境卫生,我们特制定本意向协议。请您在仔细阅读并理解本协议的内容后,进行勾选同意。一旦您勾选同意,即代表您对本意向协议内容的认可和接受。
12 </p> 12 </p>
13 13
14 <!-- 服务内容部分 --> 14 <!-- 服务内容部分 -->
15 - <h2>一、服务内容</h2> 15 + <h2>一、服务内容和标准</h2>
16 <p> 16 <p>
17 - 1.我们将为您提供装修垃圾的收运服务,包括但不限于收集、运输、处置等环节。<br>  
18 - 2.收运的装修垃圾范围包括但不限于木材、砖块、水泥、沙石、涂料、管材、电线等房屋装修过程中产生的废弃物。  
19 - </p>  
20 -  
21 - <!-- 服务标准部分 -->  
22 - <h2>二、服务标准</h2>  
23 - <p>  
24 - 1.我们将按照国家和地方相关法律法规、标准及规范的要求,对装修垃圾进行收运和处置。<br>  
25 - 2.确保收运车辆的整洁和卫生,避免对周边环境造成二次污染。<br>  
26 - 3.按照您指定的时间和地点,及时进行装修垃圾的收集和运输。 17 + 1.我们将按照国家和地方相关法律法规、标准及规范的要求为您提供装修垃圾的收运服务,包括但不限于收集、运输、处置等环节。<br>
  18 + 2.收运的装修垃圾范围包括但不限于木材、砖块、水泥、沙石、涂料、管材、电线等房屋装修过程中产生的废弃物,<span class='jiacu'>但严禁混入生活垃圾、有害垃圾等。</span>
  19 + 3.我们将按照您指定的时间和地点,及时进行装修垃圾的收集和运输,确保收运过程的整洁和卫生,并将装修垃圾运送至合法的处置场所。
27 </p> 20 </p>
28 21
29 <!-- 费用说明部分 --> 22 <!-- 费用说明部分 -->
30 - <h2>、费用说明</h2> 23 + <h2>、费用说明</h2>
31 <p> 24 <p>
32 - 1.装修垃圾收运服务的费用将根据您的装修垃圾产生量、运输距离等因素进行计算。具体费用标准将在您实际使用服务时进行明确。<br> 25 + 1.装修垃圾收运服务的费用将根据您的装修垃圾产生量、运输距离等因素进行计算。具体费用标准将在您实际使用服务时进行明确。 <br>
33 2.您同意按照我们协商一致的收费标准支付相应的费用<span class='jiacu'>(具体费用双方协商确认,不通过本预约软件支付),并理解费用可能会根据实际情况双方再协商微调。</span> 26 2.您同意按照我们协商一致的收费标准支付相应的费用<span class='jiacu'>(具体费用双方协商确认,不通过本预约软件支付),并理解费用可能会根据实际情况双方再协商微调。</span>
34 </p> 27 </p>
35 28
36 - <!-- 双方的权利和义务部分 -->  
37 - <h2>四、双方的权利和义务</h2> 29 + <!-- 权利和义务部分 -->
  30 + <h2>三、双方的权利和义务</h2>
38 <p> 31 <p>
39 1.您有权要求我们按照本协议的约定提供装修垃圾收运服务。<br> 32 1.您有权要求我们按照本协议的约定提供装修垃圾收运服务。<br>
40 - 2.我们应按照本协议的约定,为您提供优质、高效的装修垃圾收运服务。<br>  
41 - 3.我们应遵守国家和地方相关法律法规、标准及规范的要求,对装修垃圾进行收运和处置。<br>  
42 - 4.我们应保护您的隐私和信息安全,不得泄露您的相关信息。 33 + 2.双方应按照本协议的约定,以及国家和地方相关法律法规、标准及规范的要求,对装修垃圾进行投放、收运和处置。<br>
43 </p> 34 </p>
44 35
45 - <!-- 违约责任部分 -->  
46 - <h2>五、违约责任</h2> 36 + <!-- 违约责任 -->
  37 + <h2>四、违约责任</h2>
47 <p> 38 <p>
48 - 1.若您未按照国家和地方相关法律法规、标准及规范的要求将装修垃圾进行分类、装袋或放置在指定地点,我们有权拒绝收运,并要求您限期整改。若您逾期未整改,我们有权解除本协议,并要求您承担相应的违约责任。<br>  
49 - 2.若您在我们已提供收运服务后未按时支付装修垃圾收运服务的费用,我们有权解除本协议,并要求您支付已产生的费用。 39 + 1.若您未按照国家和地方相关法律法规、标准及规范的要求将投放装修垃圾,我们有权拒绝收运,并要求您限期整改。若您逾期未整改,我们有权解除本协议,并要求您承担相应的违约责任。<br>
  40 + 2.若您在我们已提供收运服务后未按时支付装修垃圾收运服务的费用,我们有权解除本协议,并要求您支付已产生的费用。<br>
  41 + 3.若垃圾运输过程中存在违法违规行为,所产生的法律后果由我方承担。<br>
50 </p> 42 </p>
51 43
52 <!-- 其他条款部分 --> 44 <!-- 其他条款部分 -->
53 - <h2>、其他条款</h2> 45 + <h2>、其他条款</h2>
54 <p> 46 <p>
55 - 1、如本协议双方经协商签订线下协议的,以线下协议为准,本协议无效。<br>  
56 - 2、本协议经长沙市渣土事务中心开发的“智慧渣管APP”发布,协议双方为使用该APP的预约装修垃圾收运服务的用户以及经用户确认预约的装修垃圾运输企业,<span class='jiacu'>长沙市渣土事务中心不承担该协议约定的权利及义务。</span> 47 + 1.如本协议双方经协商签订线下协议的,以线下协议为准,本协议无效。<br>
  48 + 2.本协议经长沙市渣土事务中心开发的“智慧渣管APP”发布,协议双方为使用该APP的预约装修垃圾收运服务的用户以及经用户确认预约的装修垃圾运输企业,<span class='jiacu'>长沙市渣土事务中心不承担该协议约定的权利及义务。</span>
57 </p> 49 </p>
58 </div> 50 </div>
59 </template> 51 </template>
garbage-removal/src/pages/home-info/clean/index.vue
@@ -55,14 +55,19 @@ @@ -55,14 +55,19 @@
55 </swiper> 55 </swiper>
56 </view> 56 </view>
57 57
58 - <view class="company-clean-container-car-main-content-type">  
59 - <view class="company-clean-container-car-main-content-type-price-area">  
60 - <text style="color: red;">*</text>车辆容积:  
61 - </view>  
62 - <view style=" width:100%;display:flex; color:#909399; align-items: center;">  
63 - <text>{{containerVolume}} 方</text>  
64 - </view>  
65 - </view> 58 + <view class="company-clean-container-car-main-content-type">
  59 + <view class="company-clean-container-car-main-content-type-price-area">
  60 + <text style="color: red;">*</text>车辆容积:
  61 + </view>
  62 + <view style="width:100%;display:flex; color:#909399; align-items: center; gap: 2rpx;">
  63 + <myPiker
  64 + :parentValue="containerVolume"
  65 + :title="'车辆容积'"
  66 + @change="handleContainerVolumeChange"
  67 + :array="containerVolumeList">
  68 + </myPiker>
  69 + </view>
  70 + </view>
66 71
67 <view class="company-clean-container-car-main-content-type"> 72 <view class="company-clean-container-car-main-content-type">
68 <view class="company-clean-container-car-main-content-type-price-area"> 73 <view class="company-clean-container-car-main-content-type-price-area">
@@ -245,6 +250,7 @@ @@ -245,6 +250,7 @@
245 const carPopupShowFlag = ref(false) 250 const carPopupShowFlag = ref(false)
246 const addressPopupRef = ref(null); 251 const addressPopupRef = ref(null);
247 const swiperClass = ref("swiperHeight1") 252 const swiperClass = ref("swiperHeight1")
  253 + const containerVolumeList = ref([])
248 const pageStyle = ref("") 254 const pageStyle = ref("")
249 const userAddress = ref({ 255 const userAddress = ref({
250 garUserContactName: "", 256 garUserContactName: "",
@@ -403,11 +409,23 @@ @@ -403,11 +409,23 @@
403 garCarInfoList.value = res.data.rows; 409 garCarInfoList.value = res.data.rows;
404 if (garCarInfoList.value[0]) { 410 if (garCarInfoList.value[0]) {
405 carName.value = garCarInfoList.value[0].carType; 411 carName.value = garCarInfoList.value[0].carType;
406 - containerVolume.value = garCarInfoList.value[0].containerVolume; 412 + containerVolume.value = garCarInfoList.value[0].containerVolume +"方";
407 } 413 }
  414 +
  415 + const volumeSet = new Set();
  416 + garCarInfoList.value.forEach(car => {
  417 + if (car.containerVolume) {
  418 + volumeSet.add(car.containerVolume +"方");
  419 + }
  420 + });
  421 + containerVolumeList.value = Array.from(volumeSet);
408 }) 422 })
409 } 423 }
410 424
  425 + const handleContainerVolumeChange = (value) => {
  426 + containerVolume.value = value;
  427 + }
  428 +
411 const handleInCarClick = (val) => { 429 const handleInCarClick = (val) => {
412 // paramFrom.value.garInCarStore = !paramFrom.value.garInCarStore 430 // paramFrom.value.garInCarStore = !paramFrom.value.garInCarStore
413 } 431 }
@@ -500,6 +518,8 @@ @@ -500,6 +518,8 @@
500 carTypeShowFlag.value = false 518 carTypeShowFlag.value = false
501 } 519 }
502 520
  521 +
  522 +
503 const orderClick = ref(true) 523 const orderClick = ref(true)
504 /** 524 /**
505 * 处理下单 525 * 处理下单
@@ -613,6 +633,7 @@ @@ -613,6 +633,7 @@
613 const handlerSaveOrder = async (params) => { 633 const handlerSaveOrder = async (params) => {
614 await saveOrder(params).then(res => { 634 await saveOrder(params).then(res => {
615 if (res.data.success) { 635 if (res.data.success) {
  636 + store.updateUnreadOrderCount();
616 if (userType.value != "用户") { 637 if (userType.value != "用户") {
617 uni.$u.toast("下单成功,请切换成且角色查看订单详情") 638 uni.$u.toast("下单成功,请切换成且角色查看订单详情")
618 uni.$u.route({ 639 uni.$u.route({
@@ -631,6 +652,7 @@ @@ -631,6 +652,7 @@
631 } 652 }
632 } 653 }
633 }) 654 })
  655 +
634 } 656 }
635 657
636 const handlerChooseAddress = () => { 658 const handlerChooseAddress = () => {
garbage-removal/src/pages/home/index.vue
@@ -131,6 +131,7 @@ import { queryRole } from &quot;@/apis/user&quot;; @@ -131,6 +131,7 @@ import { queryRole } from &quot;@/apis/user&quot;;
131 import { useMainStore } from "@/stores/index.js"; 131 import { useMainStore } from "@/stores/index.js";
132 import { onLoad, onShow } from '@dcloudio/uni-app'; 132 import { onLoad, onShow } from '@dcloudio/uni-app';
133 import { computed, ref } from 'vue'; 133 import { computed, ref } from 'vue';
  134 +import {queryOrderList} from "@/apis/order";
134 const searchKeyword = ref('') 135 const searchKeyword = ref('')
135 const mainStore = useMainStore() 136 const mainStore = useMainStore()
136 const userType = computed(() => mainStore.userType); 137 const userType = computed(() => mainStore.userType);
@@ -405,6 +406,7 @@ onLoad(() =&gt; { @@ -405,6 +406,7 @@ onLoad(() =&gt; {
405 onShow(() => { 406 onShow(() => {
406 // 初始化数据 407 // 初始化数据
407 initData() 408 initData()
  409 + updateOrderBadge()
408 let flag = uni.getStorageSync("refreshFlag"); 410 let flag = uni.getStorageSync("refreshFlag");
409 if(flag){ 411 if(flag){
410 console.log(paging.value); 412 console.log(paging.value);
@@ -413,6 +415,32 @@ onShow(() =&gt; { @@ -413,6 +415,32 @@ onShow(() =&gt; {
413 } 415 }
414 }) 416 })
415 417
  418 +const updateOrderBadge = async () => {
  419 + try {
  420 + const res = await getOrderCountByType(0);
  421 + await uni.setTabBarBadge({
  422 + index: 1, // 订单tab在tabBar中的索引
  423 + text: String(res.data.data.total)
  424 + });
  425 + } catch (error) {
  426 + console.error('获取订单数量失败:', error);
  427 + }
  428 +};
  429 +
  430 +// 根据订单类型获取订单总数
  431 +const getOrderCountByType = async (type) => {
  432 + try {
  433 + return await queryOrderList({
  434 + type: type,
  435 + pageNo: 1,
  436 + pageSize: 1
  437 + });
  438 + } catch (error) {
  439 + console.error('获取订单数量失败:', error);
  440 + throw error;
  441 + }
  442 +}
  443 +
416 const refreshPage = () => { 444 const refreshPage = () => {
417 initData(); 445 initData();
418 } 446 }
garbage-removal/src/pages/login/code.vue
@@ -18,10 +18,16 @@ @@ -18,10 +18,16 @@
18 > 18 >
19 密码登录 19 密码登录
20 </text> 20 </text>
  21 + <text
  22 + :class="{ active: loginType === 'nickname' }"
  23 + @click="switchLoginType('nickname')"
  24 + >
  25 + 用户名登录
  26 + </text>
21 </view> 27 </view>
22 28
23 <!-- 手机号输入 --> 29 <!-- 手机号输入 -->
24 - <view class="input-wrapper"> 30 + <view class="input-wrapper" v-if="loginType !== 'nickname'">
25 <u-icon name="account" size="36" color="#909399" class="input-icon"></u-icon> 31 <u-icon name="account" size="36" color="#909399" class="input-icon"></u-icon>
26 <input 32 <input
27 class="login-input" 33 class="login-input"
@@ -50,6 +56,30 @@ @@ -50,6 +56,30 @@
50 </view> 56 </view>
51 </view> 57 </view>
52 58
  59 + <view v-else-if="loginType === 'nickname'">
  60 + <view class="input-wrapper">
  61 + <u-icon name="account" size="36" color="#909399" class="input-icon"></u-icon>
  62 + <input
  63 + class="login-input"
  64 + type="text"
  65 + v-model="nickname"
  66 + placeholder="请输入用户名"
  67 + placeholder-class="placeholder-style"
  68 + />
  69 + </view>
  70 + <view class="input-wrapper">
  71 + <u-icon name="lock" size="36" color="#909399" class="input-icon"></u-icon>
  72 + <input
  73 + class="login-input"
  74 + type="password"
  75 + v-model="password"
  76 + placeholder="请输入密码"
  77 + placeholder-class="placeholder-style"
  78 + />
  79 + </view>
  80 + <button @tap="loginWithUsername" class="login-btn">登录</button>
  81 + </view>
  82 +
53 <!-- 密码登录 --> 83 <!-- 密码登录 -->
54 <view v-else> 84 <view v-else>
55 <view class="input-wrapper"> 85 <view class="input-wrapper">
@@ -67,7 +97,7 @@ @@ -67,7 +97,7 @@
67 97
68 <view class="alternative"> 98 <view class="alternative">
69 <text class="link" @click="toRegister">立即注册</text> 99 <text class="link" @click="toRegister">立即注册</text>
70 - <text class="link" @click="forgetPassword">忘记密码?</text> 100 + <text class="link" @click="toChangePassword">修改密码</text>
71 </view> 101 </view>
72 </view> 102 </view>
73 </view> 103 </view>
@@ -93,6 +123,7 @@ const maxlength = ref(4); @@ -93,6 +123,7 @@ const maxlength = ref(4);
93 const codeValue = ref(""); 123 const codeValue = ref("");
94 const second = ref(0); 124 const second = ref(0);
95 const show = ref(true); 125 const show = ref(true);
  126 +const nickname = ref("");
96 127
97 // 密码登录相关 128 // 密码登录相关
98 const password = ref(""); 129 const password = ref("");
@@ -102,6 +133,27 @@ const switchLoginType = (type) =&gt; { @@ -102,6 +133,27 @@ const switchLoginType = (type) =&gt; {
102 loginType.value = type; 133 loginType.value = type;
103 }; 134 };
104 135
  136 +const loginWithUsername = () => {
  137 + if (!nickname.value) {
  138 + proxy.$u.toast("请输入用户名");
  139 + return;
  140 + }
  141 +
  142 + if (!password.value) {
  143 + proxy.$u.toast("请输入密码");
  144 + return;
  145 + }
  146 +
  147 + userLogin({
  148 + loginType: 0,
  149 + signIn:0,
  150 + nickname: nickname.value,
  151 + password: password.value
  152 + }).then(res => {
  153 + handleLoginSuccess(res);
  154 + });
  155 +};
  156 +
105 // 获取验证码 157 // 获取验证码
106 const getCaptcha = () => { 158 const getCaptcha = () => {
107 if (!proxy.$u.test.mobile(iphoneNumber.value)) { 159 if (!proxy.$u.test.mobile(iphoneNumber.value)) {
@@ -138,6 +190,13 @@ const finish = (value) =&gt; { @@ -138,6 +190,13 @@ const finish = (value) =&gt; {
138 } 190 }
139 }; 191 };
140 192
  193 +// 跳转到修改密码页面
  194 +const toChangePassword = () => {
  195 + uni.$u.route({
  196 + url: 'pages/change-password/index'
  197 + });
  198 +};
  199 +
141 // 验证码登录 200 // 验证码登录
142 const checkVerifyNum = (code) => { 201 const checkVerifyNum = (code) => {
143 userLogin({ loginType: 0, tel: iphoneNumber.value, code: code }).then(res => { 202 userLogin({ loginType: 0, tel: iphoneNumber.value, code: code }).then(res => {
@@ -325,6 +384,18 @@ const handleIphoneNumber = (tel) =&gt; { @@ -325,6 +384,18 @@ const handleIphoneNumber = (tel) =&gt; {
325 } 384 }
326 } 385 }
327 386
  387 +.alternative {
  388 + color: $u-tips-color;
  389 + display: flex;
  390 + justify-content: space-between;
  391 + margin-top: 60rpx;
  392 +
  393 + .link {
  394 + color: $u-warning;
  395 + cursor: pointer;
  396 + }
  397 +}
  398 +
328 .placeholder-style { 399 .placeholder-style {
329 color: #c0c4cc; 400 color: #c0c4cc;
330 font-size: 26rpx; 401 font-size: 26rpx;
garbage-removal/src/pages/order-info/order-disposal/scan-detail/index.vue
@@ -247,7 +247,7 @@ @@ -247,7 +247,7 @@
247 // 修改提示框,添加跳转到订单页面的选项 247 // 修改提示框,添加跳转到订单页面的选项
248 uni.showModal({ 248 uni.showModal({
249 title: '提示', 249 title: '提示',
250 - content: '当前趟次记录完毕!需要进入订单详情页面点击"完成订单"按钮才是最终完成订单。', 250 + content: '当前趟次记录完毕!',
251 showCancel: true, 251 showCancel: true,
252 cancelText: '稍后处理', 252 cancelText: '稍后处理',
253 confirmText: '立即前往', 253 confirmText: '立即前往',
garbage-removal/src/pages/order-info/order-disposal/transport-detail/index.vue
@@ -100,11 +100,11 @@ @@ -100,11 +100,11 @@
100 <view class="space-box">{{ spaceStr }}</view> 100 <view class="space-box">{{ spaceStr }}</view>
101 </view> 101 </view>
102 <!-- 占位符 --> 102 <!-- 占位符 -->
103 - <view class="order-detail-bottom" v-if="dataGram.garOrderDisposalStatus === 1 && transportWeightCount > 0">  
104 - <view class="order-detail-bottom-box">  
105 - <u-button @click="handlerOrderSuccess(orderId)" shape="square" color="#19a97c" text="完成订单"></u-button>  
106 - </view>  
107 - </view> 103 +<!-- <view class="order-detail-bottom" v-if="dataGram.garOrderDisposalStatus === 1 && transportWeightCount > 0">-->
  104 +<!-- <view class="order-detail-bottom-box">-->
  105 +<!-- <u-button @click="handlerOrderSuccess(orderId)" shape="square" color="#19a97c" text="完成订单"></u-button>-->
  106 +<!-- </view>-->
  107 +<!-- </view>-->
108 </view> 108 </view>
109 </template> 109 </template>
110 110
garbage-removal/src/pages/order-info/order-disposal/transport-detail/tempfile_1760595387127.vue 0 → 100644
  1 +<view class="transport-process-item" style="display: flex; width: 100%; margin: 20rpx 0; flex-wrap: nowrap; align-items: center;">
  2 + <view style="width: 80rpx; flex-shrink: 0; margin-right: 10rpx;">
  3 + <up-image :show-loading="true" :src="item.fillImage" width="80rpx" height="80rpx"></up-image>
  4 + </view>
  5 + <view style="width: 120rpx; display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-right: 10rpx;">
  6 + <view style="font-size: 25rpx; white-space: nowrap;">
  7 + 载重: {{ item.garCarryingWeight }}吨
  8 + </view>
  9 + </view>
  10 + <view style="width: 80rpx; display: flex; align-items: center; justify-content: center; font-size: 25rpx; margin-right: 10rpx;">
  11 + <view style="transform: rotateY(180deg);">
  12 + <up-icon name="car-fill" size="40" color="#19a97c"></up-icon>
  13 + </view>
  14 + </view>
  15 + <view style="width: 80rpx; display: flex; justify-content: center; align-items: center; font-size: 25rpx; margin-right: 10rpx;">
  16 + <view>{{ (index + 1) + '/' + dataGram.garRealCarCount }}</view>
  17 + </view>
  18 + <view style="flex: 1; display: flex; align-items: center; margin-right: 10rpx; overflow: hidden;">
  19 + <view style="display: flex; justify-content: flex-start; align-items: center; font-size: 25rpx; overflow: hidden;">
  20 + <view style="margin-right: 4rpx; flex-shrink: 0;">
  21 + 车牌:
  22 + </view>
  23 + <view style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
  24 + {{ item.garHandlerCarCode }}
  25 + </view>
  26 + </view>
  27 + </view>
  28 + <view style="width: 100rpx; display: flex; align-items: center; justify-content: flex-end;"
  29 + @click="goTransportDetail(item)">
  30 + <text style="font-size: 30rpx; white-space: nowrap; margin-right: 15rpx; color: #19a97c;">详情</text>
  31 + <up-icon name="arrow-right" size="30" color="#19a97c"></up-icon>
  32 + </view>
  33 +</view>
garbage-removal/src/pages/order-info/order-driver/detail/index.vue
@@ -226,7 +226,7 @@ @@ -226,7 +226,7 @@
226 </template> 226 </template>
227 227
228 <script setup> 228 <script setup>
229 -import { createHandlerQrCode, queryOrderDetail, updateOrder } from "@/apis/order.js"; 229 +import {createHandlerQrCode, queryGarOrderMatchAsk, queryOrderDetail, updateOrder} from "@/apis/order.js";
230 import { createQrCode } from '@/apis/qrcode.js'; 230 import { createQrCode } from '@/apis/qrcode.js';
231 import uqrcode from '@/components/Sansnn-uQRCode_4.0.6/components/uqrcode/uqrcode.vue'; 231 import uqrcode from '@/components/Sansnn-uQRCode_4.0.6/components/uqrcode/uqrcode.vue';
232 import zStatic from '@/components/z-paging/js/z-paging-static'; 232 import zStatic from '@/components/z-paging/js/z-paging-static';
@@ -456,20 +456,47 @@ const createQrCodeValid = (val) =&gt; { @@ -456,20 +456,47 @@ const createQrCodeValid = (val) =&gt; {
456 */ 456 */
457 457
458 const handleUploadImage = (orderId, putType) => { 458 const handleUploadImage = (orderId, putType) => {
459 - const data = dataGram.value;  
460 - uni.showActionSheet({  
461 - itemList: ['上传装车图片'],  
462 - success: function (res) {  
463 - console.log('选中了第' + (res.tapIndex + 1) + '个按钮');  
464 - if(res.tapIndex === 0){  
465 - uni.$u.route(`pages/order-info/order-driver/upload/index?orderId=${orderId}&carPlate=${data.garHandlerCarCode}&driver=${store.userInfo.userName}&putType=putOnImages`) 459 + const data = dataGram.value;
  460 +
  461 + // 查询运输趟次
  462 + queryGarOrderMatchAsk(orderId).then(res => {
  463 + console.log(res.data.success+"sssss")
  464 + // 正确处理响应数据
  465 + if (res && res.data) {
  466 + if (res.data.success) {
  467 + let number = res.data.data;
  468 +
  469 + // 检查当前要上传的是第几趟
  470 + const currentGroupIndex = putOnImagesGrouped.value.length + 1;
  471 +
  472 + // 如果当前趟次大于上一趟次+1,说明上一趟次未完成
  473 + if (currentGroupIndex > number) {
  474 + uni.$u.toast('上一趟次未扫码');
  475 + return;
  476 + }
  477 +
  478 + uni.showActionSheet({
  479 + itemList: ['上传装车图片'],
  480 + success: function (res) {
  481 + console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
  482 + if(res.tapIndex === 0){
  483 + uni.$u.route(`pages/order-info/order-driver/upload/index?orderId=${orderId}&carPlate=${data.garHandlerCarCode}&driver=${store.userInfo.userName}&putType=putOnImages`)
  484 + }
  485 + },
  486 + fail: function (res) {
  487 + console.log(res.errMsg);
  488 + }
  489 + });
  490 + } else {
  491 + uni.$u.toast(res.data.msg || '查询运输趟次失败');
466 } 492 }
467 - },  
468 - fail: function (res) {  
469 - console.log(res.errMsg); 493 + } else {
  494 + uni.$u.toast('查询运输趟次失败,数据格式错误');
470 } 495 }
  496 + }).catch(error => {
  497 + console.error('查询运输趟次失败:', error);
  498 + uni.$u.toast('查询运输趟次失败');
471 }); 499 });
472 - // uni.$u.route(`pages/order-info/order-driver/upload/index?orderId=${orderId}&carPlate=${data.garHandlerCarCode}&driver=${store.userInfo.userName}`)  
473 } 500 }
474 501
475 /** 502 /**
garbage-removal/src/pages/order-info/order-other/detail/index.vue
@@ -229,6 +229,11 @@ @@ -229,6 +229,11 @@
229 @click="handleOrderDispatchClick(orderId)" shape="square" color="#19a97c" 229 @click="handleOrderDispatchClick(orderId)" shape="square" color="#19a97c"
230 text="分配驾驶员"></u-button> 230 text="分配驾驶员"></u-button>
231 </view> 231 </view>
  232 +
  233 + <view class="order-detail-bottom-center" v-if="dataGram.garOrderHandlerStatus === 1 && userType == '运输企业负责人'">
  234 + <u-button @click="handleSubmitSuccess(orderId)" shape="square" color="#19a97c" text="完成订单"></u-button>
  235 + </view>
  236 +
232 <view class="order-detail-bottom-right"> 237 <view class="order-detail-bottom-right">
233 <u-button 238 <u-button
234 v-if="dataGram.garOrderHandlerStatus === 0 && userType == '用户' && dataGram.garCancelFlag === 0" 239 v-if="dataGram.garOrderHandlerStatus === 0 && userType == '用户' && dataGram.garCancelFlag === 0"
@@ -252,6 +257,7 @@ @@ -252,6 +257,7 @@
252 @click="handleDisposalDispatchClick(orderId)" shape="square" color="#19a97c" 257 @click="handleDisposalDispatchClick(orderId)" shape="square" color="#19a97c"
253 text="分配处置场所"></u-button> 258 text="分配处置场所"></u-button>
254 </view> 259 </view>
  260 +
255 </view> 261 </view>
256 </view> 262 </view>
257 <u-action-sheet :closeOnClickOverlay="true" :closeOnClickAction="false" @actionSheetClose="handleClose" 263 <u-action-sheet :closeOnClickOverlay="true" :closeOnClickAction="false" @actionSheetClose="handleClose"
@@ -821,6 +827,7 @@ const handleDriverDispatchConfirm = (val) =&gt; { @@ -821,6 +827,7 @@ const handleDriverDispatchConfirm = (val) =&gt; {
821 </script> 827 </script>
822 828
823 <style lang="scss" scoped> 829 <style lang="scss" scoped>
  830 +
824 $custom-marin-bottom: 20rpx; 831 $custom-marin-bottom: 20rpx;
825 $custom-page-padding: 20rpx; 832 $custom-page-padding: 20rpx;
826 $custom-border-radio: 20rpx; 833 $custom-border-radio: 20rpx;
@@ -834,6 +841,27 @@ const handleDriverDispatchConfirm = (val) =&gt; { @@ -834,6 +841,27 @@ const handleDriverDispatchConfirm = (val) =&gt; {
834 margin-bottom: $custom-marin-bottom; 841 margin-bottom: $custom-marin-bottom;
835 } 842 }
836 843
  844 + .order-detail-bottom-box {
  845 + height: $custom-bottom-height;
  846 + padding: 50rpx;
  847 + box-sizing: border-box;
  848 + display: flex;
  849 + justify-content: space-between;
  850 + align-items: center;
  851 +
  852 + .order-detail-bottom-left {
  853 + min-width: 200rpx;
  854 + }
  855 +
  856 + .order-detail-bottom-center {
  857 + min-width: 200rpx;
  858 + }
  859 +
  860 + .order-detail-bottom-right {
  861 + min-width: 200rpx;
  862 + }
  863 + }
  864 +
837 .order-detail-container { 865 .order-detail-container {
838 height: 100%; 866 height: 100%;
839 width: 100%; 867 width: 100%;
garbage-removal/src/pages/order/order-disposal/index.vue
@@ -50,10 +50,12 @@ @@ -50,10 +50,12 @@
50 50
51 <script setup> 51 <script setup>
52 import QrScannerVue from '../../../components/QrScanner/QrScanner.vue'; 52 import QrScannerVue from '../../../components/QrScanner/QrScanner.vue';
53 -import { checkCode, queryOrderList } from '@/apis/order.js';  
54 -import { nextTick, onMounted, ref, computed } from 'vue'; 53 +import {checkCode, queryOrderList, querySiteByTel} from '@/apis/order.js';
  54 +import {computed, nextTick, onMounted, ref} from 'vue';
55 import swiperListItem from './swiper-list-item/index.vue'; 55 import swiperListItem from './swiper-list-item/index.vue';
56 -import { useMainStore } from '@/stores'; 56 +import {useMainStore} from '@/stores';
  57 +import {onLoad} from "@dcloudio/uni-app";
  58 +
57 const list = ref([{ 59 const list = ref([{
58 name: '处理中', 60 name: '处理中',
59 count: 0 61 count: 0
@@ -69,6 +71,7 @@ const topMargin = ref(); @@ -69,6 +71,7 @@ const topMargin = ref();
69 const lightHeight = ref(); 71 const lightHeight = ref();
70 const store = useMainStore(); 72 const store = useMainStore();
71 const showScan = ref(false); 73 const showScan = ref(false);
  74 +const location = ref({});
72 75
73 // 创建计算属性用于显示带数量的标题 76 // 创建计算属性用于显示带数量的标题
74 const displayList = computed(() => { 77 const displayList = computed(() => {
@@ -131,54 +134,94 @@ const handleScan = () =&gt; { @@ -131,54 +134,94 @@ const handleScan = () =&gt; {
131 } 134 }
132 }); 135 });
133 } 136 }
  137 +const takeLocation = () => {
  138 + window.JsInterface.takeLocation();
  139 +}
  140 +
  141 +// 接收定位结果的回调函数
  142 +const takeLocalCallBack = (lngLat) => {
  143 + const ll = lngLat.split(",");
  144 + location.value = {
  145 + longitude: ll[0],
  146 + latitude: ll[1]
  147 + };
  148 +}
  149 +
  150 +// 设置全局回调
  151 +onMounted(() => {
  152 + window.takeLocationCallBack = takeLocalCallBack
  153 +})
  154 +
  155 +onLoad((options) => {
  156 + // 获取定位信息
  157 + takeLocation();
  158 +});
  159 +
134 160
135 -const handleScanH5 = () => { 161 +const handleScanH5 = async () => {
136 showScan.value = true; 162 showScan.value = true;
137 - // uni.chooseImage({  
138 - // count: 1,  
139 - // sizeType: ['original', 'compressed'],  
140 - // sourceType: ['camera', 'album'],  
141 - // success: (res) => {  
142 - // console.log(res.tempFilePaths[0]);  
143 - // uni.uploadFile({  
144 - // url: import.meta.env.VITE_BASE_URL + "/QRCode/ocr/pric",  
145 - // header: {  
146 - // "Authorization": store.token  
147 - // },  
148 - // fileType: 'image',  
149 - // filePath: res.tempFilePaths[0],  
150 - // name: 'file',  
151 - // success: (uploadRes) => {  
152 - // if (uploadRes.statusCode == 200) {  
153 - // if ("" == uploadRes.data || undefined == uploadRes.data || null ==  
154 - // uploadRes.data) {  
155 - // uni.$u.toast("二维码图片识别失败,请检查二维码图片");  
156 - // return;  
157 - // } else {  
158 - // checkCode(uploadRes.data).then(res => {  
159 - // if (res.data && res.data.code == 200) {  
160 - // uni.$u.route({  
161 - // url: `pages/order-info/order-disposal/scan-detail/index`,  
162 - // params: {  
163 - // data: encodeURIComponent(JSON  
164 - // .stringify(res.data  
165 - // .data))  
166 - // }  
167 - // })  
168 - // return  
169 - // }  
170 - // uni.$u.toast(res.data.msg);  
171 - // })  
172 - // }  
173 - // } else {  
174 - // uni.$u.toast("二维码图片识别失败,请检查二维码图片");  
175 - // }  
176 -  
177 - // }  
178 - // })  
179 -  
180 - // }  
181 - // }) 163 +
  164 + // try {
  165 + // const isValidLocation = await validateUnloadingSite(location.value);
  166 + //
  167 + // if (!isValidLocation) {
  168 + // uni.$u.toast("您当前不在有效的卸货地址范围内");
  169 + // return;
  170 + // }
  171 + // showScan.value = true;
  172 + // } catch (error) {
  173 + // console.error('位置验证失败:', error);
  174 + // if (error.message.includes("用户拒绝")) {
  175 + // uni.$u.toast("请允许访问位置信息以验证卸货地址");
  176 + // } else if (error.message.includes("安全来源")) {
  177 + // uni.$u.toast("当前环境不支持位置验证,请使用HTTPS访问");
  178 + // } else {
  179 + // uni.$u.toast("位置验证失败: " + error.message);
  180 + // }
  181 + // }
  182 +}
  183 +
  184 +
  185 +const validateUnloadingSite = async (location) => {
  186 + try {
  187 + const res = await querySiteByTel();
  188 + const siteData = res.data.data; // 获取 SiteInfoDTO 对象
  189 +
  190 + // 确保 siteData 是数组,如果不是则包装成数组
  191 + const sites = Array.isArray(siteData) ? siteData : [siteData];
  192 +
  193 + return sites.some(site => {
  194 + // 注意:SiteInfoDTO 的字段名是 garLongitude 和 garLatitude
  195 + const distance = calculateDistance(
  196 + location.latitude,
  197 + location.longitude,
  198 + site.garLatitude, // 使用 garLatitude
  199 + site.garLongitude // 使用 garLongitude
  200 + );
  201 + console.log(distance)
  202 + return distance <= 200; // 200米范围内
  203 + });
  204 + } catch (error) {
  205 + console.error('验证卸货地址失败:', error);
  206 + return false;
  207 + }
  208 +}
  209 +
  210 +// 计算两点间距离(单位:米)
  211 +const calculateDistance = (lat1, lng1, lat2, lng2) => {
  212 + const radLat1 = (lat1 * Math.PI) / 180;
  213 + const radLat2 = (lat2 * Math.PI) / 180;
  214 + const deltaRadLat = radLat1 - radLat2;
  215 + const deltaRadLng = (lng1 * Math.PI) / 180 - (lng2 * Math.PI) / 180;
  216 +
  217 + const distance = 2 * Math.asin(
  218 + Math.sqrt(
  219 + Math.pow(Math.sin(deltaRadLat / 2), 2) +
  220 + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(deltaRadLng / 2), 2)
  221 + )
  222 + );
  223 +
  224 + return distance * 6371000; // 地球半径(米)
182 } 225 }
183 226
184 const onDecodeHandler = (data) => { 227 const onDecodeHandler = (data) => {
garbage-removal/src/pages/sign-up/index.vue
@@ -162,7 +162,7 @@ export default { @@ -162,7 +162,7 @@ export default {
162 loginType: 0, 162 loginType: 0,
163 signin: 1, 163 signin: 1,
164 tel: this.tel, 164 tel: this.tel,
165 - nikename: this.nickname, 165 + nickname: this.nickname,
166 password: this.password 166 password: this.password
167 }).then(res => { 167 }).then(res => {
168 console.log('注册成功', res); 168 console.log('注册成功', res);
garbage-removal/src/stores/main.js
1 import { defineStore } from 'pinia'; 1 import { defineStore } from 'pinia';
2 import { ref } from 'vue'; 2 import { ref } from 'vue';
  3 +import {queryOrderList} from "@/apis/order";
3 export const useMainStore = defineStore( 4 export const useMainStore = defineStore(
4 "main", 5 "main",
5 () => { 6 () => {
@@ -10,8 +11,39 @@ export const useMainStore = defineStore( @@ -10,8 +11,39 @@ export const useMainStore = defineStore(
10 // 或者保留初始对象定义,添加数据验证 11 // 或者保留初始对象定义,添加数据验证
11 const userPhone = ref(""); 12 const userPhone = ref("");
12 const userName = ref(""); 13 const userName = ref("");
  14 + const unreadOrderCount = ref(0);
  15 + const setUnreadOrderCount = (count) => {
  16 + unreadOrderCount.value = count;
  17 + };
  18 + const updateUnreadOrderCount = async () => {
  19 + try {
  20 + const res = await queryOrderList({ type: 0, pageNo: 1, pageSize: 1 });
  21 + const count = res.data.data.total || 0;
13 22
14 - return { token,tempToken,userType,userInfo,userPhone,userName }; 23 + // 更新状态
  24 + setUnreadOrderCount(count);
  25 +
  26 + // 更新 tabBar 角标
  27 + await uni.setTabBarBadge({
  28 + index: 1,
  29 + text: String(count)
  30 + });
  31 +
  32 + return count;
  33 + } catch (error) {
  34 + console.error('更新未读订单数量失败:', error);
  35 + return 0;
  36 + }
  37 + };
  38 + // 清除订单角标
  39 + const clearOrderBadge = () => {
  40 + uni.removeTabBarBadge({
  41 + index: 1
  42 + });
  43 + setUnreadOrderCount(0);
  44 + };
  45 +
  46 + return { token,tempToken,userType,userInfo,userPhone,userName,unreadOrderCount,setUnreadOrderCount,updateUnreadOrderCount };
15 }, 47 },
16 { 48 {
17 persist: { 49 persist: {