Commit bea22677ee50d9251fd3310c4b48999084df4d11

Authored by lichao
1 parent 116fac55

提交

garbage-removal/src/apis/order.js
... ... @@ -99,6 +99,14 @@ export async function createHandlerQrCode(orderId) {
99 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 110 export async function queryOrderMessageCount() {
103 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 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 24 * @method 退出登录
19 25 */
... ...
garbage-removal/src/components/clash-disposal-dispatch/index.vue
  1 +
1 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 28 </next-tree>
5 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 32 // @ts-ignore
10 33 import nextTree from '../next-tree/next-tree.vue';
  34 +
11 35 const props = defineProps({
12 36 dataList: {
13 37 type: Array,
... ... @@ -33,28 +57,50 @@ const props = defineProps({
33 57 type: Function,
34 58 default: () => { }
35 59 }
36   -
37 60 })
  61 +
38 62 const treeData = ref([])
39 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 84 function getTitle(checked) {
41 85 return `已选:${checked.length}位处置场所负责人`
42 86 }
  87 +
43 88 function changeVerify(current, chooseList) {
44 89 // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串
45 90 // 如果函数体不做return返回值,即验证通过,控件正常处理业务
46 91 // 限制条件 只能选择一个处置场所
47   - if (chooseList && chooseList.length<2) {
  92 + if (chooseList && chooseList.length < 2) {
48 93 for (let index = 0; index < chooseList.length; index++) {
49 94 const element = chooseList[index];
50 95 if (current.id.indexOf(element.id) === -1 && element.label.indexOf(current.label) != -1) {
51 96 return "该处置场所负责人已经被选中了"
52 97 }
53 98 }
54   - }else{
55   - return "只能选择一个处置场所"
  99 + } else {
  100 + return "只能选择一个处置场所"
56 101 }
57 102 }
  103 +
58 104 function open(dataList) {
59 105 treeData.value = handlerTreeData(dataList)
60 106 treeData.value = treeData.value.filter(item => {
... ... @@ -69,27 +115,28 @@ function open(dataList) {
69 115  
70 116 function handlerTreeData(dataList) {
71 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 140 function cleanTreeData(treeData) {
94 141 treeData.map(item => {
95 142 item.checked = false
... ... @@ -98,16 +145,24 @@ function cleanTreeData(treeData) {
98 145 }
99 146 })
100 147 }
  148 +
101 149 function close() {
102 150 // 清除treeData的选中状态
103 151 cleanTreeData(unref(treeData))
  152 + searchText.value = '' // 清空搜索文本
104 153 }
  154 +
  155 +// 添加清空搜索功能
  156 +function clearSearch() {
  157 + searchText.value = ''
  158 +}
  159 +
105 160 defineExpose({
106 161 open, close, nextTreeRef
107 162 })
108 163 </script>
109   -<style lang="scss">
110   -.line-block {
  164 +
  165 +<style lang="scss">.line-block {
111 166 display: flex;
112 167 flex-direction: row;
113 168 justify-content: flex-start;
... ... @@ -120,4 +175,43 @@ defineExpose({
120 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 218 \ No newline at end of file
... ...
garbage-removal/src/components/clash-driver-dispatch/index.vue
1 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 27 </next-tree>
20 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 31 // @ts-ignore
25 32 import nextTree from '../next-tree/next-tree.vue';
  33 +
26 34 const props = defineProps({
27 35 dataList: {
28 36 type: Array,
... ... @@ -48,17 +56,35 @@ const props = defineProps({
48 56 type: Function,
49 57 default: () => { }
50 58 }
51   -
52 59 })
  60 +
53 61 const treeData = ref([])
54 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 83 function getTitle(checked) {
56 84 return `已选:${checked.length}位驾驶员`
57 85 }
  86 +
58 87 function changeVerify(current, chooseList) {
59   - // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串
60   - // 如果函数体不做return返回值,即验证通过,控件正常处理业务
61   - // 限制条件
62 88 if (chooseList) {
63 89 for (let index = 0; index < chooseList.length; index++) {
64 90 const element = chooseList[index];
... ... @@ -68,6 +94,7 @@ function changeVerify(current, chooseList) {
68 94 }
69 95 }
70 96 }
  97 +
71 98 function open(dataList) {
72 99 treeData.value = handlerTreeData(dataList)
73 100 treeData.value = treeData.value.filter(item => {
... ... @@ -82,27 +109,28 @@ function open(dataList) {
82 109  
83 110 function handlerTreeData(dataList) {
84 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 134 function cleanTreeData(treeData) {
107 135 treeData.map(item => {
108 136 item.checked = false
... ... @@ -111,16 +139,27 @@ function cleanTreeData(treeData) {
111 139 }
112 140 })
113 141 }
  142 +
114 143 function close() {
115   - // 清除treeData的选中状态
116 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 157 defineExpose({
119 158 open, close, nextTreeRef
120 159 })
121 160 </script>
122   -<style lang="scss">
123   -.line-block {
  161 +
  162 +<style lang="scss">.line-block {
124 163 display: flex;
125 164 flex-direction: row;
126 165 justify-content: flex-start;
... ... @@ -133,4 +172,43 @@ defineExpose({
133 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 215 \ No newline at end of file
... ...
garbage-removal/src/pages.json
... ... @@ -23,6 +23,12 @@
23 23 }
24 24 },
25 25 {
  26 + "path": "pages/change-password/index",
  27 + "style": {
  28 + "navigationBarTitleText": "修改密码"
  29 + }
  30 + },
  31 + {
26 32 "path": "pages/sign-up/index",
27 33 "style": {
28 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 258 \ No newline at end of file
... ...
garbage-removal/src/pages/home-info/address/index.vue
... ... @@ -82,9 +82,9 @@ const toAddSite = () =&gt; {
82 82 }
83 83 onShow(() => {
84 84 getData();
85   - if (userType.value == '处置场所负责人') {
86   - updateFlag.value=false;
87   - }
  85 + // if (userType.value == '处置场所负责人') {
  86 + // updateFlag.value=false;
  87 + // }
88 88 })
89 89 </script>
90 90  
... ...
garbage-removal/src/pages/home-info/clean/agreement.vue
... ... @@ -8,52 +8,44 @@
8 8 尊敬的用户:
9 9 </p>
10 10 <p>
11   - 欢迎您通过“智慧渣管APP”选择我们的装修垃圾收运服务。为了确保装修垃圾能够得到及时、规范的处理,维护良好的环境卫生,我们特制定本意向协议。请您在仔细阅读并理解本协议的内容后,进行勾选同意。一旦您勾选同意,即代表您对本意向协议内容的认可和接受。
  11 + 欢迎您通过“智慧渣管APP”选择我们的装修垃圾收运服务。为了确保装修垃圾能够得到及时、规范的处理,维护良好的环境卫生,我们特制定本意向协议。请您在仔细阅读并理解本协议的内容后,进行勾选同意。一旦您勾选同意,即代表您对本意向协议内容的认可和接受。
12 12 </p>
13 13  
14 14 <!-- 服务内容部分 -->
15   - <h2>一、服务内容</h2>
  15 + <h2>一、服务内容和标准</h2>
16 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 20 </p>
28 21  
29 22 <!-- 费用说明部分 -->
30   - <h2>、费用说明</h2>
  23 + <h2>、费用说明</h2>
31 24 <p>
32   - 1.装修垃圾收运服务的费用将根据您的装修垃圾产生量、运输距离等因素进行计算。具体费用标准将在您实际使用服务时进行明确。<br>
  25 + 1.装修垃圾收运服务的费用将根据您的装修垃圾产生量、运输距离等因素进行计算。具体费用标准将在您实际使用服务时进行明确。 <br>
33 26 2.您同意按照我们协商一致的收费标准支付相应的费用<span class='jiacu'>(具体费用双方协商确认,不通过本预约软件支付),并理解费用可能会根据实际情况双方再协商微调。</span>
34 27 </p>
35 28  
36   - <!-- 双方的权利和义务部分 -->
37   - <h2>四、双方的权利和义务</h2>
  29 + <!-- 权利和义务部分 -->
  30 + <h2>三、双方的权利和义务</h2>
38 31 <p>
39 32 1.您有权要求我们按照本协议的约定提供装修垃圾收运服务。<br>
40   - 2.我们应按照本协议的约定,为您提供优质、高效的装修垃圾收运服务。<br>
41   - 3.我们应遵守国家和地方相关法律法规、标准及规范的要求,对装修垃圾进行收运和处置。<br>
42   - 4.我们应保护您的隐私和信息安全,不得泄露您的相关信息。
  33 + 2.双方应按照本协议的约定,以及国家和地方相关法律法规、标准及规范的要求,对装修垃圾进行投放、收运和处置。<br>
43 34 </p>
44 35  
45   - <!-- 违约责任部分 -->
46   - <h2>五、违约责任</h2>
  36 + <!-- 违约责任 -->
  37 + <h2>四、违约责任</h2>
47 38 <p>
48   - 1.若您未按照国家和地方相关法律法规、标准及规范的要求将装修垃圾进行分类、装袋或放置在指定地点,我们有权拒绝收运,并要求您限期整改。若您逾期未整改,我们有权解除本协议,并要求您承担相应的违约责任。<br>
49   - 2.若您在我们已提供收运服务后未按时支付装修垃圾收运服务的费用,我们有权解除本协议,并要求您支付已产生的费用。
  39 + 1.若您未按照国家和地方相关法律法规、标准及规范的要求将投放装修垃圾,我们有权拒绝收运,并要求您限期整改。若您逾期未整改,我们有权解除本协议,并要求您承担相应的违约责任。<br>
  40 + 2.若您在我们已提供收运服务后未按时支付装修垃圾收运服务的费用,我们有权解除本协议,并要求您支付已产生的费用。<br>
  41 + 3.若垃圾运输过程中存在违法违规行为,所产生的法律后果由我方承担。<br>
50 42 </p>
51 43  
52 44 <!-- 其他条款部分 -->
53   - <h2>、其他条款</h2>
  45 + <h2>、其他条款</h2>
54 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 49 </p>
58 50 </div>
59 51 </template>
... ...
garbage-removal/src/pages/home-info/clean/index.vue
... ... @@ -55,14 +55,19 @@
55 55 </swiper>
56 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 72 <view class="company-clean-container-car-main-content-type">
68 73 <view class="company-clean-container-car-main-content-type-price-area">
... ... @@ -245,6 +250,7 @@
245 250 const carPopupShowFlag = ref(false)
246 251 const addressPopupRef = ref(null);
247 252 const swiperClass = ref("swiperHeight1")
  253 + const containerVolumeList = ref([])
248 254 const pageStyle = ref("")
249 255 const userAddress = ref({
250 256 garUserContactName: "",
... ... @@ -403,11 +409,23 @@
403 409 garCarInfoList.value = res.data.rows;
404 410 if (garCarInfoList.value[0]) {
405 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 429 const handleInCarClick = (val) => {
412 430 // paramFrom.value.garInCarStore = !paramFrom.value.garInCarStore
413 431 }
... ... @@ -500,6 +518,8 @@
500 518 carTypeShowFlag.value = false
501 519 }
502 520  
  521 +
  522 +
503 523 const orderClick = ref(true)
504 524 /**
505 525 * 处理下单
... ... @@ -613,6 +633,7 @@
613 633 const handlerSaveOrder = async (params) => {
614 634 await saveOrder(params).then(res => {
615 635 if (res.data.success) {
  636 + store.updateUnreadOrderCount();
616 637 if (userType.value != "用户") {
617 638 uni.$u.toast("下单成功,请切换成且角色查看订单详情")
618 639 uni.$u.route({
... ... @@ -631,6 +652,7 @@
631 652 }
632 653 }
633 654 })
  655 +
634 656 }
635 657  
636 658 const handlerChooseAddress = () => {
... ...
garbage-removal/src/pages/home/index.vue
... ... @@ -131,6 +131,7 @@ import { queryRole } from &quot;@/apis/user&quot;;
131 131 import { useMainStore } from "@/stores/index.js";
132 132 import { onLoad, onShow } from '@dcloudio/uni-app';
133 133 import { computed, ref } from 'vue';
  134 +import {queryOrderList} from "@/apis/order";
134 135 const searchKeyword = ref('')
135 136 const mainStore = useMainStore()
136 137 const userType = computed(() => mainStore.userType);
... ... @@ -405,6 +406,7 @@ onLoad(() =&gt; {
405 406 onShow(() => {
406 407 // 初始化数据
407 408 initData()
  409 + updateOrderBadge()
408 410 let flag = uni.getStorageSync("refreshFlag");
409 411 if(flag){
410 412 console.log(paging.value);
... ... @@ -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 444 const refreshPage = () => {
417 445 initData();
418 446 }
... ...
garbage-removal/src/pages/login/code.vue
... ... @@ -18,10 +18,16 @@
18 18 >
19 19 密码登录
20 20 </text>
  21 + <text
  22 + :class="{ active: loginType === 'nickname' }"
  23 + @click="switchLoginType('nickname')"
  24 + >
  25 + 用户名登录
  26 + </text>
21 27 </view>
22 28  
23 29 <!-- 手机号输入 -->
24   - <view class="input-wrapper">
  30 + <view class="input-wrapper" v-if="loginType !== 'nickname'">
25 31 <u-icon name="account" size="36" color="#909399" class="input-icon"></u-icon>
26 32 <input
27 33 class="login-input"
... ... @@ -50,6 +56,30 @@
50 56 </view>
51 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 84 <view v-else>
55 85 <view class="input-wrapper">
... ... @@ -67,7 +97,7 @@
67 97  
68 98 <view class="alternative">
69 99 <text class="link" @click="toRegister">立即注册</text>
70   - <text class="link" @click="forgetPassword">忘记密码?</text>
  100 + <text class="link" @click="toChangePassword">修改密码</text>
71 101 </view>
72 102 </view>
73 103 </view>
... ... @@ -93,6 +123,7 @@ const maxlength = ref(4);
93 123 const codeValue = ref("");
94 124 const second = ref(0);
95 125 const show = ref(true);
  126 +const nickname = ref("");
96 127  
97 128 // 密码登录相关
98 129 const password = ref("");
... ... @@ -102,6 +133,27 @@ const switchLoginType = (type) =&gt; {
102 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 158 const getCaptcha = () => {
107 159 if (!proxy.$u.test.mobile(iphoneNumber.value)) {
... ... @@ -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 201 const checkVerifyNum = (code) => {
143 202 userLogin({ loginType: 0, tel: iphoneNumber.value, code: code }).then(res => {
... ... @@ -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 399 .placeholder-style {
329 400 color: #c0c4cc;
330 401 font-size: 26rpx;
... ...
garbage-removal/src/pages/order-info/order-disposal/scan-detail/index.vue
... ... @@ -247,7 +247,7 @@
247 247 // 修改提示框,添加跳转到订单页面的选项
248 248 uni.showModal({
249 249 title: '提示',
250   - content: '当前趟次记录完毕!需要进入订单详情页面点击"完成订单"按钮才是最终完成订单。',
  250 + content: '当前趟次记录完毕!',
251 251 showCancel: true,
252 252 cancelText: '稍后处理',
253 253 confirmText: '立即前往',
... ...
garbage-removal/src/pages/order-info/order-disposal/transport-detail/index.vue
... ... @@ -100,11 +100,11 @@
100 100 <view class="space-box">{{ spaceStr }}</view>
101 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 108 </view>
109 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 226 </template>
227 227  
228 228 <script setup>
229   -import { createHandlerQrCode, queryOrderDetail, updateOrder } from "@/apis/order.js";
  229 +import {createHandlerQrCode, queryGarOrderMatchAsk, queryOrderDetail, updateOrder} from "@/apis/order.js";
230 230 import { createQrCode } from '@/apis/qrcode.js';
231 231 import uqrcode from '@/components/Sansnn-uQRCode_4.0.6/components/uqrcode/uqrcode.vue';
232 232 import zStatic from '@/components/z-paging/js/z-paging-static';
... ... @@ -456,20 +456,47 @@ const createQrCodeValid = (val) =&gt; {
456 456 */
457 457  
458 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 229 @click="handleOrderDispatchClick(orderId)" shape="square" color="#19a97c"
230 230 text="分配驾驶员"></u-button>
231 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 237 <view class="order-detail-bottom-right">
233 238 <u-button
234 239 v-if="dataGram.garOrderHandlerStatus === 0 && userType == '用户' && dataGram.garCancelFlag === 0"
... ... @@ -252,6 +257,7 @@
252 257 @click="handleDisposalDispatchClick(orderId)" shape="square" color="#19a97c"
253 258 text="分配处置场所"></u-button>
254 259 </view>
  260 +
255 261 </view>
256 262 </view>
257 263 <u-action-sheet :closeOnClickOverlay="true" :closeOnClickAction="false" @actionSheetClose="handleClose"
... ... @@ -821,6 +827,7 @@ const handleDriverDispatchConfirm = (val) =&gt; {
821 827 </script>
822 828  
823 829 <style lang="scss" scoped>
  830 +
824 831 $custom-marin-bottom: 20rpx;
825 832 $custom-page-padding: 20rpx;
826 833 $custom-border-radio: 20rpx;
... ... @@ -834,6 +841,27 @@ const handleDriverDispatchConfirm = (val) =&gt; {
834 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 865 .order-detail-container {
838 866 height: 100%;
839 867 width: 100%;
... ...
garbage-removal/src/pages/order/order-disposal/index.vue
... ... @@ -50,10 +50,12 @@
50 50  
51 51 <script setup>
52 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 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 59 const list = ref([{
58 60 name: '处理中',
59 61 count: 0
... ... @@ -69,6 +71,7 @@ const topMargin = ref();
69 71 const lightHeight = ref();
70 72 const store = useMainStore();
71 73 const showScan = ref(false);
  74 +const location = ref({});
72 75  
73 76 // 创建计算属性用于显示带数量的标题
74 77 const displayList = computed(() => {
... ... @@ -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 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 227 const onDecodeHandler = (data) => {
... ...
garbage-removal/src/pages/sign-up/index.vue
... ... @@ -162,7 +162,7 @@ export default {
162 162 loginType: 0,
163 163 signin: 1,
164 164 tel: this.tel,
165   - nikename: this.nickname,
  165 + nickname: this.nickname,
166 166 password: this.password
167 167 }).then(res => {
168 168 console.log('注册成功', res);
... ...
garbage-removal/src/stores/main.js
1 1 import { defineStore } from 'pinia';
2 2 import { ref } from 'vue';
  3 +import {queryOrderList} from "@/apis/order";
3 4 export const useMainStore = defineStore(
4 5 "main",
5 6 () => {
... ... @@ -10,8 +11,39 @@ export const useMainStore = defineStore(
10 11 // 或者保留初始对象定义,添加数据验证
11 12 const userPhone = ref("");
12 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 49 persist: {
... ...