Commit 38584a8dede525a86b0322dada87c216a7b0a9ff

Authored by guzijian
1 parent 6107e055

feat: 新增角色

Showing 35 changed files with 2402 additions and 937 deletions
garbage-removal/.env.production
1 VITE_BASE_URL=http://61.169.120.202:10001/workflow 1 VITE_BASE_URL=http://61.169.120.202:10001/workflow
  2 +# VITE_BASE_URL=http://175.6.47.84:10001/workflow
2 # VITE_BASE_FILE_UPLOAD_PREFIX=/common/upload 3 # VITE_BASE_FILE_UPLOAD_PREFIX=/common/upload
3 # VITE_STOMP_URL=http://localhost:8860/ws 4 # VITE_STOMP_URL=http://localhost:8860/ws
garbage-removal/package-lock.json
@@ -24,6 +24,7 @@ @@ -24,6 +24,7 @@
24 "@dcloudio/uni-quickapp-webview": "3.0.0-3090620231104002", 24 "@dcloudio/uni-quickapp-webview": "3.0.0-3090620231104002",
25 "clipboard": "^2.0.11", 25 "clipboard": "^2.0.11",
26 "dayjs": "^1.11.10", 26 "dayjs": "^1.11.10",
  27 + "js-md5": "^0.8.3",
27 "pinia": "2.0.33", 28 "pinia": "2.0.33",
28 "pinia-plugin-persist-uni": "^1.2.0", 29 "pinia-plugin-persist-uni": "^1.2.0",
29 "sass": "1.58.3", 30 "sass": "1.58.3",
@@ -8603,6 +8604,11 @@ @@ -8603,6 +8604,11 @@
8603 "integrity": "sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==", 8604 "integrity": "sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==",
8604 "license": "BSD-3-Clause" 8605 "license": "BSD-3-Clause"
8605 }, 8606 },
  8607 + "node_modules/js-md5": {
  8608 + "version": "0.8.3",
  8609 + "resolved": "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz",
  8610 + "integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
  8611 + },
8606 "node_modules/js-tokens": { 8612 "node_modules/js-tokens": {
8607 "version": "4.0.0", 8613 "version": "4.0.0",
8608 "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", 8614 "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
garbage-removal/package.json
@@ -56,6 +56,7 @@ @@ -56,6 +56,7 @@
56 "@dcloudio/uni-quickapp-webview": "3.0.0-3090620231104002", 56 "@dcloudio/uni-quickapp-webview": "3.0.0-3090620231104002",
57 "clipboard": "^2.0.11", 57 "clipboard": "^2.0.11",
58 "dayjs": "^1.11.10", 58 "dayjs": "^1.11.10",
  59 + "js-md5": "^0.8.3",
59 "pinia": "2.0.33", 60 "pinia": "2.0.33",
60 "pinia-plugin-persist-uni": "^1.2.0", 61 "pinia-plugin-persist-uni": "^1.2.0",
61 "sass": "1.58.3", 62 "sass": "1.58.3",
garbage-removal/src/apis/address.js
@@ -2,7 +2,7 @@ import { request } from "@/utils/request"; @@ -2,7 +2,7 @@ import { request } from "@/utils/request";
2 /** 2 /**
3 * @method 新增用户地址 3 * @method 新增用户地址
4 */ 4 */
5 -export async function addAddress( params, config) { 5 +export async function addAddress(params, config) {
6 return await request.post( 6 return await request.post(
7 `/user/save/address`, 7 `/user/save/address`,
8 params, 8 params,
@@ -12,7 +12,7 @@ export async function addAddress( params, config) { @@ -12,7 +12,7 @@ export async function addAddress( params, config) {
12 /** 12 /**
13 * @method 获取用户地址 13 * @method 获取用户地址
14 */ 14 */
15 -export async function queryAddress( type) { 15 +export async function queryAddress(type) {
16 return await request.get( 16 return await request.get(
17 `/user/query/address/${type}` 17 `/user/query/address/${type}`
18 ); 18 );
@@ -20,8 +20,8 @@ export async function queryAddress( type) { @@ -20,8 +20,8 @@ export async function queryAddress( type) {
20 /** 20 /**
21 * @method 编辑用户地址 21 * @method 编辑用户地址
22 */ 22 */
23 -export async function updateAddress( params,config) {  
24 - return await request.post( 23 +export async function updateAddress(params, config) {
  24 + return await request.post(
25 `/user/update/address`, 25 `/user/update/address`,
26 params, 26 params,
27 config 27 config
@@ -30,8 +30,8 @@ export async function updateAddress( params,config) { @@ -30,8 +30,8 @@ export async function updateAddress( params,config) {
30 /** 30 /**
31 * @method 编辑用户地址 31 * @method 编辑用户地址
32 */ 32 */
33 -export async function deleteAddress( id) {  
34 - return await request.delete( 33 +export async function deleteAddress(id) {
  34 + return await request.delete(
35 `/user/delete/address/${id}` 35 `/user/delete/address/${id}`
36 ); 36 );
37 } 37 }
garbage-removal/src/main.js
1 import uviewPlus from '@/uview-plus'; 1 import uviewPlus from '@/uview-plus';
  2 +import md5 from 'js-md5';
2 import * as Pinia from 'pinia'; 3 import * as Pinia from 'pinia';
3 import piniaPersistUni from "pinia-plugin-persist-uni"; 4 import piniaPersistUni from "pinia-plugin-persist-uni";
4 import { createSSRApp } from "vue"; 5 import { createSSRApp } from "vue";
5 import mixin from './common/mixin'; 6 import mixin from './common/mixin';
  7 +
6 // 引入uView对小程序分享的mixin封装 8 // 引入uView对小程序分享的mixin封装
7 import mpShare from '@/uview-plus/libs/mixin/mpShare.js'; 9 import mpShare from '@/uview-plus/libs/mixin/mpShare.js';
8 import App from "./App.vue"; 10 import App from "./App.vue";
@@ -47,7 +49,7 @@ export function createApp() { @@ -47,7 +49,7 @@ export function createApp() {
47 const app = createSSRApp(App); 49 const app = createSSRApp(App);
48 const pinia = Pinia.createPinia() 50 const pinia = Pinia.createPinia()
49 app.use(uviewPlus) 51 app.use(uviewPlus)
50 - 52 + // 配置uView
51 // 调用setConfig方法,方法内部会进行对象属性深度合并,可以放心嵌套配置 53 // 调用setConfig方法,方法内部会进行对象属性深度合并,可以放心嵌套配置
52 // 需要在app.use(uview-plus)之后执行 54 // 需要在app.use(uview-plus)之后执行
53 uni.$u.setConfig({ 55 uni.$u.setConfig({
@@ -64,6 +66,7 @@ export function createApp() { @@ -64,6 +66,7 @@ export function createApp() {
64 } 66 }
65 } 67 }
66 }) 68 })
  69 + uni.$u.md5 = md5
67 pinia.use(piniaPersistUni); 70 pinia.use(piniaPersistUni);
68 app.use(pinia); 71 app.use(pinia);
69 app.mixin(mpShare); 72 app.mixin(mpShare);
garbage-removal/src/manifest.json
@@ -51,7 +51,14 @@ @@ -51,7 +51,14 @@
51 /* 小程序特有相关 */ 51 /* 小程序特有相关 */
52 "mp-weixin" : { 52 "mp-weixin" : {
53 "lazyCodeLoading" : "requiredComponents", 53 "lazyCodeLoading" : "requiredComponents",
  54 + "requiredPrivateInfos": ["getLocation", "chooseLocation"],
54 "appid" : "wxc3f60667dc9d6cea", 55 "appid" : "wxc3f60667dc9d6cea",
  56 + "permission":{
  57 + "scope.userLocation":{
  58 + "desc":"你的位置信息将用于小程序位置接口的"
  59 + }
  60 + },
  61 + "libVersion": "latest",
55 "setting" : { 62 "setting" : {
56 "urlCheck" : false 63 "urlCheck" : false
57 }, 64 },
garbage-removal/src/pages.json
@@ -26,6 +26,13 @@ @@ -26,6 +26,13 @@
26 } 26 }
27 }, 27 },
28 { 28 {
  29 + "path": "pages/wode/choose/index",
  30 + "style": {
  31 + "navigationBarTitleText": "账户类型",
  32 + "enablePullDownRefresh": false
  33 + }
  34 + },
  35 + {
29 "path": "pages/login/index", 36 "path": "pages/login/index",
30 "style": { 37 "style": {
31 "navigationBarTitleText": "装饰装修垃圾智慧功能模块登录", 38 "navigationBarTitleText": "装饰装修垃圾智慧功能模块登录",
@@ -38,12 +45,6 @@ @@ -38,12 +45,6 @@
38 "enablePullDownRefresh": false 45 "enablePullDownRefresh": false
39 } 46 }
40 },{ 47 },{
41 - "path": "pages/wode/choose/index",  
42 - "style": {  
43 - "navigationBarTitleText": "选择身份",  
44 - "enablePullDownRefresh": false  
45 - }  
46 - },{  
47 "path": "pages/order/detail/index", 48 "path": "pages/order/detail/index",
48 "style": { 49 "style": {
49 "navigationBarTitleText": "派单详情", 50 "navigationBarTitleText": "派单详情",
@@ -123,6 +124,13 @@ @@ -123,6 +124,13 @@
123 "navigationBarBackgroundColor":"#53c21d", 124 "navigationBarBackgroundColor":"#53c21d",
124 "enablePullDownRefresh": false 125 "enablePullDownRefresh": false
125 } 126 }
  127 + },
  128 + {
  129 + "path": "pages/home/search/index",
  130 + "style": {
  131 + "navigationBarTitleText": "公司搜索",
  132 + "enablePullDownRefresh": false
  133 + }
126 },{ 134 },{
127 "path": "pages/order/index", 135 "path": "pages/order/index",
128 "style": { 136 "style": {
garbage-removal/src/pages/home/address/addSite.vue
@@ -2,29 +2,30 @@ @@ -2,29 +2,30 @@
2 <view class="wrap"> 2 <view class="wrap">
3 <view class="wrap-from-container"> 3 <view class="wrap-from-container">
4 <city-select v-model="cityPikerShowFlag" @city-change="handleCityChange"></city-select> 4 <city-select v-model="cityPikerShowFlag" @city-change="handleCityChange"></city-select>
5 - <u--form :labelStyle="{ color: '#909399' }" labelWidth="140" labelPosition="left" :model="addressInfo" 5 + <u--form :labelStyle="{ color: '#303133' }" labelWidth="140" labelPosition="top" :model="addressInfo"
6 ref="addressFrom"> 6 ref="addressFrom">
7 <u-form-item :required="true" label="所在地区" prop="addressArea" borderBottom> 7 <u-form-item :required="true" label="所在地区" prop="addressArea" borderBottom>
8 <view @click.stop="showRegionPicker" hover-class="click-box" style="width: 100%;"> 8 <view @click.stop="showRegionPicker" hover-class="click-box" style="width: 100%;">
9 <u--input border="none" readonly style="pointer-events:none" type="text" v-model="addressInfo.addressArea" 9 <u--input border="none" readonly style="pointer-events:none" type="text" v-model="addressInfo.addressArea"
10 - placeholder-class="line" placeholder="省市区县、乡镇等"></u--input> 10 + placeholder-class="line" placeholder="请选着所在地区"></u--input>
11 </view> 11 </view>
12 </u-form-item> 12 </u-form-item>
13 <u-form-item :required="true" label="详细地址" prop="addressDetail" borderBottom> 13 <u-form-item :required="true" label="详细地址" prop="addressDetail" borderBottom>
14 <view @click.stop="chooseAddressDetail" class="wrap-from-container-address-details" 14 <view @click.stop="chooseAddressDetail" class="wrap-from-container-address-details"
15 - style="width: 100%;overflow:hidden; text-overflow: ellipsis;" hover-class="click-box">  
16 - <u--input border="none" readonly type="text" style="pointer-events:none" v-model="addressInfo.addressDetail"  
17 - placeholder-class="line" placeholder="请选着所在地址" suffixIcon="map-fill"  
18 - suffixIconStyle="font-size: 28rpx;color: #909399"></u--input> 15 + style="color:#606266;font-size: 28rpx;width: 100%;" hover-class="click-box">
  16 + <view style="pointer-events: none; width: 100%;">
  17 + <up-textarea :disabled="true" color="#606266" border="none" autoHeight style="pointer-events:none"
  18 + v-model="addressInfo.addressDetail" placeholder="请选择详细地址"></up-textarea>
  19 + </view>
19 </view> 20 </view>
20 </u-form-item> 21 </u-form-item>
21 <u-form-item :required="true" label="联系人" prop="contactPerson" borderBottom> 22 <u-form-item :required="true" label="联系人" prop="contactPerson" borderBottom>
22 - <u--input border="none" type="text" v-model="addressInfo.contactPerson" placeholder-class="line"  
23 - placeholder="联系人"></u--input> 23 + <u--input color="#606266" border="none" type="text" v-model="addressInfo.contactPerson"
  24 + placeholder-class="line" placeholder="联系人"></u--input>
24 </u-form-item> 25 </u-form-item>
25 <u-form-item :required="true" label="联系电话" prop="contactIphoneNumber" borderBottom> 26 <u-form-item :required="true" label="联系电话" prop="contactIphoneNumber" borderBottom>
26 - <u--input border="none" type="text" v-model="addressInfo.contactIphoneNumber" placeholder-class="line"  
27 - placeholder="联系电话"></u--input> 27 + <u--input color="#606266" border="none" type="text" v-model="addressInfo.contactIphoneNumber"
  28 + placeholder-class="line" placeholder="联系电话"></u--input>
28 </u-form-item> 29 </u-form-item>
29 </u--form> 30 </u--form>
30 </view> 31 </view>
@@ -103,7 +104,6 @@ const showRegionPicker = () =&gt; { @@ -103,7 +104,6 @@ const showRegionPicker = () =&gt; {
103 } 104 }
104 105
105 const handleCityChange = (e) => { 106 const handleCityChange = (e) => {
106 - console.log(e);  
107 addressInfo.addressArea = e.province.label + '-' + e.city.label + '-' + e.area.label; 107 addressInfo.addressArea = e.province.label + '-' + e.city.label + '-' + e.area.label;
108 } 108 }
109 109
@@ -165,6 +165,7 @@ const submit = () =&gt; { @@ -165,6 +165,7 @@ const submit = () =&gt; {
165 * 打开地图选择地址 165 * 打开地图选择地址
166 */ 166 */
167 const chooseAddressDetail = () => { 167 const chooseAddressDetail = () => {
  168 + console.log('打开地图选择地址');
168 let coordinate = 'gcj02'; 169 let coordinate = 'gcj02';
169 uni.chooseLocation({ 170 uni.chooseLocation({
170 type: coordinate, 171 type: coordinate,
@@ -174,7 +175,28 @@ const chooseAddressDetail = () =&gt; { @@ -174,7 +175,28 @@ const chooseAddressDetail = () =&gt; {
174 addressInfo.garLongitude = res.longitude 175 addressInfo.garLongitude = res.longitude
175 addressInfo.garLatitude = res.latitude 176 addressInfo.garLatitude = res.latitude
176 addressInfo.garCoordinate = coordinate 177 addressInfo.garCoordinate = coordinate
  178 + // #ifdef MP-WEIXIN
  179 + let SecretKey = "DsNi4Hug4POlYLJ8AaloKB6Uob5fvL8l";
  180 + let key = "HNEBZ-PWHLR-M5AWP-WMRT3-XEOHJ-Y2BHY";
  181 + let md5Param = `/ws/geocoder/v1/?key=${key}&location=${res.latitude},${res.longitude}`;
  182 + let locApi = `https://apis.map.qq.com`
  183 + let sig = uni.$u.md5(md5Param + SecretKey)
  184 + uni.request({
  185 + url: locApi + md5Param + "&sig=" + sig,
  186 + method: 'GET',
  187 + success: (res) => {
  188 + let component = res.data.result.address_component;
  189 + if (component.province == "湖南省") {
  190 + addressInfo.addressDetail = addressInfo.addressDetail.replace(component.province + component.city + component.district, "")
  191 + addressInfo.addressArea = component.province + '-' + component.city + '-' + component.district;
  192 + }
  193 + }
  194 + });
  195 + // #endif
177 } 196 }
  197 + },
  198 + fail: function (res) {
  199 + console.log(res);
178 } 200 }
179 }); 201 });
180 } 202 }
@@ -211,8 +233,10 @@ const reset = () =&gt; { @@ -211,8 +233,10 @@ const reset = () =&gt; {
211 </script> 233 </script>
212 234
213 <style lang="scss" scoped> 235 <style lang="scss" scoped>
214 -::v-deep .u-input--square {  
215 - // width: 100%; 236 +::v-deep .u-textarea {
  237 + width: 100%;
  238 + padding: 0px !important;
  239 + background: white !important;
216 } 240 }
217 241
218 .wrap { 242 .wrap {
garbage-removal/src/pages/home/address/index.vue
@@ -58,7 +58,10 @@ const handleClickChangeCurrentAddress = (res) =&gt; { @@ -58,7 +58,10 @@ const handleClickChangeCurrentAddress = (res) =&gt; {
58 contactIphoneNumber: res.garUserContactTel, 58 contactIphoneNumber: res.garUserContactTel,
59 defaultFlag: true, 59 defaultFlag: true,
60 addressDetail: res.garRemark, 60 addressDetail: res.garRemark,
61 - garAddressId: res.garAddressId 61 + garAddressId: res.garAddressId,
  62 + garLongitude: res.garLongitude,
  63 + garLatitude: res.garLatitude,
  64 + garCoordinate: res.garCoordinate
62 }).then(res => { 65 }).then(res => {
63 getData(); 66 getData();
64 uni.$u.toast(res.data.msg) 67 uni.$u.toast(res.data.msg)
garbage-removal/src/pages/home/clean/company-detail/index.vue
@@ -11,7 +11,12 @@ @@ -11,7 +11,12 @@
11 {{ headerData.name }} 11 {{ headerData.name }}
12 </view> 12 </view>
13 <view class="company-content-right-area"> 13 <view class="company-content-right-area">
14 - 注册区划:{{ headerData.registrationArea }} 14 + <view class="company-content-right-address">
  15 + 注册区划:{{ headerData.registrationArea }}
  16 + </view>
  17 + <view class="company-content-right-button" @click="handlerClickJumpMap">
  18 + 一键导航
  19 + </view>
15 </view> 20 </view>
16 </view> 21 </view>
17 </view> 22 </view>
@@ -27,7 +32,7 @@ @@ -27,7 +32,7 @@
27 <view v-if="item.label != '道路运输许可证'" class="company-content-base-data-info-item-txt"> 32 <view v-if="item.label != '道路运输许可证'" class="company-content-base-data-info-item-txt">
28 {{ item.value }} 33 {{ item.value }}
29 </view> 34 </view>
30 - <view v-else class="company-content-base-data-info-item-txt"> 35 + <view v-else-if="item.value" class="company-content-base-data-info-item-txt">
31 <u-upload :fileList="[item.value]" name="3" multiple :maxCount="10" :previewFullImage="true" 36 <u-upload :fileList="[item.value]" name="3" multiple :maxCount="10" :previewFullImage="true"
32 :isReadOnly="true"></u-upload> 37 :isReadOnly="true"></u-upload>
33 </view> 38 </view>
@@ -139,6 +144,25 @@ const handleCleanGarbage = (companyObj, tel, userAddress) =&gt; { @@ -139,6 +144,25 @@ const handleCleanGarbage = (companyObj, tel, userAddress) =&gt; {
139 url: `pages/home/clean/index?companyObj=${JSON.stringify(companyObj)}&tel=${tel}&userAddress=${JSON.stringify(userAddress)}`, 144 url: `pages/home/clean/index?companyObj=${JSON.stringify(companyObj)}&tel=${tel}&userAddress=${JSON.stringify(userAddress)}`,
140 }) 145 })
141 } 146 }
  147 +const handlerClickJumpMap = () => {
  148 + const gps = companyInfo.value.officeAddressGps.split(',')
  149 + uni.showModal({
  150 + title: '提示',
  151 + content: '是否跳转到app定位进行导航?',
  152 + success: function (res) {
  153 + if (res.confirm) {
  154 + uni.openLocation({
  155 + latitude: Number(gps[1]),
  156 + longitude: Number(gps[0]),
  157 + success: function () {
  158 + console.log('success');
  159 + }
  160 + });
  161 + }
  162 + }
  163 + })
  164 + console.log('跳转定位到公司位置');
  165 +}
142 166
143 const initData = (baseData) => { 167 const initData = (baseData) => {
144 baseDataList.value[0].value = baseData.legalRepresentative 168 baseDataList.value[0].value = baseData.legalRepresentative
@@ -221,6 +245,21 @@ $custom-bottom-height: 200rpx; @@ -221,6 +245,21 @@ $custom-bottom-height: 200rpx;
221 .company-content-right-area { 245 .company-content-right-area {
222 font-size: 25rpx; 246 font-size: 25rpx;
223 color: $u-info; 247 color: $u-info;
  248 + display: flex;
  249 + justify-content: space-between;
  250 + align-items: center;
  251 +
  252 + .company-content-right-button {
  253 + padding: 10rpx 15rpx;
  254 + background: #19be6b;
  255 + box-sizing: border-box;
  256 + border-radius: 20rpx;
  257 + font-size: 18rpx;
  258 + color: #ffffff;
  259 + display: flex;
  260 + justify-content: center;
  261 + align-items: center;
  262 + }
224 } 263 }
225 } 264 }
226 265
garbage-removal/src/pages/home/clean/index-back.vue 0 → 100644
  1 +<template>
  2 + <view class="mask-box">
  3 + <liu-delivery-time :isMask="true" :change="changeTime" ref="chooseTime" title="请选择预约时间"></liu-delivery-time>
  4 + <u-picker closeOnClickOverlay :show="carTypeShowFlag" :columns="candidates" :itemHeight="100"
  5 + @confirm="handlePickerCarInfoConfirm" @cancel="handleCarInfoClick(false)"
  6 + @close="handleCarInfoClick(false)"></u-picker>
  7 + <u-picker closeOnClickOverlay :show="garbageTypeShowFlag" :columns="garbageTypeList" :itemHeight="100"
  8 + @confirm="handlePickerGarbageTypeConfirm" @close="handleGarbageTypeClick(false)"
  9 + @cancel="handleGarbageTypeClick(false)"></u-picker>
  10 + <u-popup :zIndex="10074" closeOnClickOverlay :show="carPopupShowFlag" :round="10" @close="handlePopupClick(false)"
  11 + @open="handlePopupClick(true)">
  12 + <view class="company-clean-container-car-popup">
  13 + <!-- 主要内容 -->
  14 + <view class="company-clean-container-car-popup-content">
  15 + <view class="company-clean-container-car-popup-content-title">
  16 + <view style="text-align: center;">
  17 + 车辆类型
  18 + </view>
  19 + </view>
  20 + <view class="company-clean-container-car-popup-content-box">
  21 + <view class="company-clean-container-car-popup-content-box-item" v-for="(item, index) in garCarInfoList"
  22 + :key="index">
  23 + <view class="company-clean-container-car-popup-content-box-item-text">
  24 + {{ item.garOrderCarType }}
  25 + </view>
  26 + <view class="company-clean-container-car-popup-content-box-item-number" hover-class="hoverClickStyle">
  27 + <u-number-box :min="0" :max="9999" integer buttonSize="46" :inputWidth="100"
  28 + v-model="garCarInfoList[item.garOrderCarType].garOrderCarNumber" :disabledInput="true"></u-number-box>
  29 + </view>
  30 + </view>
  31 +
  32 + </view>
  33 + </view>
  34 + <!-- 占位盒子 -->
  35 + <view class="company-clean-container-car-popup-button-safe">
  36 + &nbsp;
  37 + </view>
  38 + </view>
  39 + </u-popup>
  40 + </view>
  41 + <view class="company-clean-container">
  42 + <view class="company-clean-container-box">
  43 + <view class="company-clean-container-header">
  44 + <view class="company-clean-container-header-address">
  45 + {{ userAddress.garUserAddress }}{{ userAddress.garRemark }}
  46 + </view>
  47 + <view class="company-clean-container-header-base-info">
  48 + {{ userAddress.garUserContactName }} {{ userAddress.garUserContactTel }}
  49 + </view>
  50 + <view @click.stop="handleTimeChoose" class="company-clean-container-header-reservation">
  51 + <view class="company-clean-container-header-reservation-left">
  52 + <text style="color: red;">*</text> <u-icon name="calendar" size="40"></u-icon>预约时间
  53 + </view>
  54 + <view class="company-clean-container-header-reservation-right">
  55 + <text style="margin-right: 10rpx;">{{ dayTime ? dayTime : "请选择时间" }}</text> <u-icon name="arrow-right"
  56 + size="25"></u-icon>
  57 + </view>
  58 + </view>
  59 + </view>
  60 + <view class="company-clean-container-car-main">
  61 + <view class="company-clean-container-car-main-content">
  62 + <view v-if="paramFrom.carType" class="company-clean-container-car-main-content-type">
  63 + <text class="company-clean-container-car-main-content-type-price-area"><text
  64 + style="color: red;">*</text>车辆类型:</text>
  65 + <!-- <uni-combox label="" :candidates="candidates" placeholder="请选择运输车辆类型"
  66 + v-model="paramFrom.carType"></uni-combox> -->
  67 + <view class="" hover-class="hoverClickStyle" @click.stop="handleCarInfoClick(true)">
  68 + <u--input color="#909399" border="none" style="pointer-events:none" :modelValue="paramFrom.carType"
  69 + type="text" placeholder-class="line" readonly />
  70 + </view>
  71 + </view>
  72 + <view class="company-clean-container-car-main-content-type">
  73 + <text class="company-clean-container-car-main-content-type-price-area"><text
  74 + style="color: red;">*</text>垃圾类型:</text>
  75 + <view hover-class="hoverClickStyle" @click.stop="handleGarbageTypeClick(true)">
  76 + <u--input color="#909399" border="none" style="pointer-events:none" :modelValue="paramFrom.garbageType"
  77 + type="text" placeholder-class="line" readonly />
  78 + </view>
  79 + </view>
  80 + <view class="company-clean-container-car-main-content-img">
  81 + <image class="company-clean-container-car-main-content-img" :src="carFront" />
  82 + </view>
  83 + <view class="company-clean-container-car-main-content-remark">
  84 + {{ garCarTransportInfo }}
  85 + </view>
  86 +
  87 + <view v-if="paramFrom.carType" class="company-clean-container-car-main-content-number">
  88 + <view class="company-clean-container-car-main-content-number-txt">
  89 + <text style="color: red;">*</text>协商车辆数量:
  90 + </view>
  91 + <view class="company-clean-container-car-main-content-number-button">
  92 + <u-number-box :min="0" :max="9999" integer buttonSize="46" :inputWidth="100"
  93 + v-model="garCarInfoList[paramFrom.carType].garOrderCarNumber"></u-number-box>
  94 + </view>
  95 + </view>
  96 + <view class="company-clean-container-car-main-content-prompt">
  97 + 温馨提示:垃圾类型不符合,企业有权拒绝清运。
  98 + </view>
  99 + </view>
  100 + </view>
  101 + <view class="company-clean-container-site-image-info">
  102 + <view class="company-clean-container-site-image-info-remark">
  103 + <text style="color: red;">*</text>现场照片(最多上传10张)
  104 + </view>
  105 + <view class="company-clean-container-site-image-info-img">
  106 + <u-upload width="200" height="150" :fileList="fileList" @afterRead="afterRead" @delete="deletePic" name="3"
  107 + multiple :maxCount="10" :previewFullImage="true"></u-upload>
  108 + </view>
  109 + <view class="company-clean-container-site-image-info-input-remark">
  110 + 填写备注
  111 + </view>
  112 + <view class="company-clean-container-site-image-info-input-remark-box">
  113 + <u--textarea v-model="paramFrom.remark" placeholder="请输入内容"></u--textarea>
  114 + </view>
  115 + </view>
  116 + <view class="company-clean-container-site-image-info-sure-button">
  117 + <view class="company-clean-container-site-image-info-sure-button-radio">
  118 + <view @click="changeAgree">
  119 + <u-checkbox-group v-model="paramFrom.sureReadFlag" placement="row">
  120 + <u-checkbox activeColor="#5ac725" :customStyle="{ marginBottom: '0px', marginTop: '1px' }" size="25"
  121 + labelSize="25" shape="square" :key="0" :name="true" :labelDisabled="true"
  122 + labelColor="#909399"></u-checkbox>
  123 + </u-checkbox-group>
  124 + </view>
  125 + <view>
  126 + 本人已确认信息真实有效,并将上述信息告知市容环境卫生主管部门。
  127 + </view>
  128 + </view>
  129 + </view>
  130 + </view>
  131 + <view class="company-clean-bottom" style="z-index: 10074;">
  132 + <movable-area v-if="!carPopupShowFlag" ref="movableAreaElement" class="movableArea">
  133 + <movable-view class="movableView" :x="x" :y="y" direction="all" @change="onChange">
  134 + <view class="company-clean-call-box-container">
  135 + <u-icon @click="handleContactClick(tel)" name="phone-fill" color="#ffffff" size="50"></u-icon>
  136 + </view>
  137 + </movable-view>
  138 + </movable-area>
  139 + <view class="company-clean-bottom-box">
  140 + <view class="company-clean-bottom-left">
  141 + <view class="company-clean-bottom-left-icon">
  142 + <u-icon @click="carPopupShowFlag = true" :stop="true" size="50" name="car-fill"></u-icon>
  143 + </view>
  144 + <view class="company-clean-bottom-left-number">
  145 + <up-badge :type="type" max="99" :value="garCarNumberCount"></up-badge>
  146 + </view>
  147 + </view>
  148 + <view class="company-clean-bottom-right">
  149 + <u-button @click="handleOderSure" shape="square" color="#a9e08f" text="立即派单"></u-button>
  150 + </view>
  151 + </view>
  152 + </view>
  153 + </view>
  154 +</template>
  155 +
  156 +<script setup>
  157 +import { queryCarList } from '@/apis/carinfo.js';
  158 +import { uploadFilePromise } from '@/apis/common.js';
  159 +import { saveOrder } from '@/apis/order.js';
  160 +import liuDeliveryTime from "@/components/liu-delivery-time/liu-delivery-time.vue";
  161 +import { useMainStore } from '@/stores/index.js';
  162 +import { onLoad } from '@dcloudio/uni-app';
  163 +import { computed, getCurrentInstance, nextTick, ref, watch } from 'vue';
  164 +const { proxy } = getCurrentInstance();
  165 +
  166 +const store = useMainStore();
  167 +const userType = computed(() => store.userType)
  168 +const x = ref(5)
  169 +const y = ref()
  170 +const movableAreaElement = ref()
  171 +const companyObj = ref()
  172 +const tel = ref()
  173 +const carTypeShowFlag = ref(false)
  174 +const garbageTypeShowFlag = ref(false)
  175 +const carPopupShowFlag = ref(false)
  176 +const userAddress = ref({
  177 + garUserContactName: "",
  178 + garUserContactTel: "",
  179 + garRemark: "",
  180 + garUserAddress: "",
  181 + garCoordinate: "",
  182 + garLongitude: "",
  183 + garLatitude: "",
  184 +})
  185 +// 车辆信息
  186 +const garCarInfoList = ref({})
  187 +const garCarLabelInfoList = ref({})
  188 +const garCarLabelInfoNow = ref()
  189 +const garCarTransportInfo = computed(() => {
  190 + try {
  191 + let carInfo = garCarLabelInfoNow.value
  192 + let lengthWidthHeight = carInfo.lengthWidthHeight.split(";");
  193 + let boxLength = lengthWidthHeight[0]; // 箱子的长度(单位:米)
  194 + let boxWidth = lengthWidthHeight[1]; // 箱子的宽度(单位:米)
  195 + let boxHeight = lengthWidthHeight[2]; // 箱子的高度(单位:米)
  196 +
  197 + let bagLength = 0.75; // 袋子的长度(单位:米)
  198 + let bagWidth = 0.45; // 袋子的宽度(单位:米)
  199 + let bagHeight = 0.22; // 袋子的高度(单位:米)
  200 +
  201 + let boxVolume = boxLength * boxWidth * boxHeight; // 箱子的体积(单位:立方米)
  202 + let bagVolume = bagLength * bagWidth * bagHeight; // 袋子的体积(单位:立方米)
  203 +
  204 + let bagCount = Math.floor(boxVolume / bagVolume); // 箱子可以容纳的袋子数量(向下取整)
  205 +
  206 + return `箱体长${boxLength}m宽${boxWidth}m高${boxHeight}m,最多课容纳约${bagCount}袋袋装修垃圾(75cm * 45cm每袋)。`
  207 + } catch (error) {
  208 + return "符合装修垃圾运输管理规范的新型环保智能装修垃圾运输车。"
  209 + }
  210 +
  211 +})
  212 +// 车辆数量
  213 +const garCarNumberCount = computed(() => {
  214 + let count = 0;
  215 + if (garCarInfoList.value) {
  216 + for (const key in garCarInfoList.value) {
  217 + const element = garCarInfoList.value[key];
  218 + count = typeof element.garOrderCarNumber === 'number' ? count + element.garOrderCarNumber : count;
  219 + console.log(element.garOrderCarNumber instanceof Number);
  220 + }
  221 + }
  222 + console.log(count);
  223 + return count;
  224 +})
  225 +const garbageTypeList = ref([["装修垃圾", "建筑垃圾"]])
  226 +const paramFrom = ref({
  227 + carNumber: 0,
  228 + remark: "",
  229 + sureReadFlag: [],
  230 + carType: "",
  231 + garbageType: "装修垃圾"
  232 +})
  233 +const dayTime = ref()
  234 +
  235 +const chooseTime = ref()
  236 +const fileList = ref([])
  237 +const candidates = ref([])
  238 +const handleTimeChoose = () => {
  239 + chooseTime.value.open();
  240 +}
  241 +
  242 +const changeTime = (e) => {
  243 + dayTime.value = e.value
  244 +}
  245 +const changeAgree = (e) => {
  246 + // paramFrom.value.sureReadFlag = e
  247 + paramFrom.value.sureReadFlag[0] = !paramFrom.value.sureReadFlag[0]
  248 +}
  249 +const onChange = (e) => {
  250 + // console.log(e);
  251 +}
  252 +
  253 +const handlePopupClick = (val) => {
  254 + carPopupShowFlag.value = val
  255 +}
  256 +
  257 +/**
  258 + * 初始化信息
  259 + */
  260 +onLoad((options) => {
  261 + companyObj.value = JSON.parse(options.companyObj);
  262 + tel.value = options.tel;
  263 + userAddress.value = JSON.parse(options.userAddress);
  264 + queryCarList({ companyId: companyObj.value.id }).then(res => {
  265 + // 设置车辆类型
  266 + candidates.value = [[...new Set(res.data.rows
  267 + .filter(item => item.containerVolume)
  268 + .map(item => {
  269 + garCarLabelInfoList.value[item.containerVolume + "方车"] = item
  270 + return item.containerVolume + "方车"
  271 + }))
  272 + ]];
  273 + // 设置初始车辆数量
  274 + candidates.value[0].forEach((item, index) => {
  275 + garCarInfoList.value[item] = {
  276 + garOrderCarNumber: 0,
  277 + garOrderCarType: item
  278 + }
  279 + })
  280 + // 设置默认车辆
  281 + paramFrom.value.carType = candidates.value[0][0];
  282 + garCarLabelInfoNow.value = garCarLabelInfoList.value[paramFrom.value.carType]
  283 + })
  284 +})
  285 +
  286 +
  287 +const handleCarInfoClick = (val) => {
  288 + carTypeShowFlag.value = val
  289 +}
  290 +const handleGarbageTypeClick = (val) => {
  291 + garbageTypeShowFlag.value = val
  292 +}
  293 +/**
  294 + * 拨打电话回调
  295 + */
  296 +const handleContactClick = (val) => {
  297 + uni.makePhoneCall({ phoneNumber: val }).then(res => {
  298 + }).catch(err => { });
  299 +}
  300 +
  301 +// 删除图片
  302 +const deletePic = (event) => {
  303 + fileList.value.splice(event.index, 1);
  304 +};
  305 +
  306 +// 新增图片
  307 +const afterRead = async (event) => {
  308 + // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
  309 + let lists = [].concat(event.file);
  310 + let fileListLen = fileList.value.length;
  311 + lists.map((item) => {
  312 + fileList.value.push({
  313 + ...item,
  314 + status: 'uploading',
  315 + message: '上传中',
  316 + });
  317 + });
  318 + for (let i = 0; i < lists.length; i++) {
  319 + let requestPath = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_BASE_FILE_UPLOAD_PREFIX;
  320 + const result = await uploadFilePromise(requestPath, lists[i].url);
  321 + let item = fileList.value[fileListLen];
  322 + fileList.value.splice(fileListLen, 1, {
  323 + ...item,
  324 + status: 'success',
  325 + message: '',
  326 + url: result.data.fileName,
  327 + });
  328 + fileListLen++;
  329 + }
  330 +};
  331 +
  332 +
  333 +const handlePickerGarbageTypeConfirm = (e) => {
  334 + paramFrom.value.garbageType = e.value
  335 + garbageTypeShowFlag.value = false
  336 +}
  337 +const handlePickerCarInfoConfirm = (e) => {
  338 + paramFrom.value.carType = e.value
  339 + garCarLabelInfoNow.value = garCarLabelInfoList.value[paramFrom.value.carType]
  340 + carTypeShowFlag.value = false
  341 + console.log(garCarLabelInfoNow.value);
  342 +}
  343 +
  344 +/**
  345 + * 处理下单
  346 + */
  347 +const handleOderSure = () => {
  348 + let garCarInfos = [];
  349 + for (const key in garCarInfoList.value) {
  350 + garCarInfos.push(garCarInfoList.value[key])
  351 + }
  352 +
  353 + let params = {
  354 + /**
  355 + * 派单地址
  356 + */
  357 + garOrderAddress: userAddress.value.garUserAddress,
  358 +
  359 + /**
  360 + * 派单详细地址
  361 + */
  362 + garOrderAddressDetails: userAddress.value.garRemark,
  363 +
  364 + /**
  365 + * 派单姓名
  366 + */
  367 + garOrderContactName: userAddress.value.garUserContactName,
  368 + garCarInfoList: garCarInfos,
  369 +
  370 + /**
  371 + * 垃圾类型
  372 + */
  373 + garOrderTrashType: paramFrom.value.garbageType,
  374 +
  375 + /**
  376 + * 派单人电话
  377 + */
  378 + garOrderContactTel: userAddress.value.garUserContactTel,
  379 +
  380 + /**
  381 + * 承接经营单位
  382 + */
  383 + garOrderCompanyId: companyObj.value.id,
  384 +
  385 + /**
  386 + * 公司名称
  387 + */
  388 + garOrderCompanyName: companyObj.value.name,
  389 +
  390 + /**
  391 + * 公司负责人电话
  392 + */
  393 + garOrderCompanyTel: companyObj.value.servicePhone,
  394 +
  395 + /**
  396 + * 约定时间
  397 + */
  398 + garOrderAgreementTime: dayTime.value,
  399 + /**
  400 + * 备注
  401 + */
  402 + garRemark: paramFrom.value.remark,
  403 + /**
  404 + * 图片列表
  405 + */
  406 + imageUrls: fileList.value.map(item => item.url),
  407 + garLongitude: userAddress.value.garLongitude,
  408 + garLatitude: userAddress.value.garLatitude,
  409 + garCoordinate: userAddress.value.garCoordinate,
  410 + }
  411 + if (!validateParams(params)) {
  412 + return;
  413 + }
  414 +
  415 + saveOrder(params).then(res => {
  416 + // TODO 派单详情
  417 + if (res.data.success) {
  418 + if (userType.value === "运输驾驶员") {
  419 + uni.$u.toast("派单成功,请切换成且角色查看派单详情")
  420 + setTimeout(() => {
  421 + uni.$u.route({
  422 + type: 'navigateBack',
  423 + url: `pages/home/index`,
  424 + })
  425 + }, 300)
  426 + } else {
  427 + uni.$u.route({
  428 + type: "redirect",
  429 + url: `pages/order/detail/index`,
  430 + params: {
  431 + orderId: res.data.data
  432 + }
  433 + })
  434 + uni.$u.toast(res.data.msg)
  435 + }
  436 +
  437 + }
  438 + })
  439 +}
  440 +
  441 +
  442 +/**
  443 + * 校验参数
  444 + * @param {Object} params
  445 + */
  446 +const validateParams = (params) => {
  447 + if (!paramFrom.value.sureReadFlag[0]) {
  448 + jumpPrompt('请勾选"本人已确认信息真实有效,并将上诉信息告知市容环境卫生主管部门"')
  449 + return false;
  450 + }
  451 + for (const key in params) {
  452 + if (!params[key] && key != "garRemark") {
  453 + switch (key) {
  454 + case "garOrderAgreementTime":
  455 + jumpPrompt('请选择预约时间')
  456 + break;
  457 +
  458 + }
  459 + return false;
  460 + }
  461 + if (key === "garCarInfoList") {
  462 + let count = 0;
  463 + params[key].forEach(item => {
  464 + count += item.garOrderCarNumber;
  465 + })
  466 + if (count === 0) {
  467 + jumpPrompt('请添加车辆数量')
  468 + return false;
  469 + }
  470 + }
  471 +
  472 + if (key == "imageUrls") {
  473 + if (params[key].length == 0) {
  474 + jumpPrompt('请上传现场图片')
  475 + return false;
  476 + }
  477 + if (!validateImage(params[key])) {
  478 + uni.$u.toast('请等待图片上传完毕')
  479 + return false;
  480 + }
  481 + }
  482 + }
  483 + return true;
  484 +}
  485 +
  486 +const jumpPrompt = (msg) => {
  487 + uni.showModal({
  488 + title: '提示',
  489 + content: msg,
  490 + showCancel: false,
  491 + success: function (res) {
  492 + if (res.confirm) {
  493 + } else if (res.cancel) {
  494 + }
  495 + }
  496 + });
  497 +}
  498 +const validateImage = (fileList) => {
  499 + for (let index = 0; index < fileList.length; index++) {
  500 + const str = fileList[index];
  501 + if (!str.startsWith("/profile/upload")) {
  502 + return false;
  503 + }
  504 + }
  505 + return true;
  506 +}
  507 +
  508 +
  509 +// 开始执行一次
  510 +watch(carPopupShowFlag, (val) => {
  511 + // console.log(val);
  512 + // carPopupShowFlag.value = val
  513 + if (!val) {
  514 + setTimeout(() => {
  515 + nextTick(() => {
  516 + let areaHeight;
  517 + // select中的参数就如css选择器一样选择元素
  518 + let movableArea = uni.createSelectorQuery().in(proxy).select(".movableArea");
  519 + movableArea.boundingClientRect(function (data) {
  520 + // data - 包含元素的高度等信息
  521 + areaHeight = data.height;
  522 + y.value = areaHeight > 40 ? (areaHeight - 40) : areaHeight;
  523 + }).exec(function (res) {
  524 + // 注意:exec方法必须执行,即便什么也不做,否则不会获取到任何数据
  525 + })
  526 + })
  527 + }, 0);
  528 + }
  529 +}, {
  530 + immediate: true
  531 +})
  532 +
  533 +</script>
  534 +
  535 +<style lang="scss" scoped>
  536 +$custom-marin-bottom: 20rpx;
  537 +$custom-page-padding: 20rpx;
  538 +$custom-border-radio: 20rpx;
  539 +$custom-bottom-height: 200rpx;
  540 +
  541 +
  542 +.company-clean-container {
  543 + height: 100%;
  544 + width: 100%;
  545 + background-color: $u-info-light;
  546 + box-sizing: border-box;
  547 + overflow-y: scroll;
  548 +
  549 +
  550 + .company-clean-container-box {
  551 + height: 100%;
  552 + width: 100%;
  553 + padding: $custom-page-padding;
  554 + box-sizing: border-box;
  555 +
  556 + .company-clean-container-header {
  557 + padding: $custom-page-padding;
  558 + box-sizing: border-box;
  559 + background-color: #ffffff;
  560 + border-radius: $custom-border-radio;
  561 + margin-bottom: $custom-marin-bottom;
  562 +
  563 + .company-clean-container-header-address {
  564 + font-size: 30rpx;
  565 + font-weight: bold;
  566 + color: $u-main-color;
  567 + }
  568 +
  569 + .company-clean-container-header-base-info {
  570 + font-size: 25rpx;
  571 + color: $u-info;
  572 + line-height: 80rpx;
  573 + }
  574 +
  575 + .company-clean-container-header-reservation {
  576 + display: flex;
  577 + justify-content: space-between;
  578 + font-size: 25rpx;
  579 + @include handleClick;
  580 +
  581 + .company-clean-container-header-reservation-left {
  582 + display: flex;
  583 + align-items: center;
  584 + color: $u-content-color;
  585 + }
  586 +
  587 + .company-clean-container-header-reservation-right {
  588 + display: flex;
  589 + align-items: center;
  590 + color: $u-content-color;
  591 + }
  592 + }
  593 +
  594 +
  595 + }
  596 +
  597 + .company-clean-container-car-main {
  598 + padding: $custom-page-padding;
  599 + border-radius: $custom-border-radio;
  600 + box-sizing: border-box;
  601 + background-color: #ffffff;
  602 + margin-bottom: $custom-marin-bottom;
  603 +
  604 + .company-clean-container-car-main-title {
  605 + font-size: 30rpx;
  606 + font-weight: bold;
  607 + color: #a9e08f;
  608 + display: flex;
  609 + justify-content: center;
  610 + }
  611 +
  612 + .company-clean-container-car-main-content {
  613 + width: 100%;
  614 + display: flex;
  615 + flex-direction: column;
  616 + justify-content: center;
  617 +
  618 + .company-clean-container-car-main-content-img {
  619 + width: 600rpx;
  620 + height: 400rpx;
  621 +
  622 + .company-clean-container-car-main-content-img {
  623 + width: 600rpx;
  624 + height: 400rpx;
  625 + }
  626 + }
  627 +
  628 + .company-clean-container-car-main-content-remark {
  629 + color: $u-tips-color;
  630 + font-size: 23rpx;
  631 + line-height: 30rpx;
  632 + padding: $custom-page-padding;
  633 + background-color: $u-info-light;
  634 + word-break: break-all;
  635 + }
  636 +
  637 + .company-clean-container-car-main-content-type {
  638 + margin-top: $custom-marin-bottom;
  639 + margin-bottom: $custom-marin-bottom;
  640 + display: flex;
  641 + justify-content: space-between;
  642 + border-radius: $custom-border-radio;
  643 + // background-color: $u-info-light;
  644 + box-sizing: border-box;
  645 +
  646 + .company-clean-container-car-main-content-type-price-area {
  647 + display: flex;
  648 + justify-content: flex-start;
  649 + align-items: center;
  650 + color: $u-info;
  651 + white-space: nowrap;
  652 + }
  653 + }
  654 +
  655 + .company-clean-container-car-main-content-number {
  656 + display: flex;
  657 + justify-content: space-between;
  658 + font-size: 28rpx;
  659 + color: $u-tips-color;
  660 + font-weight: small;
  661 + align-items: center;
  662 +
  663 + .company-clean-container-car-main-content-number-txt {
  664 + line-height: 80rpx;
  665 + }
  666 +
  667 + .company-clean-container-car-main-content-number-button {}
  668 + }
  669 + }
  670 +
  671 +
  672 + }
  673 +
  674 + .company-clean-container-car-main-content-prompt {
  675 + color: $u-tips-color;
  676 + font-size: 23rpx;
  677 + line-height: 30rpx;
  678 + padding: $custom-page-padding;
  679 + word-break: break-all;
  680 + text-align: center;
  681 + }
  682 +
  683 + .company-clean-container-site-image-info {
  684 + padding: $custom-page-padding;
  685 + background-color: #ffffff;
  686 + border-radius: $custom-border-radio;
  687 + color: $u-info;
  688 + font-size: 28rpx;
  689 + margin-bottom: $custom-marin-bottom;
  690 +
  691 + .company-clean-container-site-image-info-remark {
  692 + line-height: 80rpx;
  693 +
  694 + }
  695 +
  696 + .company-clean-container-site-image-info-img {}
  697 +
  698 + .company-clean-container-site-image-info-input-remark {
  699 + line-height: 80rpx;
  700 + }
  701 +
  702 + .company-clean-container-site-image-info-input-remark-box {}
  703 + }
  704 +
  705 + .company-clean-container-site-image-info-sure-button {
  706 + padding-bottom: $custom-bottom-height;
  707 + font-size: 28rpx;
  708 +
  709 + .company-clean-container-site-image-info-sure-button-radio {
  710 + padding: $custom-page-padding;
  711 + box-sizing: border-box;
  712 + display: flex;
  713 + // flex-flow: row wrap;
  714 + font-size: 25rpx;
  715 + color: $u-info;
  716 + }
  717 + }
  718 + }
  719 +
  720 + .company-clean-bottom {
  721 + position: absolute;
  722 + width: 100%;
  723 + // height: 100%;
  724 + bottom: 0;
  725 + left: 0;
  726 + // 阴影
  727 + box-shadow: 0 0 10rpx 0 rgba(0, 0, 0, 0.1);
  728 +
  729 + .movableArea {
  730 + pointer-events: none;
  731 + position: fixed;
  732 + left: 0;
  733 + top: 0;
  734 + width: 100%;
  735 + height: calc(100% - $custom-bottom-height);
  736 + // z-index: 99;
  737 +
  738 + .movableView {
  739 + pointer-events: auto;
  740 + min-height: 60rpx;
  741 + min-width: 60rpx;
  742 +
  743 + .company-clean-call-box-container {
  744 + min-height: 60rpx;
  745 + min-width: 60rpx;
  746 + display: flex;
  747 + align-items: center;
  748 + justify-content: center;
  749 + background-color: #a9e08f;
  750 + border-radius: 100%;
  751 + }
  752 + }
  753 + }
  754 +
  755 + .company-clean-bottom-box {
  756 + height: $custom-bottom-height;
  757 + background-color: #ffffff;
  758 + padding: 50rpx;
  759 + box-sizing: border-box;
  760 + display: flex;
  761 + justify-content: space-between;
  762 + align-items: center;
  763 +
  764 + .company-clean-bottom-left {
  765 + display: flex;
  766 +
  767 + .company-clean-bottom-left-icon {
  768 + transform: rotateY(180deg);
  769 + }
  770 +
  771 + }
  772 +
  773 + .company-clean-bottom-right {
  774 + min-width: 200rpx;
  775 + }
  776 + }
  777 +
  778 + }
  779 +
  780 +
  781 +
  782 +}
  783 +
  784 +.hoverClickStyle {
  785 + @include handleClick;
  786 +}
  787 +
  788 +// 弹出框
  789 +.company-clean-container-car-popup {
  790 + min-height: 450rpx;
  791 + padding: $custom-page-padding;
  792 + box-sizing: border-box;
  793 +
  794 + .company-clean-container-car-popup-content {
  795 + font-size: 28rpx;
  796 +
  797 + .company-clean-container-car-popup-content-box {
  798 + box-sizing: border-box;
  799 + padding: $custom-page-padding;
  800 + border: 2rpx solid #a9e08f;
  801 + border-radius: 10rpx;
  802 +
  803 + .company-clean-container-car-popup-content-box-item {
  804 + display: flex;
  805 + align-items: center;
  806 + justify-content: space-between;
  807 + margin: 20rpx 0;
  808 + box-sizing: border-box;
  809 +
  810 + .company-clean-container-car-popup-content-box-item-text {}
  811 +
  812 + .company-clean-container-car-popup-content-box-item-number {}
  813 + }
  814 + }
  815 +
  816 + .company-clean-container-car-popup-content-title {
  817 + color: $u-main-color;
  818 + box-sizing: border-box;
  819 + margin-bottom: 20rpx;
  820 + font-size: 30rpx;
  821 + font-weight: bold;
  822 + }
  823 + }
  824 +
  825 + .company-clean-container-car-popup-button-safe {
  826 + width: 100%;
  827 + height: $custom-bottom-height;
  828 + }
  829 +}
  830 +</style>
garbage-removal/src/pages/home/clean/index.vue
@@ -60,18 +60,41 @@ @@ -60,18 +60,41 @@
60 <view class="company-clean-container-car-main"> 60 <view class="company-clean-container-car-main">
61 <view class="company-clean-container-car-main-content"> 61 <view class="company-clean-container-car-main-content">
62 <view v-if="paramFrom.carType" class="company-clean-container-car-main-content-type"> 62 <view v-if="paramFrom.carType" class="company-clean-container-car-main-content-type">
63 - <text class="company-clean-container-car-main-content-type-price-area"><text  
64 - style="color: red;">*</text>车辆类型:</text>  
65 - <!-- <uni-combox label="" :candidates="candidates" placeholder="请选择运输车辆类型"  
66 - v-model="paramFrom.carType"></uni-combox> -->  
67 - <view class="" hover-class="hoverClickStyle" @click.stop="handleCarInfoClick(true)"> 63 + <view class="company-clean-container-car-main-content-type-price-area">
  64 + <text style="color: red;">*</text>车辆类型:
  65 + </view>
  66 + <!-- <scrollText :candidates="candidates" /> -->
  67 + <view style="display:flex; align-items: center;" hover-class="hoverClickStyle"
  68 + @click.stop="handleCarInfoClick(true)">
68 <u--input color="#909399" border="none" style="pointer-events:none" :modelValue="paramFrom.carType" 69 <u--input color="#909399" border="none" style="pointer-events:none" :modelValue="paramFrom.carType"
69 type="text" placeholder-class="line" readonly /> 70 type="text" placeholder-class="line" readonly />
70 </view> 71 </view>
71 </view> 72 </view>
  73 + <!-- <view v-if="paramFrom.carType" class="company-clean-container-car-main-content-type">
  74 + <view class="company-clean-container-car-main-content-type-price-area">
  75 + <text style="color: red;">*</text>协商车辆:
  76 + </view>
  77 + <view class="company-clean-container-car-main-content-number-button">
  78 + <u-number-box :min="0" :max="9999" integer buttonSize="46" :inputWidth="100"
  79 + v-model="garCarInfoList[paramFrom.carType].garOrderCarNumber"></u-number-box>
  80 + </view>
  81 + </view> -->
  82 + <view class="company-clean-container-car-main-content">
  83 + <view v-if="paramFrom.carType" class="company-clean-container-car-main-content-type">
  84 + <view class="company-clean-container-car-main-content-type-price-area">
  85 + <text style="color: red;">*</text>车辆数量:
  86 + </view>
  87 + <view class="company-clean-container-car-main-content-number-button" style="width: 308rpx;">
  88 + <u-number-box :min="0" :max="9999" integer buttonSize="46" :inputWidth="100"
  89 + v-model="garCarInfoList[paramFrom.carType].garOrderCarNumber"></u-number-box>
  90 + </view>
  91 + </view>
  92 + </view>
  93 +
72 <view class="company-clean-container-car-main-content-type"> 94 <view class="company-clean-container-car-main-content-type">
73 - <text class="company-clean-container-car-main-content-type-price-area"><text  
74 - style="color: red;">*</text>垃圾类型:</text> 95 + <view class="company-clean-container-car-main-content-type-price-area">
  96 + <text style="color: red;">*</text>垃圾类型:
  97 + </view>
75 <view hover-class="hoverClickStyle" @click.stop="handleGarbageTypeClick(true)"> 98 <view hover-class="hoverClickStyle" @click.stop="handleGarbageTypeClick(true)">
76 <u--input color="#909399" border="none" style="pointer-events:none" :modelValue="paramFrom.garbageType" 99 <u--input color="#909399" border="none" style="pointer-events:none" :modelValue="paramFrom.garbageType"
77 type="text" placeholder-class="line" readonly /> 100 type="text" placeholder-class="line" readonly />
@@ -83,16 +106,6 @@ @@ -83,16 +106,6 @@
83 <view class="company-clean-container-car-main-content-remark"> 106 <view class="company-clean-container-car-main-content-remark">
84 {{ garCarTransportInfo }} 107 {{ garCarTransportInfo }}
85 </view> 108 </view>
86 -  
87 - <view v-if="paramFrom.carType" class="company-clean-container-car-main-content-number">  
88 - <view class="company-clean-container-car-main-content-number-txt">  
89 - <text style="color: red;">*</text>添加车辆数量  
90 - </view>  
91 - <view class="company-clean-container-car-main-content-number-button">  
92 - <u-number-box :min="0" :max="9999" integer buttonSize="46" :inputWidth="100"  
93 - v-model="garCarInfoList[paramFrom.carType].garOrderCarNumber"></u-number-box>  
94 - </view>  
95 - </view>  
96 <view class="company-clean-container-car-main-content-prompt"> 109 <view class="company-clean-container-car-main-content-prompt">
97 温馨提示:垃圾类型不符合,企业有权拒绝清运。 110 温馨提示:垃圾类型不符合,企业有权拒绝清运。
98 </view> 111 </view>
@@ -100,26 +113,46 @@ @@ -100,26 +113,46 @@
100 </view> 113 </view>
101 <view class="company-clean-container-site-image-info"> 114 <view class="company-clean-container-site-image-info">
102 <view class="company-clean-container-site-image-info-remark"> 115 <view class="company-clean-container-site-image-info-remark">
103 - <text style="color: red;">*</text>现场照片(最多上传10张) 116 + <text style="color: red;">*</text>要求装车完成后虚上传现场照片(最少1张,最多上传10张),照片须看清全貌。
104 </view> 117 </view>
105 <view class="company-clean-container-site-image-info-img"> 118 <view class="company-clean-container-site-image-info-img">
106 - <u-upload width="200" height="150" :fileList="fileList" @afterRead="afterRead" @delete="deletePic" name="3"  
107 - multiple :maxCount="10" :previewFullImage="true"></u-upload> 119 + <u-upload width="200" height="150" :fileList="fileList" @afterRead="afterRead" :deletable="deletable"
  120 + @delete="deletePic" name="3" multiple :maxCount="10" :previewFullImage="true"></u-upload>
108 </view> 121 </view>
109 - <view class="company-clean-container-site-image-info-input-remark">  
110 - 填写备注 122 + <view class="company-in-car-store-box">
  123 + <view class="company-in-car-store-box-content"
  124 + style="font-size: 15rpx;display: flex;color: white; justify-content: flex-end;">
  125 + <view
  126 + :class="paramFrom.garInCarStore ? 'company-in-car-store-box-text-yes' : 'company-in-car-store-box-text-no'"
  127 + @click="handleInCarClick" style="padding: 10rpx;box-sizing: border-box;border-radius: 15rpx;">
  128 + 需要进入车库?
  129 + </view>
  130 + </view>
111 </view> 131 </view>
112 - <view class="company-clean-container-site-image-info-input-remark-box">  
113 - <u--textarea v-model="paramFrom.remark" placeholder="请输入内容"></u--textarea> 132 + <view v-if="paramFrom.garInCarStore" class="company-in-car-store-box-info">
  133 + <view class="company-clean-container-site-image-info-input-remark">
  134 + 填写备注
  135 + </view>
  136 + <view class="company-clean-container-site-image-info-input-remark-box">
  137 + <u--textarea v-model="paramFrom.remark" placeholder="请输入内容"></u--textarea>
  138 + </view>
  139 + <view class="company-in-car-store-box-prompt" style="margin-top: 20rpx; font-size: 23rpx;">
  140 + 提示:需要进入车库需要写车辆限高,部门车库限高2.3m,如果装修垃圾在车库,要考虑车辆是否能进入。
  141 + </view>
114 </view> 142 </view>
115 </view> 143 </view>
116 <view class="company-clean-container-site-image-info-sure-button"> 144 <view class="company-clean-container-site-image-info-sure-button">
117 <view class="company-clean-container-site-image-info-sure-button-radio"> 145 <view class="company-clean-container-site-image-info-sure-button-radio">
118 - <u-checkbox-group v-model="paramFrom.sureReadFlag" placement="row">  
119 - <u-checkbox activeColor="#a9e08f" size="25" labelSize="25" shape="circle" @change="changeAgree" :key="0"  
120 - :name="true" :labelDisabled="true" labelColor="#909399"  
121 - label="本人已确认信息真实有效,并将上述信息告知市容环境卫生主管部门。"></u-checkbox>  
122 - </u-checkbox-group> 146 + <view @click="changeAgree">
  147 + <u-checkbox-group v-model="paramFrom.sureReadFlag" placement="row">
  148 + <u-checkbox activeColor="#5ac725" :customStyle="{ marginBottom: '0px', marginTop: '1px' }" size="25"
  149 + labelSize="25" shape="square" :key="0" :name="true" :labelDisabled="true"
  150 + labelColor="#909399"></u-checkbox>
  151 + </u-checkbox-group>
  152 + </view>
  153 + <view>
  154 + 本人已确认信息真实有效,并将上述信息告知市容环境卫生主管部门。
  155 + </view>
123 </view> 156 </view>
124 </view> 157 </view>
125 </view> 158 </view>
@@ -141,7 +174,7 @@ @@ -141,7 +174,7 @@
141 </view> 174 </view>
142 </view> 175 </view>
143 <view class="company-clean-bottom-right"> 176 <view class="company-clean-bottom-right">
144 - <u-button @click="handleOderSure" shape="circle" color="#a9e08f" text="立即派单"></u-button> 177 + <u-button @click="handleOderSure" shape="square" color="#a9e08f" text="立即派单"></u-button>
145 </view> 178 </view>
146 </view> 179 </view>
147 </view> 180 </view>
@@ -153,16 +186,17 @@ import { queryCarList } from &#39;@/apis/carinfo.js&#39;; @@ -153,16 +186,17 @@ import { queryCarList } from &#39;@/apis/carinfo.js&#39;;
153 import { uploadFilePromise } from '@/apis/common.js'; 186 import { uploadFilePromise } from '@/apis/common.js';
154 import { saveOrder } from '@/apis/order.js'; 187 import { saveOrder } from '@/apis/order.js';
155 import liuDeliveryTime from "@/components/liu-delivery-time/liu-delivery-time.vue"; 188 import liuDeliveryTime from "@/components/liu-delivery-time/liu-delivery-time.vue";
  189 +import garbageUrl from '@/static/image/garbage.png';
156 import { useMainStore } from '@/stores/index.js'; 190 import { useMainStore } from '@/stores/index.js';
157 import { onLoad } from '@dcloudio/uni-app'; 191 import { onLoad } from '@dcloudio/uni-app';
158 import { computed, getCurrentInstance, nextTick, ref, watch } from 'vue'; 192 import { computed, getCurrentInstance, nextTick, ref, watch } from 'vue';
159 const { proxy } = getCurrentInstance(); 193 const { proxy } = getCurrentInstance();
160 -  
161 const store = useMainStore(); 194 const store = useMainStore();
162 const userType = computed(() => store.userType) 195 const userType = computed(() => store.userType)
163 const x = ref(5) 196 const x = ref(5)
164 const y = ref() 197 const y = ref()
165 const movableAreaElement = ref() 198 const movableAreaElement = ref()
  199 +const deletable = ref(false)
166 const companyObj = ref() 200 const companyObj = ref()
167 const tel = ref() 201 const tel = ref()
168 const carTypeShowFlag = ref(false) 202 const carTypeShowFlag = ref(false)
@@ -223,12 +257,19 @@ const paramFrom = ref({ @@ -223,12 +257,19 @@ const paramFrom = ref({
223 remark: "", 257 remark: "",
224 sureReadFlag: [], 258 sureReadFlag: [],
225 carType: "", 259 carType: "",
226 - garbageType: "装修垃圾" 260 + garbageType: ["装修垃圾"],
  261 + garInCarStore: false
  262 +
227 }) 263 })
228 const dayTime = ref() 264 const dayTime = ref()
229 265
230 const chooseTime = ref() 266 const chooseTime = ref()
231 -const fileList = ref([]) 267 +const fileList = ref([
  268 + {
  269 + url: garbageUrl,
  270 + label: '预览'
  271 + }
  272 +])
232 const candidates = ref([]) 273 const candidates = ref([])
233 const handleTimeChoose = () => { 274 const handleTimeChoose = () => {
234 chooseTime.value.open(); 275 chooseTime.value.open();
@@ -239,6 +280,7 @@ const changeTime = (e) =&gt; { @@ -239,6 +280,7 @@ const changeTime = (e) =&gt; {
239 } 280 }
240 const changeAgree = (e) => { 281 const changeAgree = (e) => {
241 // paramFrom.value.sureReadFlag = e 282 // paramFrom.value.sureReadFlag = e
  283 + paramFrom.value.sureReadFlag[0] = !paramFrom.value.sureReadFlag[0]
242 } 284 }
243 const onChange = (e) => { 285 const onChange = (e) => {
244 // console.log(e); 286 // console.log(e);
@@ -277,6 +319,9 @@ onLoad((options) =&gt; { @@ -277,6 +319,9 @@ onLoad((options) =&gt; {
277 }) 319 })
278 }) 320 })
279 321
  322 +const handleInCarClick = () => {
  323 + paramFrom.value.garInCarStore = !paramFrom.value.garInCarStore
  324 +}
280 325
281 const handleCarInfoClick = (val) => { 326 const handleCarInfoClick = (val) => {
282 carTypeShowFlag.value = val 327 carTypeShowFlag.value = val
@@ -321,6 +366,10 @@ const afterRead = async (event) =&gt; { @@ -321,6 +366,10 @@ const afterRead = async (event) =&gt; {
321 }); 366 });
322 fileListLen++; 367 fileListLen++;
323 } 368 }
  369 + fileList.value = fileList.value.filter(item => {
  370 + deletable.value = true
  371 + return !item.label
  372 + })
324 }; 373 };
325 374
326 375
@@ -364,7 +413,7 @@ const handleOderSure = () =&gt; { @@ -364,7 +413,7 @@ const handleOderSure = () =&gt; {
364 /** 413 /**
365 * 垃圾类型 414 * 垃圾类型
366 */ 415 */
367 - garOrderTrashType: paramFrom.value.garbageType, 416 + garOrderTrashType: paramFrom.value.garbageType[0],
368 417
369 /** 418 /**
370 * 派单人电话 419 * 派单人电话
@@ -397,10 +446,11 @@ const handleOderSure = () =&gt; { @@ -397,10 +446,11 @@ const handleOderSure = () =&gt; {
397 /** 446 /**
398 * 图片列表 447 * 图片列表
399 */ 448 */
400 - imageUrls: fileList.value.map(item => item.url), 449 + imageUrls: fileList.value.filter(item => !item.label).map(item => item.url),
401 garLongitude: userAddress.value.garLongitude, 450 garLongitude: userAddress.value.garLongitude,
402 garLatitude: userAddress.value.garLatitude, 451 garLatitude: userAddress.value.garLatitude,
403 garCoordinate: userAddress.value.garCoordinate, 452 garCoordinate: userAddress.value.garCoordinate,
  453 + garInCarStore: paramFrom.value.garInCarStore
404 } 454 }
405 if (!validateParams(params)) { 455 if (!validateParams(params)) {
406 return; 456 return;
@@ -410,7 +460,7 @@ const handleOderSure = () =&gt; { @@ -410,7 +460,7 @@ const handleOderSure = () =&gt; {
410 // TODO 派单详情 460 // TODO 派单详情
411 if (res.data.success) { 461 if (res.data.success) {
412 if (userType.value === "运输驾驶员") { 462 if (userType.value === "运输驾驶员") {
413 - uni.$u.toast("派单成功,请切换成且角色查看单详情") 463 + uni.$u.toast("派单成功,请切换成且角色查看单详情")
414 setTimeout(() => { 464 setTimeout(() => {
415 uni.$u.route({ 465 uni.$u.route({
416 type: 'navigateBack', 466 type: 'navigateBack',
@@ -438,11 +488,16 @@ const handleOderSure = () =&gt; { @@ -438,11 +488,16 @@ const handleOderSure = () =&gt; {
438 * @param {Object} params 488 * @param {Object} params
439 */ 489 */
440 const validateParams = (params) => { 490 const validateParams = (params) => {
  491 +
441 if (!paramFrom.value.sureReadFlag[0]) { 492 if (!paramFrom.value.sureReadFlag[0]) {
442 jumpPrompt('请勾选"本人已确认信息真实有效,并将上诉信息告知市容环境卫生主管部门"') 493 jumpPrompt('请勾选"本人已确认信息真实有效,并将上诉信息告知市容环境卫生主管部门"')
443 return false; 494 return false;
444 } 495 }
445 for (const key in params) { 496 for (const key in params) {
  497 + // 跳过garInCarStore
  498 + if (key == "garInCarStore") {
  499 + continue;
  500 + }
446 if (!params[key] && key != "garRemark") { 501 if (!params[key] && key != "garRemark") {
447 switch (key) { 502 switch (key) {
448 case "garOrderAgreementTime": 503 case "garOrderAgreementTime":
@@ -683,7 +738,7 @@ $custom-bottom-height: 200rpx; @@ -683,7 +738,7 @@ $custom-bottom-height: 200rpx;
683 margin-bottom: $custom-marin-bottom; 738 margin-bottom: $custom-marin-bottom;
684 739
685 .company-clean-container-site-image-info-remark { 740 .company-clean-container-site-image-info-remark {
686 - line-height: 80rpx; 741 + line-height: 50rpx;
687 742
688 } 743 }
689 744
@@ -703,8 +758,9 @@ $custom-bottom-height: 200rpx; @@ -703,8 +758,9 @@ $custom-bottom-height: 200rpx;
703 .company-clean-container-site-image-info-sure-button-radio { 758 .company-clean-container-site-image-info-sure-button-radio {
704 padding: $custom-page-padding; 759 padding: $custom-page-padding;
705 box-sizing: border-box; 760 box-sizing: border-box;
706 - // display: flex; 761 + display: flex;
707 // flex-flow: row wrap; 762 // flex-flow: row wrap;
  763 + font-size: 25rpx;
708 color: $u-info; 764 color: $u-info;
709 } 765 }
710 } 766 }
@@ -820,4 +876,12 @@ $custom-bottom-height: 200rpx; @@ -820,4 +876,12 @@ $custom-bottom-height: 200rpx;
820 height: $custom-bottom-height; 876 height: $custom-bottom-height;
821 } 877 }
822 } 878 }
  879 +
  880 +.company-in-car-store-box-text-yes {
  881 + background: #a9e08f;
  882 +}
  883 +
  884 +.company-in-car-store-box-text-no {
  885 + background: #909399;
  886 +}
823 </style> 887 </style>
garbage-removal/src/pages/home/clean/scroll-text.vue 0 → 100644
  1 +<template>
  2 + <view class="car-type-list-box" :style="activeStyle">
  3 + <span v-for="(item, index) in candidates[0]" :key="index">{{ item }}</span>
  4 +
  5 + </view>
  6 +</template>
  7 +
  8 +<script setup>
  9 +import { getCurrentInstance, onMounted, ref } from "vue";
  10 +const { proxy } = getCurrentInstance();
  11 +const activeStyle = ref({
  12 + height: '100rpx',
  13 + display: 'flex',
  14 + justifyContent: 'center',
  15 + alignItems: 'center',
  16 + flexDirection: 'column',
  17 + overflowY: 'auto',
  18 +})
  19 +// uniapp 限制不能直接获取操作dom只能通过动态绑定style修改样式
  20 +const props = defineProps({
  21 + candidates: {
  22 + type: Array,
  23 + required: true,
  24 + default: () => []
  25 + }
  26 +})
  27 +const columns = ref(props.candidates[0])
  28 +onMounted(() => {
  29 + // carTypeBox.value.style.height = minHeight.value + 'rpx';
  30 +
  31 +
  32 +})
  33 +</script>
  34 +
  35 +<style lang="scss" scoped></style>
garbage-removal/src/pages/home/index.vue
@@ -18,72 +18,101 @@ @@ -18,72 +18,101 @@
18 <!-- 公司容器 --> 18 <!-- 公司容器 -->
19 <view class="company-box"> 19 <view class="company-box">
20 <view class="info-box"> 20 <view class="info-box">
21 - <view class="info-box-item" v-for="(item, index) in infoBoxList" :key="index"> 21 + <view class="info-box-item" hover-class="click-box" v-for="(item, index) in infoBoxList" :key="index">
22 <view class="info-box-item-icon" :class="item.icon"> 22 <view class="info-box-item-icon" :class="item.icon">
23 </view> 23 </view>
24 <view class="info-box-item-text">{{ item.text }}</view> 24 <view class="info-box-item-text">{{ item.text }}</view>
25 </view> 25 </view>
26 </view> 26 </view>
27 <view class="company-container"> 27 <view class="company-container">
28 - <span class="company-label-info">可进行垃圾清运单位</span>  
29 <view class="company-list-box" v-if="addressInfo"> 28 <view class="company-list-box" v-if="addressInfo">
30 <view class="company-list-header"> 29 <view class="company-list-header">
31 <view class="company-list-header-left"> 30 <view class="company-list-header-left">
32 - 综合排序 31 + <u-dropdown>
  32 + <u-dropdown-item :height="'240rpx'" :placement="'left'" v-model="registrationAreaValue"
  33 + @change="handleDropdownAreaChange" :title="'所属区域'" :options="dropdownOptions[0]"></u-dropdown-item>
  34 + <u-dropdown-item :placement="'center'" v-model="carTypeValue" @change="handleDropdownCarChange"
  35 + :title="'车辆类型'" :options="dropdownOptions[1]"></u-dropdown-item>
  36 + <u-dropdown-item :placement="'right'" v-model="sortValue" @change="handleDropdownSortChange"
  37 + :title="dropdownOptions[2][sortValue].label" :options="dropdownOptions[2]"></u-dropdown-item>
  38 + </u-dropdown>
33 </view> 39 </view>
34 - <view class="company-list-header-right">  
35 - <u-search placeholder="请输入" :searchIconSize="40" disabled @click="handleSearchClick"  
36 - :showAction="false"></u-search> 40 + <view class="company-list-header-right" @tap.stop="handleSearchClick">
  41 + <view
  42 + style="display: inline-block; width: 100%;pointer-events: none;margin: 10rpx 0rpx; box-sizing: border-box;">
  43 + <u-search :searchIconSize="40" :disabled="true" :placeholder="'搜索'" :showAction="false"></u-search>
  44 + </view>
37 </view> 45 </view>
38 </view> 46 </view>
39 <view class="company-list-content"> 47 <view class="company-list-content">
40 <view class="company-list-content-box"> 48 <view class="company-list-content-box">
41 <z-paging ref="paging" :fixed="false" v-model="companyList" @query="queryList"> 49 <z-paging ref="paging" :fixed="false" v-model="companyList" @query="queryList">
42 <empty-view slot:empty></empty-view> 50 <empty-view slot:empty></empty-view>
43 - <view class="company-list-item" v-for="item in companyList" :key="item.id"> 51 + <view class="company-list-item" v-for="(item, index) in companyList" :key="item.id">
44 <view class="company-list-item-main"> 52 <view class="company-list-item-main">
45 - <view class="company-list-item-main-left">  
46 - <image class="company-list-item-main-left-img"  
47 - :src="item.carParkPanorama ? item.carParkPanorama : 'https://ijry.github.io/uview-plus/h5/assets/logo-8d54bbeb.png'" />  
48 - </view>  
49 - <view class="company-list-item-main-right"  
50 - @click="handleDetailClick(item, item.servicePhone, userAddress)"> 53 + <view class="company-list-item-main-right">
51 <view class="company-list-item-main-right-name"> 54 <view class="company-list-item-main-right-name">
52 - {{ item.name }} 55 + <view class="company-list-item-main-right-name-label-recently"
  56 + v-if="index == 0 && sortValue == 0">
  57 + {{ "距离最近" }}
  58 + </view>
  59 + <view class="company-list-item-main-right-name-label-distance">
  60 + {{ "距离" + item.distance + "公里" }}
  61 + </view>
  62 + <view class="company-list-item-main-right-name-label-name">
  63 + {{ item.name }}
  64 + </view>
53 </view> 65 </view>
54 - <view class="company-list-item-main-right-score">  
55 - <text class="company-list-item-main-right-text">评分:</text>  
56 - <view v-if="item.score != 0" class="company-list-item-main-right-score-start">  
57 - <!-- <u-icon v-for="todo in maxStar" :name="item.score > todo ? 'star-fill' : 'star'" :key="todo" 66 + <view class="company-list-item-main-box" style="display: flex;">
  67 + <view class="company-list-item-main-left-box" style="flex: 1;">
  68 + <view class="company-list-item-main-bottom-box"
  69 + @click="handleDetailClick(item, item.servicePhone, userAddress)">
  70 + <view class="company-list-item-main-right-score">
  71 + <text class="company-list-item-main-right-text">评分:</text>
  72 + <view v-if="item.score != 0" class="company-list-item-main-right-score-start">
  73 + <!-- <u-icon v-for="todo in maxStar" :name="item.score > todo ? 'star-fill' : 'star'" :key="todo"
58 color="#f9ae3d" size="28"></u-icon> --> 74 color="#f9ae3d" size="28"></u-icon> -->
59 - <u-rate activeColor="#f9ae3d" inactive-color="#f9ae3d" size="28" :modelValue="item.score"  
60 - allowHalf readonly></u-rate> 75 + <u-rate activeColor="#f9ae3d" inactive-color="#f9ae3d" size="28"
  76 + :modelValue="item.score" allowHalf readonly></u-rate>
  77 + </view>
  78 + <text v-if="item.score > 0" class="company-list-item-main-right-text"
  79 + style="color: #fd5d00;">
  80 + {{ item.score }}分
  81 + </text>
  82 + <text v-else class="company-list-item-main-right-text"
  83 + style="color: #fd5d00;">最近一月暂无评分</text>
  84 + </view>
  85 + <view class="company-list-item-main-right-price-number">
  86 + <view class="company-list-item-main-right-price">
  87 + 报价:<text style="color: #fd5d00;">¥400起&nbsp;&nbsp;</text>
  88 + </view>
  89 + <view class="company-list-item-main-right-number">
  90 + 清运数:<text class="company-list-item-main-right-number-text">{{ item.cleanNumber }}</text>
  91 + </view>
  92 + </view>
  93 + </view>
  94 + <view class="company-list-item-bottom-contact-company" style="display: flex;">
  95 + <up-icon name="phone" color="#a9e08f"></up-icon>
  96 + <view @click="handleContactClick(item.servicePhone)"
  97 + style="display: flex; justify-content: center; align-items: center" color="#a9e08f">
  98 + {{ item.servicePhone }}
  99 + </view>
  100 + </view>
61 </view> 101 </view>
62 - <text v-if="item.score > 0" class="company-list-item-main-right-text" style="color: #fd5d00;">{{  
63 - item.score }}分</text>  
64 - <text v-else class="company-list-item-main-right-text" style="color: #fd5d00;">最近一月暂无评分</text>  
65 - </view>  
66 - <view class="company-list-item-main-right-price-number">  
67 - <view class="company-list-item-main-right-price">报价:<text  
68 - style="color: #fd5d00;">¥400起&nbsp;&nbsp;</text></view>  
69 - <view class="company-list-item-main-right-number">  
70 - 清运数:<text class="company-list-item-main-right-number-text">{{ item.cleanNumber }}</text> 102 + <view class="company-list-item-main-right-box"
  103 + style="display: flex; justify-content: flex-end; align-items: flex-end;color:#458B74;font-weight: bold;">
  104 + <view class="company-list-item-main-right-box-text"
  105 + @click="handleCleanGarbage(item, item.servicePhone, userAddress)">
  106 + 垃圾清运 ->
  107 + </view>
71 </view> 108 </view>
72 </view> 109 </view>
73 - <view class="company-list-item-main-right-remark"> 110 + <!-- <view class="company-list-item-main-right-remark">
74 {{ item.remark }} 111 {{ item.remark }}
75 - </view> 112 + </view> -->
76 </view> 113 </view>
77 </view> 114 </view>
78 <view class="company-list-item-bottom"> 115 <view class="company-list-item-bottom">
79 - <view class="company-list-item-bottom-contact-company">  
80 - <u-button @click="handleContactClick(item.servicePhone)" color="#a9e08f" size="normal"  
81 - type="success" :hairline="true" shape="circle" text="联系公司"></u-button>  
82 - </view>  
83 - <view class="company-list-item-bottom-button-clean">  
84 - <u-button @click="handleCleanGarbage(item, item.servicePhone, userAddress)" type="success"  
85 - :hairline="true" size="normal" shape="circle" text="垃圾清运"></u-button>  
86 - </view>  
87 </view> 116 </view>
88 </view> 117 </view>
89 </z-paging> 118 </z-paging>
@@ -108,7 +137,7 @@ @@ -108,7 +137,7 @@
108 </view> 137 </view>
109 </template> 138 </template>
110 139
111 -<script setup > 140 +<script setup>
112 import { queryAddress } from '@/apis/address.js'; 141 import { queryAddress } from '@/apis/address.js';
113 import { queryEnterpriseList } from '@/apis/company.js'; 142 import { queryEnterpriseList } from '@/apis/company.js';
114 import { onLoad, onShow } from '@dcloudio/uni-app'; 143 import { onLoad, onShow } from '@dcloudio/uni-app';
@@ -121,13 +150,72 @@ const topMargin = ref(null);//状态栏高度 @@ -121,13 +150,72 @@ const topMargin = ref(null);//状态栏高度
121 const musicheadHeight = ref(); 150 const musicheadHeight = ref();
122 const paging = ref(null) 151 const paging = ref(null)
123 const swiperImageList = ref([{ 152 const swiperImageList = ref([{
124 - image: 'https://cdn.uviewui.com/uview/swiper/swiper1.png', 153 + image: 'https://tse2-mm.cn.bing.net/th/id/OIP-C.o6VdtT8EY8mHjzoX7qAlrQAAAA?w=261&h=180&c=7&r=0&o=5&dpr=1.5&pid=1.7'
125 }, { 154 }, {
126 - image: 'https://cdn.uviewui.com/uview/swiper/swiper3.png', 155 + image: 'https://tse3-mm.cn.bing.net/th/id/OIP-C.LwNUQLX3A3PIJ0Rzm4ATOwHaEQ?w=304&h=180&c=7&r=0&o=5&dpr=1.5&pid=1.7',
127 }]) 156 }])
128 157
129 const userAddress = ref({}) 158 const userAddress = ref({})
130 const addressInfo = ref() 159 const addressInfo = ref()
  160 +const sortValue = ref(0)
  161 +const registrationAreaValue = ref('')
  162 +const registrationAreaRealValue = ref('')
  163 +const carTypeValue = ref('')
  164 +const carTypeRealValue = ref('')
  165 +const dropdownOptions = ref([
  166 + [{
  167 + label: '芙蓉区',
  168 + value: '芙蓉区',
  169 + },
  170 + {
  171 + label: '天心区',
  172 + value: '天心区'
  173 + },
  174 + {
  175 + label: '岳麓区',
  176 + value: '岳麓区'
  177 + },
  178 + {
  179 + label: '开福区',
  180 + value: '开福区'
  181 + },
  182 + {
  183 + label: '雨花区',
  184 + value: '雨花区'
  185 + },
  186 + {
  187 + label: '望城区',
  188 + value: '望城区'
  189 + },
  190 + {
  191 + label: '长沙县',
  192 + value: '长沙县'
  193 + },
  194 + {
  195 + label: '浏阳市',
  196 + value: '浏阳市'
  197 + },
  198 + {
  199 + label: '宁乡市',
  200 + value: '宁乡市'
  201 + }
  202 + ], [{
  203 + label: '暂未开放',
  204 + value: '暂未开放',
  205 + },]
  206 + , [{
  207 + label: '距离排序',
  208 + value: 0,
  209 + },
  210 + {
  211 + label: '清运排序',
  212 + value: 1
  213 + },
  214 + {
  215 + label: '评价排序',
  216 + value: 2
  217 + }]
  218 +])
131 219
132 // 信息指南 220 // 信息指南
133 const infoBoxList = ref([{ 221 const infoBoxList = ref([{
@@ -159,6 +247,39 @@ const handleContactClick = (val) =&gt; { @@ -159,6 +247,39 @@ const handleContactClick = (val) =&gt; {
159 } 247 }
160 248
161 /** 249 /**
  250 + * 下拉框改变
  251 + * @param {number} val
  252 + */
  253 +const handleDropdownSortChange = (val) => {
  254 + sortValue.value = val;
  255 + // 重新获取列表
  256 + paging.value.reload()
  257 +}
  258 +const handleDropdownAreaChange = (val) => {
  259 + if (registrationAreaRealValue.value == val) {
  260 + registrationAreaValue.value = ''
  261 + registrationAreaRealValue.value = ''
  262 + // 重新获取列表
  263 + paging.value.reload()
  264 + return
  265 + }
  266 + registrationAreaRealValue.value = val;
  267 + // 重新获取列表
  268 + paging.value.reload()
  269 +}
  270 +const handleDropdownCarChange = (val) => {
  271 + if (carTypeRealValue.value == val) {
  272 + carTypeValue.value = ''
  273 + carTypeRealValue.value = ''
  274 + // 重新获取列表
  275 + paging.value.reload()
  276 + return
  277 + }
  278 + carTypeRealValue.value = val;
  279 + // 重新获取列表
  280 + paging.value.reload()
  281 +}
  282 +/**
162 * 跳转地址 283 * 跳转地址
163 */ 284 */
164 function handleAddressInfo() { 285 function handleAddressInfo() {
@@ -202,9 +323,7 @@ const handleCleanClick = () =&gt; { @@ -202,9 +323,7 @@ const handleCleanClick = () =&gt; {
202 } 323 }
203 } 324 }
204 }); 325 });
205 -  
206 } 326 }
207 -  
208 return 327 return
209 328
210 } 329 }
@@ -229,8 +348,10 @@ const handleCleanGarbage = (companyObj, tel, userAddress) =&gt; { @@ -229,8 +348,10 @@ const handleCleanGarbage = (companyObj, tel, userAddress) =&gt; {
229 /** 348 /**
230 * 搜索 349 * 搜索
231 */ 350 */
232 -const handleSearchClick = () => {  
233 - console.log("search"); 351 +const handleSearchClick = (e) => {
  352 + uni.$u.route({
  353 + url: `pages/home/search/index`,
  354 + })
234 } 355 }
235 356
236 /** 357 /**
@@ -281,8 +402,16 @@ const initData = () =&gt; { @@ -281,8 +402,16 @@ const initData = () =&gt; {
281 }) 402 })
282 } 403 }
283 const queryList = (pageNo, pageSize) => { 404 const queryList = (pageNo, pageSize) => {
  405 + let query = {
  406 + companyType: 1,
  407 + pageNum: pageNo,
  408 + pageSize,
  409 + orderByColumn: sortValue.value,
  410 + registrationArea: registrationAreaValue.value,
  411 + searchValue: carTypeValue.value
  412 + }
284 // 查询公司信息 413 // 查询公司信息
285 - queryEnterpriseList({ companyType: 1, pageNum: pageNo, pageSize }).then(res => { 414 + queryEnterpriseList(query).then(res => {
286 paging.value.complete(res.data.data.list); 415 paging.value.complete(res.data.data.list);
287 }) 416 })
288 } 417 }
@@ -310,13 +439,19 @@ const queryList = (pageNo, pageSize) =&gt; { @@ -310,13 +439,19 @@ const queryList = (pageNo, pageSize) =&gt; {
310 439
311 ::v-deep .u-swiper { 440 ::v-deep .u-swiper {
312 height: 400rpx !important; 441 height: 400rpx !important;
  442 + background-size: 100% 100% !important;
313 443
314 .u-swiper__wrapper { 444 .u-swiper__wrapper {
315 height: 400rpx !important; 445 height: 400rpx !important;
  446 + background-size: 100% 100% !important;
316 } 447 }
317 448
318 .u-swiper__wrapper__item__wrapper__image { 449 .u-swiper__wrapper__item__wrapper__image {
319 height: 400rpx !important; 450 height: 400rpx !important;
  451 +
  452 + &>div {
  453 + background-size: 100% 100% !important;
  454 + }
320 } 455 }
321 } 456 }
322 457
@@ -356,7 +491,7 @@ const queryList = (pageNo, pageSize) =&gt; { @@ -356,7 +491,7 @@ const queryList = (pageNo, pageSize) =&gt; {
356 z-index: 200; 491 z-index: 200;
357 box-sizing: border-box; 492 box-sizing: border-box;
358 padding: 30rpx; 493 padding: 30rpx;
359 - margin-top: 330rpx; 494 + margin-top: 300rpx;
360 flex: 1; 495 flex: 1;
361 display: flex; 496 display: flex;
362 flex-direction: column; 497 flex-direction: column;
@@ -460,16 +595,16 @@ const queryList = (pageNo, pageSize) =&gt; { @@ -460,16 +595,16 @@ const queryList = (pageNo, pageSize) =&gt; {
460 flex: 1; 595 flex: 1;
461 display: flex; 596 display: flex;
462 flex-direction: column; 597 flex-direction: column;
  598 + box-sizing: border-box;
463 599
464 .company-list-header { 600 .company-list-header {
465 - display: flex;  
466 font-size: small; 601 font-size: small;
467 font-weight: small; 602 font-weight: small;
468 align-items: center; 603 align-items: center;
469 604
470 .company-list-header-left { 605 .company-list-header-left {
471 - width: 200rpx;  
472 text-align: center; 606 text-align: center;
  607 + margin-bottom: 15rpx;
473 } 608 }
474 609
475 .company-list-header-right { 610 .company-list-header-right {
@@ -520,14 +655,49 @@ const queryList = (pageNo, pageSize) =&gt; { @@ -520,14 +655,49 @@ const queryList = (pageNo, pageSize) =&gt; {
520 font-size: 25rpx; 655 font-size: 25rpx;
521 656
522 .company-list-item-main-right-name { 657 .company-list-item-main-right-name {
523 - font-weight: bold; 658 + // font-weight: bold;
524 color: $u-main-color; 659 color: $u-main-color;
525 font-size: 30rpx; 660 font-size: 30rpx;
  661 + display: flex;
  662 + line-height: 20rpx !important;
  663 +
  664 + .company-list-item-main-right-name-label-recently {
  665 + margin-right: 10rpx;
  666 + font-size: 16rpx;
  667 + display: flex;
  668 + align-items: center;
  669 + justify-content: center;
  670 + padding: 8rpx 13rpx;
  671 + box-sizing: border-box;
  672 + border-radius: 25rpx;
  673 + background: #19a97c;
  674 + color: #ffffff
  675 + }
  676 +
  677 + .company-list-item-main-right-name-label-distance {
  678 + margin-right: 10rpx;
  679 + font-size: 16rpx;
  680 + display: flex;
  681 + align-items: center;
  682 + justify-content: center;
  683 + padding: 8rpx 13rpx;
  684 + box-sizing: border-box;
  685 + border-radius: 25rpx;
  686 + background: #deab11;
  687 + }
  688 +
  689 + .company-list-item-main-right-name-label-name {
  690 + display: flex;
  691 + align-items: center;
  692 + justify-content: center;
  693 + font-size: 30rpx;
  694 + }
526 } 695 }
527 696
528 .company-list-item-main-right-score { 697 .company-list-item-main-right-score {
529 display: flex; 698 display: flex;
530 font-size: small; 699 font-size: small;
  700 + font-size: 24rpx;
531 701
532 .company-list-item-main-right-text { 702 .company-list-item-main-right-text {
533 text-align: center; 703 text-align: center;
@@ -571,7 +741,9 @@ const queryList = (pageNo, pageSize) =&gt; { @@ -571,7 +741,9 @@ const queryList = (pageNo, pageSize) =&gt; {
571 .company-list-item-bottom { 741 .company-list-item-bottom {
572 display: flex; 742 display: flex;
573 justify-content: space-around; 743 justify-content: space-around;
574 - margin-top: 20rpx; 744 + font-size: 25rpx;
  745 + color: #909399;
  746 + margin-bottom: 50rpx;
575 747
576 .company-list-item-bottom-contact-company { 748 .company-list-item-bottom-contact-company {
577 flex: 1; 749 flex: 1;
@@ -592,6 +764,30 @@ const queryList = (pageNo, pageSize) =&gt; { @@ -592,6 +764,30 @@ const queryList = (pageNo, pageSize) =&gt; {
592 } 764 }
593 } 765 }
594 } 766 }
  767 +}
595 768
  769 +.click-box {
  770 + @include handleClick;
  771 + transform: all 0.5s;
  772 +}
  773 +
  774 +.company-label-title-box {
  775 + width: 100%;
  776 +
  777 + .company-label-title-top {
  778 + display: flex;
  779 + justify-content: space-between;
  780 + width: 100%;
  781 +
  782 + .company-label-title-top-left {
  783 + width: 100%;
  784 + }
  785 +
  786 + .company-label-title-top-right {
  787 + width: 100%;
  788 + display: flex;
  789 + justify-content: flex-end;
  790 + }
  791 + }
596 } 792 }
597 </style> 793 </style>
garbage-removal/src/pages/home/search/index.vue 0 → 100644
  1 +<template>
  2 + <view class="search-container">
  3 + <view class="search-box">
  4 + <u-search placeholder="请输入" :searchIconSize="40" :disabled="true" @click="handleSearchClick"
  5 + :showAction="false"></u-search>
  6 + </view>
  7 + </view>
  8 +</template>
  9 +
  10 +<script setup>
  11 +
  12 +</script>
  13 +
  14 +<style lang="scss" scoped></style>
garbage-removal/src/pages/login/code.vue
@@ -74,7 +74,9 @@ const checkVerifyNum = (code) =&gt; { @@ -74,7 +74,9 @@ const checkVerifyNum = (code) =&gt; {
74 if (res.data.success) { 74 if (res.data.success) {
75 verifyFlag.value = false; 75 verifyFlag.value = false;
76 store.tempToken = res.data.data.token 76 store.tempToken = res.data.data.token
77 - proxy.$u.route(`pages/wode/choose/index`, res.data.data) 77 + uni.navigateTo({
  78 + url: `/pages/wode/choose/index?ruleVos= ${encodeURIComponent(JSON.stringify(res.data.data.ruleVos))}`
  79 + });
78 } else { 80 } else {
79 verifyFlag.value = true; 81 verifyFlag.value = true;
80 } 82 }
garbage-removal/src/pages/login/index.vue
@@ -21,11 +21,14 @@ @@ -21,11 +21,14 @@
21 </view> 21 </view>
22 </view> --> 22 </view> -->
23 <view class="hint"> 23 <view class="hint">
24 - <u-checkbox-group v-model="agree" placement="row" @change="groupChange">  
25 - <u-checkbox shape="circle" :customStyle="{ marginBottom: '8px', marginTop: '2px' }" :key="0" :name="true"  
26 - @change="radioChange">  
27 - </u-checkbox>  
28 - </u-checkbox-group> 24 + <view style="display: flex; justify-content: flex-start;" @click="radioChange">
  25 + <u-checkbox-group v-model="agree" placement="row" @change="groupChange">
  26 + <!-- 选中颜色为绿色 -->
  27 + <u-checkbox shape="square" activeColor="green" :size="24"
  28 + :customStyle="{ marginBottom: '0px', marginTop: '1px' }" :key="0" :name="true">
  29 + </u-checkbox>
  30 + </u-checkbox-group>
  31 + </view>
29 <view class="prompt-txt"> 32 <view class="prompt-txt">
30 登录代表同意 33 登录代表同意
31 <text class="link" @click="handleUserAgreement">用户协议、隐私政策,</text> 34 <text class="link" @click="handleUserAgreement">用户协议、隐私政策,</text>
@@ -41,7 +44,7 @@ import { userLogin } from &quot;@/apis/user.js&quot;; @@ -41,7 +44,7 @@ import { userLogin } from &quot;@/apis/user.js&quot;;
41 export default { 44 export default {
42 data() { 45 data() {
43 return { 46 return {
44 - tel: '18977778888', 47 + tel: '13222222222',
45 agree: [] 48 agree: []
46 } 49 }
47 }, 50 },
@@ -92,8 +95,8 @@ export default { @@ -92,8 +95,8 @@ export default {
92 handleUserAgreement() { 95 handleUserAgreement() {
93 console.log("user click agreement"); 96 console.log("user click agreement");
94 }, 97 },
95 - radioChange(e) {  
96 - this.agree = e 98 + radioChange() {
  99 + this.agree[0] = !this.agree[0]
97 }, 100 },
98 handleWeixinLogin(wxInfo) { 101 handleWeixinLogin(wxInfo) {
99 uni.login({ 102 uni.login({
@@ -190,7 +193,7 @@ export default { @@ -190,7 +193,7 @@ export default {
190 193
191 .hint { 194 .hint {
192 padding: 20rpx 40rpx; 195 padding: 20rpx 40rpx;
193 - font-size: 20rpx; 196 + font-size: 25rpx;
194 color: $u-tips-color; 197 color: $u-tips-color;
195 display: flex; 198 display: flex;
196 justify-content: flex-start; 199 justify-content: flex-start;
garbage-removal/src/pages/order/detail/index.vue
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 @click.stop="handlerJumpOtherApp(dataGram.garLatitude, dataGram.garLongitude, dataGram.garCoordinate)"> 33 @click.stop="handlerJumpOtherApp(dataGram.garLatitude, dataGram.garLongitude, dataGram.garCoordinate)">
34 <text class="order-detail-container-header-title">派单地点:</text> 34 <text class="order-detail-container-header-title">派单地点:</text>
35 <view class="order-detail-container-header-content" style="text-decoration: underline"> 35 <view class="order-detail-container-header-content" style="text-decoration: underline">
36 - {{ dataGram.garOrderAddress + dataGram.garOrderAddressDetails }} 36 + <text selectable='true'>{{ dataGram.garOrderAddress + dataGram.garOrderAddressDetails }}</text>
37 </view> 37 </view>
38 </view> 38 </view>
39 <view class="order-detail-container-header-item"> 39 <view class="order-detail-container-header-item">
@@ -58,7 +58,7 @@ @@ -58,7 +58,7 @@
58 <view class="order-detail-container-header-item"> 58 <view class="order-detail-container-header-item">
59 <text class="order-detail-container-header-title">派单号:</text> 59 <text class="order-detail-container-header-title">派单号:</text>
60 <view class="order-detail-container-header-content"> 60 <view class="order-detail-container-header-content">
61 - {{ orderId }} 61 + <text selectable="true">{{ orderId }}</text>
62 </view> 62 </view>
63 <!-- 生成二维码 --> 63 <!-- 生成二维码 -->
64 <view class="order-detail-container-header-qrCode" style="display: flex; align-items: center;"> 64 <view class="order-detail-container-header-qrCode" style="display: flex; align-items: center;">
@@ -104,7 +104,7 @@ @@ -104,7 +104,7 @@
104 <view class="order-detail-container-header-item"> 104 <view class="order-detail-container-header-item">
105 <text class="order-detail-container-header-title">联系电话:</text> 105 <text class="order-detail-container-header-title">联系电话:</text>
106 <view class="order-detail-container-header-content"> 106 <view class="order-detail-container-header-content">
107 - {{ dataGram.garOrderContactTel }} 107 + <text selectable="true">{{ dataGram.garOrderContactTel }}</text>
108 <view class="icon-box" style="display: flex; align-items: center; justify-content: center;"> 108 <view class="icon-box" style="display: flex; align-items: center; justify-content: center;">
109 <u-icon v-if="dataGram.handleFlag" name="phone" size="28" 109 <u-icon v-if="dataGram.handleFlag" name="phone" size="28"
110 @click="handleContactClick(dataGram.garOrderContactTel)"></u-icon> 110 @click="handleContactClick(dataGram.garOrderContactTel)"></u-icon>
@@ -170,50 +170,50 @@ @@ -170,50 +170,50 @@
170 <view class="order-detail-bottom-box"> 170 <view class="order-detail-bottom-box">
171 <view class=" order-detail-bottom-left"> 171 <view class=" order-detail-bottom-left">
172 <u-button v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'" 172 <u-button v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
173 - @click="handleSubmitSuccess(orderId)" shape="circle" color="#a9e08f" text="完成派单"></u-button> 173 + @click="handleSubmitSuccess(orderId)" shape="square" color="#a9e08f" text="完成派单"></u-button>
174 <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '企业负责人' && dataGram.garCancelFlag === 0" 174 <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '企业负责人' && dataGram.garCancelFlag === 0"
175 - @click="handleOderCancelClick()" shape="circle" color="#a9e08f" text="取消派单"></u-button> 175 + @click="handleOderCancelClick()" shape="square" color="#a9e08f" text="取消派单"></u-button>
176 <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '运输驾驶员' && dataGram.garCancelFlag === 0" 176 <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '运输驾驶员' && dataGram.garCancelFlag === 0"
177 - @click="handleOderCancelClick()" shape="circle" color="#a9e08f" text="取消派单"></u-button> 177 + @click="handleOderCancelClick()" shape="square" color="#a9e08f" text="取消派单"></u-button>
178 <u-button v-if="dataGram.garOrderHandlerStatus === 1 && userType == '企业负责人'" 178 <u-button v-if="dataGram.garOrderHandlerStatus === 1 && userType == '企业负责人'"
179 - @click="handleOrderDispatchClick(orderId)" shape="circle" color="#a9e08f" 179 + @click="handleOrderDispatchClick(orderId)" shape="square" color="#a9e08f"
180 :text="dataGram.garOrderMatchFlag === 0 ? '派单下发' : '继续下发'"></u-button> 180 :text="dataGram.garOrderMatchFlag === 0 ? '派单下发' : '继续下发'"></u-button>
181 </view> 181 </view>
182 <view class="order-detail-bottom-right"> 182 <view class="order-detail-bottom-right">
183 <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '居民用户' && dataGram.garCancelFlag === 0" 183 <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '居民用户' && dataGram.garCancelFlag === 0"
184 - @click="handleOderCancelClick()" shape="circle" color="#a9e08f" text="取消派单"></u-button> 184 + @click="handleOderCancelClick()" shape="square" color="#a9e08f" text="取消派单"></u-button>
185 <u-button @click="driverHandleOrder(orderId)" 185 <u-button @click="driverHandleOrder(orderId)"
186 v-if="dataGram.garOrderHandlerStatus === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'" 186 v-if="dataGram.garOrderHandlerStatus === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
187 - shape="circle" color="#a9e08f" text="处理派单"></u-button> 187 + shape="square" color="#a9e08f" text="处理派单"></u-button>
188 <u-button @click="handleOrder(orderId)" 188 <u-button @click="handleOrder(orderId)"
189 v-if="dataGram.garOrderHandlerStatus === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '企业负责人'" 189 v-if="dataGram.garOrderHandlerStatus === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '企业负责人'"
190 - shape="circle" color="#a9e08f" text="处理派单"></u-button> 190 + shape="square" color="#a9e08f" text="处理派单"></u-button>
191 <u-button @click="handleUploadImage(orderId, 'putOnImages')" 191 <u-button @click="handleUploadImage(orderId, 'putOnImages')"
192 v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'" 192 v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
193 - shape="circle" color="#a9e08f" text="上传图片"></u-button> 193 + shape="square" color="#a9e08f" text="上传图片"></u-button>
194 <!-- <u-button @click="handleUploadImage(orderId, 'putOnImages')" 194 <!-- <u-button @click="handleUploadImage(orderId, 'putOnImages')"
195 v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putOnImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'" 195 v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putOnImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
196 - shape="circle" color="#a9e08f" text="装车照片"></u-button> 196 + shape="square" color="#a9e08f" text="装车照片"></u-button>
197 <u-button @click="handleUploadImage(orderId, 'putDownImages')" 197 <u-button @click="handleUploadImage(orderId, 'putDownImages')"
198 v-else-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putDownImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'" 198 v-else-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putDownImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
199 - shape="circle" color="#a9e08f" text="卸车照片"></u-button> --> 199 + shape="square" color="#a9e08f" text="卸车照片"></u-button> -->
200 <!-- <u-button @click="handleUploadImage(orderId, 'putDownImages')" 200 <!-- <u-button @click="handleUploadImage(orderId, 'putDownImages')"
201 v-else-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putDownImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '企业负责人'" 201 v-else-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putDownImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '企业负责人'"
202 - shape="circle" color="#a9e08f" text="上传照片"></u-button> --> 202 + shape="square" color="#a9e08f" text="上传照片"></u-button> -->
203 <u-button @click="handleEvaluate(orderId, userType)" 203 <u-button @click="handleEvaluate(orderId, userType)"
204 - v-if="dataGram.garEvaluateFlag === 0 && userType === '居民用户'" shape="circle" color="#a9e08f" 204 + v-if="dataGram.garEvaluateFlag === 0 && userType === '居民用户'" shape="square" color="#a9e08f"
205 text="去评价"></u-button> 205 text="去评价"></u-button>
206 <u-button @click="handleEvaluate(orderId, userType)" 206 <u-button @click="handleEvaluate(orderId, userType)"
207 - v-if="dataGram.garHandlerEvaluateFlag === 0 && userType === '企业负责人'" shape="circle" color="#a9e08f" 207 + v-if="dataGram.garHandlerEvaluateFlag === 0 && userType === '企业负责人'" shape="square" color="#a9e08f"
208 text="去评价"></u-button> 208 text="去评价"></u-button>
209 <u-button @click="handleEvaluateDetail(orderId, userType)" 209 <u-button @click="handleEvaluateDetail(orderId, userType)"
210 - v-if="dataGram.garHandlerEvaluateFlag === 1 && userType === '企业负责人'" shape="circle" color="#a9e08f" 210 + v-if="dataGram.garHandlerEvaluateFlag === 1 && userType === '企业负责人'" shape="square" color="#a9e08f"
211 text="查看评价"></u-button> 211 text="查看评价"></u-button>
212 <u-button @click="handleEvaluateDetail(orderId, userType)" 212 <u-button @click="handleEvaluateDetail(orderId, userType)"
213 - v-if="dataGram.garEvaluateFlag === 1 && userType === '居民用户'" shape="circle" color="#a9e08f" 213 + v-if="dataGram.garEvaluateFlag === 1 && userType === '居民用户'" shape="square" color="#a9e08f"
214 text="查看评价"></u-button> 214 text="查看评价"></u-button>
215 <u-button v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType != '运输驾驶员'" 215 <u-button v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType != '运输驾驶员'"
216 - @click="handleSubmitSuccess(orderId)" shape="circle" color="#a9e08f" text="完成派单"></u-button> 216 + @click="handleSubmitSuccess(orderId)" shape="square" color="#a9e08f" text="完成派单"></u-button>
217 </view> 217 </view>
218 </view> 218 </view>
219 </view> 219 </view>
@@ -253,30 +253,39 @@ const cancelShow = ref(false) @@ -253,30 +253,39 @@ const cancelShow = ref(false)
253 const currentCancelName = ref("") 253 const currentCancelName = ref("")
254 const qrCodeRef = ref() 254 const qrCodeRef = ref()
255 const qrCodeText = ref() 255 const qrCodeText = ref()
256 -const list = ref([  
257 - {  
258 - name: '长时间无人接单',  
259 - },  
260 - {  
261 - name: '派单信息填写有误',  
262 - },  
263 - {  
264 - name: '线下协商有问题',  
265 - },  
266 - {  
267 - name: '不需要清运了',  
268 - },  
269 - {  
270 - name: '其他',  
271 - },  
272 - {  
273 - name: '提交', 256 +const list = computed(() => {
  257 + let reason = [
  258 + {
  259 + name: '派单信息填写有误',
  260 + },
  261 + {
  262 + name: '线下协商有问题',
  263 + },
  264 + {
  265 + name: '不需要清运了',
  266 + },
  267 + {
  268 + name: '其他',
  269 + },
  270 + {
  271 + name: '提交',
  272 + }
  273 + ]
  274 + if (userType.value === '居民用户') {
  275 + reason.unshift({
  276 + name: '长时间无人接单',
  277 + })
  278 + } else {
  279 + reason.unshift({
  280 + name: '无修改权限'
  281 + })
274 } 282 }
275 -]) 283 + return reason
  284 +})
276 285
277 // 创建二维码 286 // 创建二维码
278 const createQrCodeLocal = (orderId) => { 287 const createQrCodeLocal = (orderId) => {
279 - // 获取本地地址拼接单id 288 + // 获取本地地址拼接单id
280 showUQRcode.value = true; 289 showUQRcode.value = true;
281 const hostname = window.location.hostname; 290 const hostname = window.location.hostname;
282 const port = window.location.port; 291 const port = window.location.port;
@@ -362,7 +371,6 @@ const handleContactClick = (val) =&gt; { @@ -362,7 +371,6 @@ const handleContactClick = (val) =&gt; {
362 } 371 }
363 372
364 const handlerJumpOtherApp = (latitude, longitude, garCoordinate) => { 373 const handlerJumpOtherApp = (latitude, longitude, garCoordinate) => {
365 - console.log(latitude, longitude);  
366 // 给出提示确定要跳转吗 374 // 给出提示确定要跳转吗
367 uni.showModal({ 375 uni.showModal({
368 title: '提示', 376 title: '提示',
garbage-removal/src/pages/order/upload/index.vue
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <view class="upload-image-box-submit-box"> 20 <view class="upload-image-box-submit-box">
21 <view class="upload-image-box-submit-box-button" @click="handleSubmit(orderId, putType)"> 21 <view class="upload-image-box-submit-box-button" @click="handleSubmit(orderId, putType)">
22 <view class="upload-image-box-submit-box-button-container"> 22 <view class="upload-image-box-submit-box-button-container">
23 - <up-button color="#19be6b" type="primary" shape="circle" text="确定"></up-button> 23 + <up-button color="#19be6b" type="primary" shape="square" text="确定"></up-button>
24 </view> 24 </view>
25 </view> 25 </view>
26 </view> 26 </view>
garbage-removal/src/pages/wode/choose/index.vue
1 <template> 1 <template>
2 <view class="wrap"> 2 <view class="wrap">
3 - <u-radio-group v-model="userType" placement="row" @change="groupChange">  
4 - <view class="choose-type" v-for="(item, index) in typeList">  
5 - <u-radio size="28" labelSize="28" :key="index" :label="item.name" :name="item.name" @change="radioChange">  
6 - </u-radio>  
7 - </view>  
8 - </u-radio-group>  
9 - <!-- 角色信息匹配 -->  
10 - <view class="rule-label-info-box">  
11 - <view class="manager-info" v-if="userType === '居民用户'">  
12 - <view class="manager-info-parent-company-name">  
13 - 派单前请输先完善地址信息~  
14 - </view>  
15 - </view>  
16 - <view class="manager-info" v-if="userType === '运输驾驶员'">  
17 - <view v-if="tempUserType === '运输驾驶员'" class="manager-info-parent-company-name">  
18 - {{ unitInfo.transportCompanyName }}运输公司-运输驾驶员  
19 - </view>  
20 - <view v-else class="manager-info-parent-company-name">  
21 - 未匹配到该手机号绑定的运输公司! 3 + <view class="choose-type-box">
  4 + <view class="choose-type-item" :class="item.isNow ? 'itemActive' : ''" v-for=" (item, index) in typeList"
  5 + :key="index" @click="handlerClick(item)">
  6 + <view class="choose-type-item-top" :class="item.classStyle">
  7 + <view class="choose-type-item-image" width="100%" height="100%">
  8 + <image :src="item.image" shape="circle" mode="aspectFill">
  9 + </image>
  10 + </view>
  11 + <view class="choose-type-item-text">
  12 + <view class="choose-type-item-text-right">
  13 + <view v-if="item.company" class="choose-tyep-item-text-right-compay">
  14 + {{ item.company }}
  15 + </view>
  16 + <view class="choose-tyep-item-text-right-info">
  17 + {{ item.info }}
  18 + </view>
  19 + <view class="choose-type-item-text-right-label">
  20 + {{ item.label }}
  21 + </view>
  22 + </view>
  23 + </view>
22 </view> 24 </view>
23 - </view>  
24 - <view class="manager-info" v-if="userType === '企业负责人'">  
25 - <view v-if="tempUserType === '企业负责人'" class="manager-info-parent-company-name">  
26 - {{ unitInfo.transportCompanyName }}服务账号  
27 - </view>  
28 - <view v-else class="manager-info-parent-company-name">  
29 - 未匹配到该手机号绑定运输公司公司服务账号! 25 + <view class="choose-type-item-bottom">
  26 + <view class="choose-type-item-bottom-button"
  27 + :class="item.isNow ? 'choose-type-item-bottom-button-active' : ''">
  28 + {{ item.isNow ? '当前身份' : '切换此身份' }}
  29 + <up-icon name="checkmark-circle-fill" :color="item.isNow ? '#35bef7' : ''" size="28"></up-icon>
  30 + </view>
30 </view> 31 </view>
31 </view> 32 </view>
32 </view> 33 </view>
33 - <view class="choose-button">  
34 - <u-button shape="circle" color="#a9e08f" @click="submit(userType)">确定</u-button> 34 + <view class="choose-user-bottom-button-box">
  35 + <view class="choose-user-bottom-button-box-button" @click="submit(userType)">
  36 + 下一步
  37 + </view>
35 </view> 38 </view>
36 </view> 39 </view>
  40 +
  41 +
37 </template> 42 </template>
38 43
39 <script setup> 44 <script setup>
@@ -42,25 +47,72 @@ import { useMainStore } from &#39;@/stores/index.js&#39;; @@ -42,25 +47,72 @@ import { useMainStore } from &#39;@/stores/index.js&#39;;
42 import { setRequestToken } from '@/utils/request/request.js'; 47 import { setRequestToken } from '@/utils/request/request.js';
43 import { onLoad } from "@dcloudio/uni-app"; 48 import { onLoad } from "@dcloudio/uni-app";
44 import { ref } from 'vue'; 49 import { ref } from 'vue';
  50 +const userType = ref('')
  51 +const imageBase = "data:image/jpeg;base64,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";
45 const store = useMainStore(); 52 const store = useMainStore();
46 -const userType = ref("居民用户")  
47 -const tempUserType = ref()  
48 -const typeList = ref([{ name: "居民用户" }, { name: "运输驾驶员" }, { name: "企业负责人" }])  
49 -const unitInfo = ref({})  
50 -const radioChange = (e) => {  
51 -}  
52 -const groupChange = (e) => { 53 +const typeList = ref([{
  54 + label: "居民用户",
  55 + info: '下单清运',
  56 + image: imageBase,
  57 + order: 999,
  58 + classStyle: 'choose-type-item-top-back-sky',
  59 + isNow: false,
  60 + isExit: true,
  61 +}, {
  62 + label: "处理场所",
  63 + info: '负责现场指导',
  64 + company: '长沙xxxx',
  65 + image: imageBase,
  66 + isExit: false,
  67 + classStyle: 'choose-type-item-top-back-pink',
  68 + order: 3,
  69 + isNow: false,
  70 +}, {
  71 + label: "运输驾驶员",
  72 + info: '负责垃圾清运',
  73 + company: '长沙xxxx',
  74 + image: imageBase,
  75 + isExit: false,
  76 + classStyle: 'choose-type-item-top-back-blue',
  77 + order: 2,
  78 + isNow: false,
  79 +}, {
  80 + label: "企业负责人",
  81 + info: '负责订单处理',
  82 + company: '长沙xxxx',
  83 + image: imageBase,
  84 + isExit: false,
  85 + classStyle: 'choose-type-item-top-back-sun',
  86 + order: 1,
  87 + isNow: false,
  88 +}])
  89 +const unitInfo = ref([])
  90 +const handlerClick = (val) => {
  91 + if (val.isExit) {
  92 + val.isNow = true;
  93 + userType.value = val.label;
  94 + typeList.value.forEach((item) => {
  95 + if (val.label !== item.label) {
  96 + item.isNow = false
  97 + }
  98 + })
  99 + } else {
  100 + // 提示 当前账号未绑定,无法选中
  101 + uni.showToast({
  102 + title: '账号未绑定,无法选中',
  103 + icon: 'none',
  104 + duration: 1500
  105 + })
  106 + }
53 } 107 }
54 -  
55 const submit = (userType) => { 108 const submit = (userType) => {
56 setRequestToken(store.tempToken) 109 setRequestToken(store.tempToken)
57 updateUserInfo({ garUserType: userType }).then(res => { 110 updateUserInfo({ garUserType: userType }).then(res => {
58 - store.token = store.tempToken  
59 - store.tempToken = "";  
60 if (res.data.success) { 111 if (res.data.success) {
  112 + store.token = store.tempToken
  113 + store.tempToken = "";
61 store.userType = userType; 114 store.userType = userType;
62 - unitInfo.value.userType = userType  
63 - store.userInfo = unitInfo.value 115 + store.userInfo = unitInfo.value[userType]
64 uni.$u.route({ 116 uni.$u.route({
65 type: "switchTab", 117 type: "switchTab",
66 url: `pages/home/index`, 118 url: `pages/home/index`,
@@ -70,10 +122,29 @@ const submit = (userType) =&gt; { @@ -70,10 +122,29 @@ const submit = (userType) =&gt; {
70 122
71 } 123 }
72 onLoad((options) => { 124 onLoad((options) => {
73 - unitInfo.value = options  
74 - userType.value = options.userType  
75 - tempUserType.value = options.userType  
76 - // submit(options.userType) 125 + // let loginInfo = JSON.parse(options)
  126 + let loginInfo = JSON.parse(decodeURIComponent(options.ruleVos))
  127 + for (let index = 0; index < loginInfo.length; index++) {
  128 + const element = loginInfo[index];
  129 + unitInfo.value[element.userType] = element
  130 + }
  131 + let order = 999;
  132 + let index = 0;
  133 + // typeList优先级最高的设置isNow 为 true
  134 + if (loginInfo.length > 1) {
  135 + typeList.value.forEach((item, i) => {
  136 + if (unitInfo.value[item.label]) {
  137 + item.isExit = true;
  138 + if (item.order < order) {
  139 + order = item.order;
  140 + index = i;
  141 + }
  142 + }
  143 + })
  144 + typeList.value[index].isNow = true
  145 + userType.value = typeList.value[index].label
  146 + }
  147 + console.log(typeList.value, "typeList.value");
77 }) 148 })
78 </script> 149 </script>
79 150
@@ -82,50 +153,177 @@ onLoad((options) =&gt; { @@ -82,50 +153,177 @@ onLoad((options) =&gt; {
82 height: 100%; 153 height: 100%;
83 width: 100%; 154 width: 100%;
84 box-sizing: border-box; 155 box-sizing: border-box;
85 - padding: 20rpx; 156 + // padding: 20rpx;
86 background-color: $u-info-light; 157 background-color: $u-info-light;
87 158
88 - .choose-type {  
89 - // width: 100%;  
90 - box-sizing: border-box;  
91 - padding: 20rpx;  
92 - background-color: #ffffff;  
93 - border-radius: 20rpx;  
94 - margin-right: 20rpx; 159 +
  160 + .choose-type-box {
  161 + width: 750rpx;
95 display: flex; 162 display: flex;
96 - align-items: center; 163 + flex-direction: column;
97 justify-content: center; 164 justify-content: center;
  165 + align-items: center;
  166 + box-sizing: border-box;
  167 + padding: 20rpx 70rpx;
  168 +
  169 + .choose-type-item {
  170 + width: 100%;
  171 + height: 270rpx;
  172 + box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.1);
  173 + margin-bottom: 40rpx;
  174 + border-radius: 15rpx 15rpx 0rpx 0rpx;
  175 +
  176 +
  177 + .choose-type-item-top-back-blue {
  178 + background: linear-gradient(135deg, #a1c4fd, #c2e9fb) !important;
  179 + }
  180 +
  181 + .choose-type-item-top-back-pink {
  182 + background: linear-gradient(135deg, #c7e9fb, #a6defa, #80d4f9, #5bc9f8, #35bef7) !important;
  183 + }
  184 +
  185 + .choose-type-item-top-back-sun {
  186 + background: linear-gradient(135deg, #f6d365, #fda085) !important;
  187 + }
  188 +
  189 + .choose-type-item-top-back-sky {
  190 + background: linear-gradient(135deg, #c2ef8c, #83e455) !important;
  191 + }
  192 +
  193 + .choose-type-item-top {
  194 + height: 235rpx;
  195 + display: flex;
  196 + align-items: center;
  197 + box-sizing: border-box;
  198 + padding: 30rpx;
  199 + border-radius: 15rpx 15rpx 5rpx 5rpx;
  200 + box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.1);
  201 +
  202 + .choose-type-item-image {
  203 + width: 140rpx;
  204 + height: 170rpx;
  205 + border-radius: 50%;
  206 + display: flex;
  207 + align-items: center;
  208 + justify-content: flex-start;
  209 + margin-right: 20rpx;
  210 +
  211 + image {
  212 + width: 100%;
  213 + height: 100%;
  214 + }
  215 + }
  216 +
  217 + .choose-type-item-text {
  218 + width: 100%;
  219 + height: 100%;
  220 +
  221 + .choose-type-item-text-right {
  222 + width: 100%;
  223 + height: 100%;
  224 + display: flex;
  225 + flex-direction: column;
  226 + align-items: flex-start;
  227 + justify-content: space-around;
  228 + color: white;
  229 +
  230 + .choose-tyep-item-text-right-info {
  231 + font-size: 28rpx;
  232 + }
  233 +
  234 + .choose-tyep-item-text-right-compay {
  235 + font-weight: bolder;
  236 + line-height: 35rpx;
  237 + font-size: 32rpx;
  238 + }
  239 +
  240 + .choose-type-item-text-right-label {
  241 + font-size: 23rpx;
  242 + padding: 8rpx 15rpx;
  243 + border-radius: 5rpx;
  244 + color: $u-info-dark;
  245 + font-weight: 600;
  246 + margin-bottom: 10rpx;
  247 + background: #ffffffad;
  248 + border: 3rpx solid white;
  249 + }
  250 + }
  251 + }
  252 +
  253 + }
  254 +
  255 + .choose-type-item-bottom {
  256 + width: 100%;
  257 + height: 35rpx;
  258 + box-sizing: border-box;
  259 + display: flex;
  260 + align-items: center;
  261 + justify-content: flex-end;
  262 + background: #ffffff;
  263 +
  264 + .choose-type-item-bottom-button {
  265 + font-size: 25rpx;
  266 + color: #999999;
  267 + display: flex;
  268 + }
  269 +
  270 + .choose-type-item-bottom-button-active {
  271 + color: #35bef7 !important;
  272 + }
  273 + }
  274 + }
98 275
99 - &:last-child {  
100 - margin-right: 20rpx; 276 + .itemActive {
  277 + animation: overScroll 0.5s forwards ease-in-out;
101 } 278 }
102 279
  280 + @keyframes overScroll {
  281 + 0% {
  282 + transform: translateY(8rpx);
  283 + }
103 284
104 - } 285 + 20% {
  286 + transform: translateY(-4rpx);
  287 + }
105 288
106 - .rule-label-info-box {  
107 - box-sizing: border-box;  
108 - margin-top: 20rpx; 289 + 40% {
  290 + transform: translateY(8rpx);
  291 + }
109 292
110 - .manager-info {  
111 - font-size: 25rpx;  
112 - color: $u-main-color;  
113 - box-sizing: border-box; 293 + 60% {
  294 + transform: translateY(-4rpx);
  295 + }
114 296
115 - .manager-info-parent-company-name {  
116 - color: $u-info; 297 + 80% {
  298 + transform: translateY(8rpx);
  299 + }
  300 +
  301 + 100% {
  302 + transform: translateY(0);
117 } 303 }
118 } 304 }
119 } 305 }
120 306
121 -  
122 - .choose-button {  
123 - position: relative; 307 + .choose-user-bottom-button-box {
124 width: 100%; 308 width: 100%;
125 - height: 100%; 309 + height: 80rpx;
126 display: flex; 310 display: flex;
127 - justify-content: center;  
128 align-items: center; 311 align-items: center;
  312 + justify-content: center;
  313 + box-sizing: border-box;
  314 +
  315 + .choose-user-bottom-button-box-button {
  316 + width: 80%;
  317 + height: 100%;
  318 + background: #23d283;
  319 + border-radius: 30rpx;
  320 + color: white;
  321 + font-size: 30rpx;
  322 + display: flex;
  323 + align-items: center;
  324 + justify-content: center;
  325 + @include handleClick;
  326 + }
129 } 327 }
130 } 328 }
131 </style> 329 </style>
garbage-removal/src/static/image/garbage.png 0 → 100644

249 KB

garbage-removal/src/uview-plus/components/u-calendar/u-calendar.vue
1 <template> 1 <template>
2 - <u-popup  
3 - :show="show"  
4 - mode="bottom"  
5 - closeable  
6 - @close="close"  
7 - :round="round"  
8 - :closeOnClickOverlay="closeOnClickOverlay"  
9 - > 2 + <u-popup :show="show" mode="bottom" closeable @close="close" :round="round"
  3 + :closeOnClickOverlay="closeOnClickOverlay">
10 <view class="u-calendar"> 4 <view class="u-calendar">
11 - <uHeader  
12 - :title="title"  
13 - :subtitle="subtitle"  
14 - :showSubtitle="showSubtitle"  
15 - :showTitle="showTitle"  
16 - ></uHeader>  
17 - <scroll-view  
18 - :style="{  
19 - height: $u.addUnit(listHeight)  
20 - }"  
21 - scroll-y  
22 - @scroll="onScroll"  
23 - :scroll-top="scrollTop"  
24 - :scrollIntoView="scrollIntoView"  
25 - >  
26 - <uMonth  
27 - :color="color"  
28 - :rowHeight="rowHeight"  
29 - :showMark="showMark"  
30 - :months="months"  
31 - :mode="mode"  
32 - :maxCount="maxCount"  
33 - :startText="startText"  
34 - :endText="endText"  
35 - :defaultDate="defaultDate"  
36 - :minDate="innerMinDate"  
37 - :maxDate="innerMaxDate"  
38 - :maxMonth="monthNum"  
39 - :readonly="readonly"  
40 - :maxRange="maxRange"  
41 - :rangePrompt="rangePrompt"  
42 - :showRangePrompt="showRangePrompt"  
43 - :allowSameDay="allowSameDay"  
44 - ref="month"  
45 - @monthSelected="monthSelected"  
46 - @updateMonthTop="updateMonthTop"  
47 - ></uMonth> 5 + <uHeader :title="title" :subtitle="subtitle" :showSubtitle="showSubtitle" :showTitle="showTitle"></uHeader>
  6 + <scroll-view :style="{
  7 + height: $u.addUnit(listHeight)
  8 + }" scroll-y @scroll="onScroll" :scroll-top="scrollTop" :scrollIntoView="scrollIntoView">
  9 + <uMonth :color="color" :rowHeight="rowHeight" :showMark="showMark" :months="months" :mode="mode"
  10 + :maxCount="maxCount" :startText="startText" :endText="endText" :defaultDate="defaultDate"
  11 + :minDate="innerMinDate" :maxDate="innerMaxDate" :maxMonth="monthNum" :readonly="readonly" :maxRange="maxRange"
  12 + :rangePrompt="rangePrompt" :showRangePrompt="showRangePrompt" :allowSameDay="allowSameDay" ref="month"
  13 + @monthSelected="monthSelected" @updateMonthTop="updateMonthTop"></uMonth>
48 </scroll-view> 14 </scroll-view>
49 <slot name="footer" v-if="showConfirm"> 15 <slot name="footer" v-if="showConfirm">
50 <view class="u-calendar__confirm"> 16 <view class="u-calendar__confirm">
51 - <u-button  
52 - shape="circle"  
53 - :text="  
54 - buttonDisabled ? confirmDisabledText : confirmText  
55 - "  
56 - :color="color"  
57 - @click="confirm"  
58 - :disabled="buttonDisabled"  
59 - ></u-button> 17 + <u-button shape="square" :text="buttonDisabled ? confirmDisabledText : confirmText
  18 + " :color="color" @click="confirm" :disabled="buttonDisabled"></u-button>
60 </view> 19 </view>
61 </slot> 20 </slot>
62 </view> 21 </view>
@@ -67,12 +26,11 @@ @@ -67,12 +26,11 @@
67 import uHeader from './header.vue' 26 import uHeader from './header.vue'
68 import uMonth from './month.vue' 27 import uMonth from './month.vue'
69 import props from './props.js' 28 import props from './props.js'
70 -import util from './util.js'  
71 // import dayjs from '../../libs/util/dayjs.min.js' 29 // import dayjs from '../../libs/util/dayjs.min.js'
72 import dayjs from 'dayjs/esm/index' 30 import dayjs from 'dayjs/esm/index'
73 -import Calendar from '../../libs/util/calendar.js'  
74 -import mpMixin from '../../libs/mixin/mpMixin.js'  
75 import mixin from '../../libs/mixin/mixin.js' 31 import mixin from '../../libs/mixin/mixin.js'
  32 +import mpMixin from '../../libs/mixin/mpMixin.js'
  33 +import Calendar from '../../libs/util/calendar.js'
76 /** 34 /**
77 * Calendar 日历 35 * Calendar 日历
78 * @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中. 36 * @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中.
@@ -129,7 +87,7 @@ export default { @@ -129,7 +87,7 @@ export default {
129 // month组件中选择的日期数组 87 // month组件中选择的日期数组
130 selected: [], 88 selected: [],
131 scrollIntoView: '', 89 scrollIntoView: '',
132 - scrollTop:0, 90 + scrollTop: 0,
133 // 过滤处理方法 91 // 过滤处理方法
134 innerFormatter: (value) => value 92 innerFormatter: (value) => value
135 } 93 }
@@ -168,9 +126,8 @@ export default { @@ -168,9 +126,8 @@ export default {
168 subtitle() { 126 subtitle() {
169 // 初始化时,this.months为空数组,所以需要特别判断处理 127 // 初始化时,this.months为空数组,所以需要特别判断处理
170 if (this.months.length) { 128 if (this.months.length) {
171 - return `${this.months[this.monthIndex].year}年${  
172 - this.months[this.monthIndex].month  
173 - }月` 129 + return `${this.months[this.monthIndex].year}年${this.months[this.monthIndex].month
  130 + }月`
174 } else { 131 } else {
175 return '' 132 return ''
176 } 133 }
@@ -320,9 +277,9 @@ export default { @@ -320,9 +277,9 @@ export default {
320 scrollIntoDefaultMonth(selected) { 277 scrollIntoDefaultMonth(selected) {
321 // 查询默认日期在可选列表的下标 278 // 查询默认日期在可选列表的下标
322 const _index = this.months.findIndex(({ 279 const _index = this.months.findIndex(({
323 - year,  
324 - month  
325 - }) => { 280 + year,
  281 + month
  282 + }) => {
326 month = uni.$u.padZero(month) 283 month = uni.$u.padZero(month)
327 return `${year}-${month}` === selected 284 return `${year}-${month}` === selected
328 }) 285 })
garbage-removal/src/uview-plus/components/u-cell-group/props.js
@@ -10,6 +10,15 @@ export default { @@ -10,6 +10,15 @@ export default {
10 border: { 10 border: {
11 type: Boolean, 11 type: Boolean,
12 default: defprops.cellGroup.border 12 default: defprops.cellGroup.border
  13 + },
  14 + // 对齐方式
  15 + placement: {
  16 + type: String,
  17 + default: 'center'
  18 + },
  19 + activeStyle: {
  20 + type: Object,
  21 + default: {}
13 } 22 }
14 } 23 }
15 } 24 }
garbage-removal/src/uview-plus/components/u-cell-group/u-cell-group.vue
1 <template> 1 <template>
2 - <view :style="[$u.addStyle(customStyle)]" :class="[customClass]" class="u-cell-group">  
3 - <view v-if="title" class="u-cell-group__title">  
4 - <slot name="title"> 2 + <view :style="[$u.addStyle(activeStyle)]" :class="[customClass]" class="u-cell-group">
  3 + <view v-if="title" class="u-cell-group__title">
  4 + <slot name="title">
5 <text class="u-cell-group__title__text">{{ title }}</text> 5 <text class="u-cell-group__title__text">{{ title }}</text>
6 </slot> 6 </slot>
7 - </view>  
8 - <view class="u-cell-group__wrapper"> 7 + </view>
  8 + <view class="u-cell-group__wrapper">
9 <u-line v-if="border"></u-line> 9 <u-line v-if="border"></u-line>
10 - <slot />  
11 - </view>  
12 - </view> 10 + <slot />
  11 + </view>
  12 + </view>
13 </template> 13 </template>
14 14
15 <script> 15 <script>
16 - import props from './props.js';  
17 - import mpMixin from '../../libs/mixin/mpMixin.js';  
18 - import mixin from '../../libs/mixin/mixin.js';  
19 - /**  
20 - * cellGroup 单元格  
21 - * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。  
22 - * @tutorial https://uviewui.com/components/cell.html  
23 - *  
24 - * @property {String} title 分组标题  
25 - * @property {Boolean} border 是否显示外边框 (默认 true )  
26 - * @property {Object} customStyle 定义需要用到的外部样式  
27 - *  
28 - * @event {Function} click 点击cell列表时触发  
29 - * @example <u-cell-group title="设置喜好">  
30 - */  
31 - export default {  
32 - name: 'u-cell-group',  
33 - mixins: [mpMixin, mixin, props],  
34 - } 16 +import mixin from '../../libs/mixin/mixin.js';
  17 +import mpMixin from '../../libs/mixin/mpMixin.js';
  18 +import props from './props.js';
  19 +/**
  20 + * cellGroup 单元格
  21 + * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。
  22 + * @tutorial https://uviewui.com/components/cell.html
  23 + *
  24 + * @property {String} title 分组标题
  25 + * @property {Boolean} border 是否显示外边框 (默认 true )
  26 + * @property {Object} customStyle 定义需要用到的外部样式
  27 + *
  28 + * @event {Function} click 点击cell列表时触发
  29 + * @example <u-cell-group title="设置喜好">
  30 + */
  31 +export default {
  32 + name: 'u-cell-group',
  33 + mixins: [mpMixin, mixin, props],
  34 +}
35 </script> 35 </script>
36 36
37 <style lang="scss" scoped> 37 <style lang="scss" scoped>
38 - @import "../../libs/css/components.scss";  
39 -  
40 - $u-cell-group-title-padding: 16px 16px 8px !default;  
41 - $u-cell-group-title-font-size: 15px !default;  
42 - $u-cell-group-title-line-height: 16px !default;  
43 - $u-cell-group-title-color: $u-main-color !default; 38 +@import "../../libs/css/components.scss";
  39 +
  40 +$u-cell-group-title-padding: 16px 16px 8px !default;
  41 +$u-cell-group-title-font-size: 15px !default;
  42 +$u-cell-group-title-line-height: 16px !default;
  43 +$u-cell-group-title-color: $u-main-color !default;
44 44
45 - .u-cell-group {  
46 - flex: 1;  
47 -  
48 - &__title {  
49 - padding: $u-cell-group-title-padding; 45 +.u-cell-group {
  46 + flex: 1;
50 47
51 - &__text {  
52 - font-size: $u-cell-group-title-font-size;  
53 - line-height: $u-cell-group-title-line-height;  
54 - color: $u-cell-group-title-color;  
55 - }  
56 - }  
57 -  
58 - &__wrapper {  
59 - position: relative; 48 + &__title {
  49 + padding: $u-cell-group-title-padding;
  50 +
  51 + &__text {
  52 + font-size: $u-cell-group-title-font-size;
  53 + line-height: $u-cell-group-title-line-height;
  54 + color: $u-cell-group-title-color;
60 } 55 }
61 - }  
62 -</style> 56 + }
63 57
  58 + &__wrapper {
  59 + position: relative;
  60 + }
  61 +}
  62 +</style>
garbage-removal/src/uview-plus/components/u-checkbox/u-checkbox.vue
@@ -7,10 +7,10 @@ @@ -7,10 +7,10 @@
7 </slot> 7 </slot>
8 </view> 8 </view>
9 <text @tap.stop="labelClickHandler" :style="{ 9 <text @tap.stop="labelClickHandler" :style="{
10 - color: elDisabled ? elInactiveColor : elLabelColor,  
11 - fontSize: elLabelSize,  
12 - lineHeight: elLabelSize  
13 - }" style="flex-wrap: wrap;">{{ label }}</text> 10 + color: elDisabled ? elInactiveColor : elLabelColor,
  11 + fontSize: elLabelSize,
  12 + lineHeight: elLabelSize
  13 + }" style="flex-wrap: wrap;">{{ label }}</text>
14 </view> 14 </view>
15 </template> 15 </template>
16 16
@@ -89,7 +89,7 @@ export default { @@ -89,7 +89,7 @@ export default {
89 }, 89 },
90 // 组件选中激活时的颜色 90 // 组件选中激活时的颜色
91 elActiveColor() { 91 elActiveColor() {
92 - return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff'); 92 + return this.activeColor ? "#5ac725" : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
93 }, 93 },
94 // 组件选未中激活时的颜色 94 // 组件选未中激活时的颜色
95 elInactiveColor() { 95 elInactiveColor() {
garbage-removal/src/uview-plus/components/u-dropdown-item/props.js
1 -import defprops from '../../libs/config/props';  
2 export default { 1 export default {
3 props: { 2 props: {
  3 + // #ifdef VUE3
4 // 当前选中项的value值 4 // 当前选中项的value值
  5 + modelValue: {
  6 + type: [Number, String, Array],
  7 + default: ''
  8 + },
  9 + // #endif
  10 + // #ifdef VUE2
  11 + // 当前选中项的value值
5 value: { 12 value: {
6 type: [Number, String, Array], 13 type: [Number, String, Array],
7 default: '' 14 default: ''
8 }, 15 },
  16 + // #endif
9 // 菜单项标题 17 // 菜单项标题
10 title: { 18 title: {
11 type: [String, Number], 19 type: [String, Number],
@@ -32,6 +40,11 @@ export default { @@ -32,6 +40,11 @@ export default {
32 closeOnClickOverlay: { 40 closeOnClickOverlay: {
33 type: Boolean, 41 type: Boolean,
34 default: true 42 default: true
  43 + },
  44 + // 对齐方式
  45 + placement: {
  46 + type: String,
  47 + default: 'center'
35 } 48 }
36 } 49 }
37 } 50 }
garbage-removal/src/uview-plus/components/u-dropdown-item/u-dropdown-item.vue
1 <template> 1 <template>
2 - <view class="u-drawdown-item">  
3 - <u-overlay  
4 - customStyle="top: 126px"  
5 - :show="show"  
6 - :closeOnClickOverlay="closeOnClickOverlay"  
7 - @click="overlayClick"  
8 - ></u-overlay>  
9 - <view  
10 - class="u-drawdown-item__content"  
11 - :style="[style]"  
12 - :animation="animationData"  
13 - ref="animation"  
14 - >  
15 - <slot />  
16 - </view> 2 + <view class="u-dropdown-item" v-if="active" @touchmove.stop.prevent="() => { }" @tap.stop.prevent="() => { }">
  3 + <block v-if="!$slots.default && !$slots.$default">
  4 + <scroll-view scroll-y="true" :style="{ height: $u.addUnit(height) }">
  5 + <view class="u-dropdown-item__options">
  6 + <up-cell-group :activeStyle="activeStyle">
  7 + <up-cell @click="cellClick(item.value)" :border="false" :arrow="false" :title="item.label"
  8 + v-for="(item, index) in options" :key="index"
  9 + :title-style="{ color: modelValue == item.value ? activeColor : inactiveColor }">
  10 + <up-icon v-if="modelValue == item.value" name="checkbox-mark" :color="activeColor" size="32"></up-icon>
  11 + </up-cell>
  12 + </up-cell-group>
  13 + </view>
  14 + </scroll-view>
  15 + </block>
  16 + <slot v-else />
17 </view> 17 </view>
18 </template> 18 </template>
19 19
20 <script> 20 <script>
21 - // #ifdef APP-NVUE  
22 - const animation = uni.requireNativePlugin('animation')  
23 - const dom = uni.requireNativePlugin('dom')  
24 - // #endif  
25 - import props from './props.js';  
26 - import mpMixin from '../../libs/mixin/mpMixin.js';  
27 - import mixin from '../../libs/mixin/mixin.js';  
28 - /**  
29 - * Drawdownitem  
30 - * @description  
31 - * @tutorial url  
32 - * @property {String}  
33 - * @event {Function}  
34 - * @example  
35 - */  
36 - export default {  
37 - name: 'u-drawdown-item',  
38 - mixins: [mpMixin, mixin, props],  
39 - data() {  
40 - return {  
41 - show: false,  
42 - top: '126px',  
43 - // uni.createAnimation的导出数据  
44 - animationData: {},  
45 - }  
46 - },  
47 - mounted() {  
48 - this.init()  
49 - },  
50 - watch: {  
51 - // 发生变化时,需要去更新父组件对应的值  
52 - dataChange(newValue, oldValue) {  
53 - this.updateParentData()  
54 - }  
55 - },  
56 - computed: {  
57 - // 监听对应变量的变化  
58 - dataChange() {  
59 - return [this.title, this.disabled]  
60 - },  
61 - style() {  
62 - const style = {  
63 - zIndex: 10071,  
64 - position: 'fixed',  
65 - display: 'flex',  
66 - left: 0,  
67 - right: 0  
68 - }  
69 - style.top = uni.$u.addUnit(this.top)  
70 - return style 21 +import mixin from '../../libs/mixin/mixin.js';
  22 +import mpMixin from '../../libs/mixin/mpMixin.js';
  23 +import props from './props.js';
  24 +/**
  25 + * dropdown-item 下拉菜单
  26 + * @description 该组件一般用于向下展开菜单,同时可切换多个选项卡的场景
  27 + * @tutorial https://ijry.github.io/uview-plus/components/dropdown.html
  28 + * @property {String | Number} v-model 双向绑定选项卡选择值
  29 + * @property {String} title 菜单项标题
  30 + * @property {Array[Object]} options 选项数据,如果传入了默认slot,此参数无效
  31 + * @property {Boolean} disabled 是否禁用此选项卡(默认false)
  32 + * @property {String | Number} duration 选项卡展开和收起的过渡时间,单位ms(默认300)
  33 + * @property {String | Number} height 弹窗下拉内容的高度(内容超出将会滚动)(默认auto)
  34 + * @example <u-dropdown-item title="标题"></u-dropdown-item>
  35 + */
  36 +export default {
  37 + name: 'u-dropdown-item',
  38 + mixins: [mpMixin, mixin, props],
  39 + options: {
  40 + styleIsolation: 'shared',
  41 + },
  42 + data() {
  43 + return {
  44 + activeStyle: {},
  45 + active: false, // 当前项是否处于展开状态
  46 + activeColor: '#2979ff', // 激活时左边文字和右边对勾图标的颜色
  47 + inactiveColor: '#606266', // 未激活时左边文字和右边对勾图标的颜色
  48 + }
  49 + },
  50 + computed: {
  51 + // 监听props是否发生了变化,有些值需要传递给父组件u-dropdown,无法双向绑定
  52 + propsChange() {
  53 + return `${this.title}-${this.disabled}`;
  54 + }
  55 + },
  56 + watch: {
  57 + propsChange(n) {
  58 + // 当值变化时,通知父组件重新初始化,让父组件执行每个子组件的init()方法
  59 + // 将所有子组件数据重新整理一遍
  60 + if (this.parent) this.parent.init();
  61 + }
  62 + },
  63 + created() {
  64 + // 父组件的实例
  65 + this.parent = false;
  66 + },
  67 + emits: ['update:modelValue', 'change'],
  68 + methods: {
  69 + activeStyleInit() {
  70 + this.activeStyle = {
  71 + alignItems: this.placement == 'center' ? 'center' : this.placement == 'right' ? 'flex-end' : 'flex-start',
71 } 72 }
72 }, 73 },
73 - methods: {  
74 - init() {  
75 - this.updateParentData()  
76 - },  
77 - // 更新父组件所需的数据  
78 - updateParentData() {  
79 - // 获取父组件u-dropdown  
80 - this.getParentData('u-dropdown')  
81 - if (!this.parent) uni.$u.error('u-dropdown-item必须配合u-dropdown使用')  
82 - // 查找父组件menuList数组中对应的标题数据  
83 - const menuIndex = this.parent.menuList.findIndex(item => item.title === this.title)  
84 - const menuContent = { 74 + init() {
  75 + // 获取父组件u-dropdown
  76 + let parent = this.$u.$parent.call(this, 'u-dropdown');
  77 + if (parent) {
  78 + this.parent = parent;
  79 + // 将子组件的激活颜色配置为父组件设置的激活和未激活时的颜色
  80 + this.activeColor = parent.activeColor;
  81 + this.inactiveColor = parent.inactiveColor;
  82 + // 将本组件的this,放入到父组件的children数组中,让父组件可以操作本(子)组件的方法和属性
  83 + // push进去前,显判断是否已经存在了本实例,因为在子组件内部数据变化时,会通过父组件重新初始化子组件
  84 + let exist = parent.children.find(val => {
  85 + return this === val;
  86 + })
  87 + if (!exist) parent.children.push(this);
  88 + if (parent.children.length == 1) this.active = true;
  89 + // 父组件无法监听children的变化,故将子组件的title,传入父组件的menuList数组中
  90 + parent.menuList.push({
85 title: this.title, 91 title: this.title,
86 disabled: this.disabled 92 disabled: this.disabled
87 - }  
88 - if (menuIndex >= 0) {  
89 - // 如果能找到,则直接修改  
90 - this.parent.menuList[menuIndex] = menuContent;  
91 - } else {  
92 - // 如果无法找到,则为第一次添加,直接push即可  
93 - this.parent.menuList.push(menuContent);  
94 - }  
95 - },  
96 - async setContentAnimate(height) {  
97 - this.animating = true  
98 - // #ifdef APP-NVUE  
99 - const ref = this.$refs['animation'].ref  
100 - animation.transition(ref, {  
101 - styles: {  
102 - height: uni.$u.addUnit(height)  
103 - },  
104 - duration: this.duration,  
105 - timingFunction: 'ease-in-out',  
106 - }, () => {  
107 - this.animating = false  
108 - })  
109 - // #endif  
110 -  
111 - // #ifndef APP-NVUE  
112 - const animation = uni.createAnimation({  
113 - timingFunction: 'ease-in-out',  
114 }); 93 });
115 - animation  
116 - .height(height)  
117 - .step({  
118 - duration: this.duration,  
119 - })  
120 - .step()  
121 - // 导出动画数据给面板的animationData值  
122 - this.animationData = animation.export()  
123 - // 标识动画结束  
124 - uni.$u.sleep(this.duration).then(() => {  
125 - this.animating = false  
126 - })  
127 - // #endif  
128 - },  
129 - overlayClick() {  
130 - this.show = false  
131 - this.setContentAnimate(0)  
132 } 94 }
133 }, 95 },
  96 + // cell被点击
  97 + cellClick(value) {
  98 + // 修改通过v-model绑定的值
  99 + // #ifdef VUE2
  100 + this.$emit('input', value);
  101 + // #endif
  102 + // #ifdef VUE3
  103 + this.$emit('update:modelValue', value);
  104 + // #endif
  105 + // 通知父组件(u-dropdown)收起菜单
  106 + this.parent.close();
  107 + // 发出事件,抛出当前勾选项的value
  108 + this.$emit('change', value);
  109 + }
  110 + },
  111 + mounted() {
  112 + this.init();
  113 + this.activeStyleInit();
134 } 114 }
  115 +}
135 </script> 116 </script>
136 117
137 -<style lang="scss" scoped>  
138 - @import '../../libs/css/components.scss';  
139 -  
140 - .u-drawdown-item {  
141 -  
142 - &__content {  
143 - background-color: #FFFFFF;  
144 - overflow: hidden;  
145 - height: 0;  
146 - } 118 +<style scoped lang="scss">
  119 +@import "../../libs/css/components.scss";
  120 +
  121 +.u-dropdown-item__options {
  122 + ::v-deep .u-cell-group {
  123 + background: #ffffffeb;
147 } 124 }
  125 +
  126 +}
148 </style> 127 </style>
garbage-removal/src/uview-plus/components/u-dropdown/props.js
1 -import defprops from '../../libs/config/props';  
2 export default { 1 export default {
3 props: { 2 props: {
4 - // 标题选中时的样式  
5 - activeStyle: {  
6 - type: [String, Object],  
7 - default: () => ({  
8 - color: '#2979ff',  
9 - fontSize: '14px'  
10 - }) 3 + // 菜单标题和选项的激活态颜色
  4 + activeColor: {
  5 + type: String,
  6 + default: '#2979ff'
11 }, 7 },
12 - // 标题未选中时的样式  
13 - inactiveStyle: {  
14 - type: [String, Object],  
15 - default: () => ({  
16 - color: '#606266',  
17 - fontSize: '14px'  
18 - }) 8 + // 菜单标题和选项的未激活态颜色
  9 + inactiveColor: {
  10 + type: String,
  11 + default: '#606266'
19 }, 12 },
20 // 点击遮罩是否关闭菜单 13 // 点击遮罩是否关闭菜单
21 closeOnClickMask: { 14 closeOnClickMask: {
@@ -45,7 +38,7 @@ export default { @@ -45,7 +38,7 @@ export default {
45 // 标题的字体大小 38 // 标题的字体大小
46 titleSize: { 39 titleSize: {
47 type: [Number, String], 40 type: [Number, String],
48 - default: 14 41 + default: 28
49 }, 42 },
50 // 下拉出来的内容部分的圆角值 43 // 下拉出来的内容部分的圆角值
51 borderRadius: { 44 borderRadius: {
garbage-removal/src/uview-plus/components/u-dropdown/u-dropdown.vue
1 <template> 1 <template>
2 - <view class="u-drawdown">  
3 - <view  
4 - class="u-dropdown__menu"  
5 - :style="{  
6 - height: $u.addUnit(height)  
7 - }"  
8 - ref="u-dropdown__menu"  
9 - >  
10 - <view  
11 - class="u-dropdown__menu__item"  
12 - v-for="(item, index) in menuList"  
13 - :key="index"  
14 - @tap.stop="clickHandler(item, index)"  
15 - >  
16 - <view class="u-dropdown__menu__item__content">  
17 - <text  
18 - class="u-dropdown__menu__item__content__text"  
19 - :style="[index === current ? activeStyle : inactiveStyle]"  
20 - >{{item.title}}</text>  
21 - <view  
22 - class="u-dropdown__menu__item__content__arrow"  
23 - :class="[index === current && 'u-dropdown__menu__item__content__arrow--rotate']"  
24 - >  
25 - <u-icon  
26 - :name="menuIcon"  
27 - :size="$u.addUnit(menuIconSize)"  
28 - ></u-icon> 2 + <view class="u-dropdown">
  3 + <view class="u-dropdown__menu" :style="{
  4 + height: $u.addUnit(height)
  5 + }" :class="{
  6 + 'u-border-bottom': borderBottom
  7 + }">
  8 + <view class="u-dropdown__menu__item" v-for="(item, index) in menuList" :key="index" @tap.stop="menuClick(index)">
  9 + <view class="u-flex u-flex-row">
  10 + <text class="u-dropdown__menu__item__text" :style="{
  11 + color: item.disabled ? '#c0c4cc' : (index === current || highlightIndex == index) ? activeColor : inactiveColor,
  12 + fontSize: $u.addUnit(titleSize)
  13 + }">{{ item.title }}</text>
  14 + <view class="u-dropdown__menu__item__arrow" :class="{
  15 + 'u-dropdown__menu__item__arrow--rotate': index === current
  16 + }">
  17 + <u-icon :custom-style="{ display: 'flex' }" :name="menuIcon" :size="$u.addUnit(menuIconSize)"
  18 + :color="index === current || highlightIndex == index ? activeColor : '#c0c4cc'"></u-icon>
29 </view> 19 </view>
30 </view> 20 </view>
31 </view> 21 </view>
32 </view> 22 </view>
33 - <view class="u-dropdown__content">  
34 - <slot /> 23 + <view class="u-dropdown__content" :style="[contentStyle, {
  24 + transition: `opacity ${duration / 1000}s linear`,
  25 + top: $u.addUnit(height),
  26 + height: contentHeight + 'px'
  27 + }]" @tap="maskClick" @touchmove.stop.prevent>
  28 + <view @tap.stop.prevent class="u-dropdown__content__popup" :style="[popupStyle]">
  29 + <slot></slot>
  30 + </view>
  31 + <view class="u-dropdown__content__mask"></view>
35 </view> 32 </view>
36 </view> 33 </view>
37 </template> 34 </template>
38 35
39 <script> 36 <script>
40 - import props from './props.js';  
41 - import mpMixin from '../../libs/mixin/mpMixin.js';  
42 - import mixin from '../../libs/mixin/mixin.js';  
43 - /**  
44 - * Dropdown  
45 - * @description  
46 - * @tutorial url  
47 - * @property {String}  
48 - * @event {Function}  
49 - * @example  
50 - */  
51 - export default {  
52 - name: 'u-dropdown',  
53 - mixins: [mixin, props],  
54 - data() {  
55 - return {  
56 - // �˵�����  
57 - menuList: [],  
58 - current: 0 37 +import mixin from '../../libs/mixin/mixin.js';
  38 +import mpMixin from '../../libs/mixin/mpMixin.js';
  39 +import props from './props.js';
  40 +/**
  41 + * dropdown 下拉菜单
  42 + * @description 该组件一般用于向下展开菜单,同时可切换多个选项卡的场景
  43 + * @tutorial https://ijry.github.io/uview-plus/components/dropdown.html
  44 + * @property {String} active-color 标题和选项卡选中的颜色(默认#2979ff)
  45 + * @property {String} inactive-color 标题和选项卡未选中的颜色(默认#606266)
  46 + * @property {Boolean} close-on-click-mask 点击遮罩是否关闭菜单(默认true)
  47 + * @property {Boolean} close-on-click-self 点击当前激活项标题是否关闭菜单(默认true)
  48 + * @property {String | Number} duration 选项卡展开和收起的过渡时间,单位ms(默认300)
  49 + * @property {String | Number} height 标题菜单的高度,单位任意(默认80)
  50 + * @property {String | Number} border-radius 菜单展开内容下方的圆角值,单位任意(默认0)
  51 + * @property {Boolean} border-bottom 标题菜单是否显示下边框(默认false)
  52 + * @property {String | Number} title-size 标题的字体大小,单位任意,数值默认为rpx单位(默认28)
  53 + * @event {Function} open 下拉菜单被打开时触发
  54 + * @event {Function} close 下拉菜单被关闭时触发
  55 + * @example <u-dropdown></u-dropdown>
  56 + */
  57 +export default {
  58 + name: 'u-dropdown',
  59 + mixins: [mpMixin, mixin, props],
  60 + data() {
  61 + return {
  62 + showDropdown: true, // 是否打开下来菜单,
  63 + menuList: [], // 显示的菜单
  64 + active: false, // 下拉菜单的状态
  65 + // 当前是第几个菜单处于激活状态,小程序中此处不能写成false或者"",否则后续将current赋值为0,
  66 + // 无能的TX没有使用===而是使用==判断,导致程序认为前后二者没有变化,从而不会触发视图更新
  67 + current: 99999,
  68 + // 外层内容的样式,初始时处于底层,且透明
  69 + contentStyle: {
  70 + zIndex: -1,
  71 + opacity: 0
  72 + },
  73 + // 让某个菜单保持高亮的状态
  74 + highlightIndex: 99999,
  75 + contentHeight: 0
  76 + }
  77 + },
  78 + computed: {
  79 + // 下拉出来部分的样式
  80 + popupStyle() {
  81 + let style = {};
  82 + // 进行Y轴位移,展开状态时,恢复原位。收齐状态时,往上位移100%,进行隐藏
  83 + style.transform = `translateY(${this.active ? 0 : '-100%'})`
  84 + style['transition-duration'] = this.duration / 1000 + 's';
  85 + style.borderRadius = `0 0 ${this.$u.addUnit(this.borderRadius)} ${this.$u.addUnit(this.borderRadius)}`;
  86 + return style;
  87 + }
  88 + },
  89 + created() {
  90 + // 引用所有子组件(u-dropdown-item)的this,不能在data中声明变量,否则在微信小程序会造成循环引用而报错
  91 + this.children = [];
  92 + },
  93 + mounted() {
  94 + this.getContentHeight();
  95 + },
  96 + emits: ['open', 'close'],
  97 + methods: {
  98 + init() {
  99 + // 当某个子组件内容变化时,触发父组件的init,父组件再让每一个子组件重新初始化一遍
  100 + // 以保证数据的正确性
  101 + this.menuList = [];
  102 + this.children.map(child => {
  103 + child.init();
  104 + })
  105 + },
  106 + // 点击菜单
  107 + menuClick(index) {
  108 + // 判断是否被禁用
  109 + if (this.menuList[index].disabled) return;
  110 + // 如果点击时的索引和当前激活项索引相同,意味着点击了激活项,需要收起下拉菜单
  111 + if (index === this.current && this.closeOnClickSelf) {
  112 + this.close();
  113 + // 等动画结束后,再移除下拉菜单中的内容,否则直接移除,也就没有下拉菜单收起的效果了
  114 + setTimeout(() => {
  115 + this.children[index].active = false;
  116 + }, this.duration)
  117 + return;
  118 + }
  119 + this.open(index);
  120 + },
  121 + // 打开下拉菜单
  122 + open(index) {
  123 + // 嵌套popup使用时可能获取不到正确的高度,重新计算
  124 + if (this.contentHeight < 1) this.getContentHeight()
  125 + // 重置高亮索引,否则会造成多个菜单同时高亮
  126 + // this.highlightIndex = 9999;
  127 + // 展开时,设置下拉内容的样式
  128 + this.contentStyle = {
  129 + zIndex: 11,
59 } 130 }
  131 + // 标记展开状态以及当前展开项的索引
  132 + this.active = true;
  133 + this.current = index;
  134 + // 历遍所有的子元素,将索引匹配的项标记为激活状态,因为子元素是通过v-if控制切换的
  135 + // 之所以不是因display: none,是因为nvue没有display这个属性
  136 + this.children.map((val, idx) => {
  137 + val.active = index == idx ? true : false;
  138 + })
  139 + this.$emit('open', this.current);
60 }, 140 },
61 - computed: {  
62 - 141 + // 设置下拉菜单处于收起状态
  142 + close() {
  143 + this.$emit('close', this.current);
  144 + // 设置为收起状态,同时current归位,设置为空字符串
  145 + this.active = false;
  146 + this.current = 99999;
  147 + // 下拉内容的样式进行调整,不透明度设置为0
  148 + this.contentStyle = {
  149 + zIndex: -1,
  150 + opacity: 0
  151 + }
63 }, 152 },
64 - created() {  
65 - // �������������(u-dropdown-item)��this��������data������������������΢��С��������ѭ�����ö�����  
66 - this.children = []; 153 + // 点击遮罩
  154 + maskClick() {
  155 + // 如果不允许点击遮罩,直接返回
  156 + if (!this.closeOnClickMask) return;
  157 + this.close();
67 }, 158 },
68 - methods: {  
69 - clickHandler(item, index) {  
70 - this.children.map(child => {  
71 - if(child.title === item.title) {  
72 - // this.queryRect('u-dropdown__menu').then(size => {  
73 - child.$emit('click')  
74 - child.setContentAnimate(child.show ? 0 : 300)  
75 - child.show = !child.show  
76 - // })  
77 - } else {  
78 - child.show = false  
79 - child.setContentAnimate(0)  
80 - }  
81 - })  
82 - },  
83 - // ��ȡ��ǩ�ijߴ�λ��  
84 - queryRect(el) {  
85 - // #ifndef APP-NVUE  
86 - // $uGetRectΪuView�Դ��Ľڵ��ѯ�򻯷���https://ijry.github.io/uview-plus/.uviewui.com/js/getRect.html  
87 - // ����ڲ�һ����this.$uGetRect�������Ϊthis.$u.getRect�����߹���һ�£����Ʋ�ͬ  
88 - return new Promise(resolve => {  
89 - this.$uGetRect(`.${el}`).then(size => {  
90 - resolve(size)  
91 - })  
92 - })  
93 - // #endif  
94 -  
95 - // #ifdef APP-NVUE  
96 - // nvue�£�ʹ��domģ���ѯԪ�ظ߶�  
97 - // ����һ��promise���õ��ô˷�����������ʹ��then�ص�  
98 - return new Promise(resolve => {  
99 - dom.getComponentRect(this.$refs[el], res => {  
100 - resolve(res.size)  
101 - })  
102 - })  
103 - // #endif  
104 - }, 159 + // 外部手动设置某个菜单高亮
  160 + highlight(index = undefined) {
  161 + this.highlightIndex = index !== undefined ? index : 99999;
105 }, 162 },
  163 + // 获取下拉菜单内容的高度
  164 + getContentHeight() {
  165 + // 这里的原理为,因为dropdown组件是相对定位的,它的下拉出来的内容,必须给定一个高度
  166 + // 才能让遮罩占满菜单一下,直到屏幕底部的高度
  167 + // this.$u.sys()为uView封装的获取设备信息的方法
  168 + let windowHeight = this.$u.sys().windowHeight;
  169 + this.$uGetRect('.u-dropdown__menu').then(res => {
  170 + // 这里获取的是dropdown的尺寸,在H5上,uniapp获取尺寸是有bug的(以前提出修复过,后来又出现了此bug,目前hx2.8.11版本)
  171 + // H5端bug表现为元素尺寸的top值为导航栏底部到到元素的上边沿的距离,但是元素的bottom值确是导航栏顶部到元素底部的距离
  172 + // 二者是互相矛盾的,本质原因是H5端导航栏非原生,uni的开发者大意造成
  173 + // 这里取菜单栏的botton值合理的,不能用res.top,否则页面会造成滚动
  174 + this.contentHeight = windowHeight - res.bottom;
  175 + })
  176 + }
106 } 177 }
  178 +}
107 </script> 179 </script>
108 180
109 -<style lang="scss">  
110 - @import '../../libs/css/components.scss'; 181 +<style scoped lang="scss">
  182 +@import "../../libs/css/components.scss";
  183 +
  184 +.u-dropdown {
  185 + flex: 1;
  186 + width: 100%;
  187 + position: relative;
111 188
112 - .u-dropdown { 189 + &__menu {
  190 + @include flex;
  191 + position: relative;
  192 + z-index: 11;
  193 + height: 80rpx;
113 194
114 - &__menu { 195 + &__item {
  196 + flex: 1;
115 @include flex; 197 @include flex;
  198 + justify-content: center;
  199 + align-items: center;
116 200
117 - &__item {  
118 - flex: 1; 201 + .u-flex-row {
  202 + flex-direction: row;
  203 + }
  204 +
  205 + &__text {
  206 + font-size: 28rpx;
  207 + color: $u-content-color;
  208 + }
  209 +
  210 + &__arrow {
  211 + margin-left: 6rpx;
  212 + transition: transform .3s;
  213 + align-items: center;
119 @include flex; 214 @include flex;
120 - justify-content: center;  
121 215
122 - &__content {  
123 - @include flex;  
124 - align-items: center; 216 + &--rotate {
  217 + transform: rotate(180deg);
125 } 218 }
126 } 219 }
127 } 220 }
128 } 221 }
  222 +
  223 + &__content {
  224 + position: absolute;
  225 + z-index: 8;
  226 + width: 100%;
  227 + left: 0px;
  228 + bottom: 0;
  229 + overflow: hidden;
  230 +
  231 +
  232 + &__mask {
  233 + position: absolute;
  234 + z-index: 9;
  235 + // background: rgba(0, 0, 0, .3);
  236 + width: 100%;
  237 + left: 0;
  238 + top: 0;
  239 + bottom: 0;
  240 + }
  241 +
  242 + &__popup {
  243 + position: relative;
  244 + z-index: 10;
  245 + transition: all 0.3s;
  246 + transform: translate3D(0, -100%, 0);
  247 + overflow: hidden;
  248 + }
  249 + }
  250 +
  251 +}
129 </style> 252 </style>
garbage-removal/src/uview-plus/components/u-form-item/u-form-item.vue
@@ -7,19 +7,20 @@ @@ -7,19 +7,20 @@
7 <slot name="label"> 7 <slot name="label">
8 <!-- {{required}} --> 8 <!-- {{required}} -->
9 <view class="u-form-item__body__left" v-if="required || leftIcon || label" :style="{ 9 <view class="u-form-item__body__left" v-if="required || leftIcon || label" :style="{
10 - width: $u.addUnit(labelWidth || parentData.labelWidth),  
11 - marginBottom: parentData.labelPosition === 'left' ? 0 : '5px',  
12 - }"> 10 + width: $u.addUnit(labelWidth || parentData.labelWidth),
  11 + marginBottom: parentData.labelPosition === 'left' ? 0 : '5px',
  12 + }">
13 <!-- 为了块对齐 --> 13 <!-- 为了块对齐 -->
14 <view class="u-form-item__body__left__content"> 14 <view class="u-form-item__body__left__content">
15 <!-- nvue不支持伪元素before --> 15 <!-- nvue不支持伪元素before -->
16 - <text v-if="required" class="u-form-item__body__left__content__required">*</text> 16 + <text v-if="required" class="u-form-item__body__left__content__required"
  17 + style="top: -3px !important;font-size: 14px !important;">*</text>
17 <view class="u-form-item__body__left__content__icon" v-if="leftIcon"> 18 <view class="u-form-item__body__left__content__icon" v-if="leftIcon">
18 <u-icon :name="leftIcon" :custom-style="leftIconStyle"></u-icon> 19 <u-icon :name="leftIcon" :custom-style="leftIconStyle"></u-icon>
19 </view> 20 </view>
20 <text class="u-form-item__body__left__content__label" :style="[parentData.labelStyle, { 21 <text class="u-form-item__body__left__content__label" :style="[parentData.labelStyle, {
21 - justifyContent: parentData.labelAlign === 'left' ? 'flex-start' : parentData.labelAlign === 'center' ? 'center' : 'flex-end'  
22 - }]">{{ label }}</text> 22 + justifyContent: parentData.labelAlign === 'left' ? 'flex-start' : parentData.labelAlign === 'center' ? 'center' : 'flex-end'
  23 + }]">{{ label }}</text>
23 </view> 24 </view>
24 </view> 25 </view>
25 </slot> 26 </slot>
@@ -36,8 +37,8 @@ @@ -36,8 +37,8 @@
36 </view> 37 </view>
37 <slot name="error"> 38 <slot name="error">
38 <text v-if="!!message && parentData.errorType === 'message'" class="u-form-item__body__right__message" :style="{ 39 <text v-if="!!message && parentData.errorType === 'message'" class="u-form-item__body__right__message" :style="{
39 - marginLeft: $u.addUnit(parentData.labelPosition === 'top' ? 0 : (labelWidth || parentData.labelWidth))  
40 - }">{{ message }}</text> 40 + marginLeft: $u.addUnit(parentData.labelPosition === 'top' ? 0 : (labelWidth || parentData.labelWidth))
  41 + }">{{ message }}</text>
41 </slot> 42 </slot>
42 <u-line v-if="borderBottom" 43 <u-line v-if="borderBottom"
43 :color="message && parentData.errorType === 'border-bottom' ? $u.color.error : propsLine.color" 44 :color="message && parentData.errorType === 'border-bottom' ? $u.color.error : propsLine.color"
garbage-removal/src/uview-plus/components/u-search/u-search.vue
1 <template> 1 <template>
2 - <view  
3 - class="u-search"  
4 - @tap="clickHandler"  
5 - :style="[{  
6 - margin: margin,  
7 - }, $u.addStyle(customStyle)]"  
8 - >  
9 - <view  
10 - class="u-search__content"  
11 - :style="{  
12 - backgroundColor: bgColor,  
13 - borderRadius: shape == 'round' ? '100px' : '4px',  
14 - borderColor: borderColor,  
15 - }"  
16 - > 2 + <view class="u-search" :style="[{
  3 + margin: margin,
  4 + }, $u.addStyle(customStyle)]">
  5 + <view class="u-search__content" :style="{
  6 + backgroundColor: bgColor,
  7 + borderRadius: shape == 'round' ? '100px' : '4px',
  8 + borderColor: borderColor,
  9 + }">
17 <template v-if="$slots.label || label !== null"> 10 <template v-if="$slots.label || label !== null">
18 <slot name="label"> 11 <slot name="label">
19 <text class="u-search__content__label">{{ label }}</text> 12 <text class="u-search__content__label">{{ label }}</text>
20 </slot> 13 </slot>
21 </template> 14 </template>
22 <view class="u-search__content__icon"> 15 <view class="u-search__content__icon">
23 - <u-icon  
24 - @tap="clickIcon"  
25 - :size="searchIconSize"  
26 - :name="searchIcon"  
27 - :color="searchIconColor ? searchIconColor : color"  
28 - ></u-icon> 16 + <u-icon @click.stop="clickIcon" :size="searchIconSize" :name="searchIcon"
  17 + :color="searchIconColor ? searchIconColor : color"></u-icon>
29 </view> 18 </view>
30 - <input  
31 - confirm-type="search"  
32 - @blur="blur"  
33 - :value="keyword"  
34 - @confirm="search"  
35 - @input="inputChange"  
36 - :disabled="disabled"  
37 - @focus="getFocus"  
38 - :focus="focus"  
39 - :maxlength="maxlength"  
40 - placeholder-class="u-search__content__input--placeholder"  
41 - :placeholder="placeholder"  
42 - :placeholder-style="`color: ${placeholderColor}`"  
43 - class="u-search__content__input"  
44 - type="text"  
45 - :style="[{  
46 - textAlign: inputAlign,  
47 - color: color,  
48 - backgroundColor: bgColor,  
49 - height: $u.addUnit(height)  
50 - }, inputStyle]"  
51 - />  
52 - <view  
53 - class="u-search__content__icon u-search__content__close"  
54 - v-if="keyword && clearabled && focused"  
55 - @tap="clear"  
56 - >  
57 - <u-icon  
58 - name="close"  
59 - size="11"  
60 - color="#ffffff"  
61 - customStyle="line-height: 12px"  
62 - ></u-icon> 19 + <input @tap.stop="clickHandler" confirm-type="search" @blur="blur" :value="keyword" @confirm="search"
  20 + @input="inputChange" :disabled="disabled" @focus="getFocus" :focus="focus" :maxlength="maxlength"
  21 + placeholder-class="u-search__content__input--placeholder" :placeholder="placeholder"
  22 + :placeholder-style="`color: ${placeholderColor}`" class="u-search__content__input" type="text" :style="[{
  23 + textAlign: inputAlign,
  24 + color: color,
  25 + backgroundColor: bgColor,
  26 + height: $u.addUnit(height)
  27 + }, inputStyle]" />
  28 + <view class="u-search__content__icon u-search__content__close" v-if="keyword && clearabled && focused"
  29 + @tap="clear">
  30 + <u-icon name="close" size="11" color="#ffffff" customStyle="line-height: 12px"></u-icon>
63 </view> 31 </view>
64 </view> 32 </view>
65 - <text  
66 - :style="[actionStyle]"  
67 - class="u-search__action"  
68 - :class="[(showActionBtn || show) && 'u-search__action--active']"  
69 - @tap.stop.prevent="custom"  
70 - >{{ actionText }}</text> 33 + <text :style="[actionStyle]" class="u-search__action"
  34 + :class="[(showActionBtn || show) && 'u-search__action--active']" @tap.stop.prevent="custom">{{ actionText
  35 + }}</text>
71 </view> 36 </view>
72 </template> 37 </template>
73 38
74 <script> 39 <script>
75 - import props from './props.js';  
76 - import mpMixin from '../../libs/mixin/mpMixin.js';  
77 - import mixin from '../../libs/mixin/mixin.js'; 40 +import mixin from '../../libs/mixin/mixin.js';
  41 +import mpMixin from '../../libs/mixin/mpMixin.js';
  42 +import props from './props.js';
78 43
79 - /**  
80 - * search 搜索框  
81 - * @description 搜索组件,集成了常见搜索框所需功能,用户可以一键引入,开箱即用。  
82 - * @tutorial https://ijry.github.io/uview-plus/components/search.html  
83 - * @property {String} shape 搜索框形状,round-圆形,square-方形(默认 'round' )  
84 - * @property {String} bgColor 搜索框背景颜色(默认 '#f2f2f2' )  
85 - * @property {String} placeholder 占位文字内容(默认 '请输入关键字' )  
86 - * @property {Boolean} clearabled 是否启用清除控件(默认 true )  
87 - * @property {Boolean} focus 是否自动获得焦点(默认 false )  
88 - * @property {Boolean} showAction 是否显示右侧控件(默认 true )  
89 - * @property {Object} actionStyle 右侧控件的样式,对象形式  
90 - * @property {String} actionText 右侧控件文字(默认 '搜索' )  
91 - * @property {String} inputAlign 输入框内容水平对齐方式 (默认 'left' )  
92 - * @property {Object} inputStyle 自定义输入框样式,对象形式  
93 - * @property {Boolean} disabled 是否启用输入框(默认 false )  
94 - * @property {String} borderColor 边框颜色,配置了颜色,才会有边框 (默认 'transparent' )  
95 - * @property {String} searchIconColor 搜索图标的颜色,默认同输入框字体颜色 (默认 '#909399' )  
96 - * @property {Number | String} searchIconSize 搜索图标的字体,默认22  
97 - * @property {String} color 输入框字体颜色(默认 '#606266' )  
98 - * @property {String} placeholderColor placeholder的颜色(默认 '#909399' )  
99 - * @property {String} searchIcon 输入框左边的图标,可以为uView图标名称或图片路径 (默认 'search' )  
100 - * @property {String} margin 组件与其他上下左右元素之间的距离,带单位的字符串形式,如"30px" (默认 '0' )  
101 - * @property {Boolean} animation 是否开启动画,见上方说明(默认 false )  
102 - * @property {String} value 输入框初始值  
103 - * @property {String | Number} maxlength 输入框最大能输入的长度,-1为不限制长度 (默认 '-1' )  
104 - * @property {String | Number} height 输入框高度,单位px(默认 64 )  
105 - * @property {String | Number} label 搜索框左边显示内容  
106 - * @property {Object} customStyle 定义需要用到的外部样式  
107 - *  
108 - * @event {Function} change 输入框内容发生变化时触发  
109 - * @event {Function} search 用户确定搜索时触发,用户按回车键,或者手机键盘右下角的"搜索"键时触发  
110 - * @event {Function} custom 用户点击右侧控件时触发  
111 - * @event {Function} clear 用户点击清除按钮时触发  
112 - * @example <u-search placeholder="日照香炉生紫烟" v-model="keyword"></u-search>  
113 - */  
114 - export default {  
115 - name: "u-search",  
116 - mixins: [mpMixin, mixin, props],  
117 - data() {  
118 - return {  
119 - keyword: '',  
120 - showClear: false, // 是否显示右边的清除图标  
121 - show: false,  
122 - // 标记input当前状态是否处于聚焦中,如果是,才会显示右侧的清除控件  
123 - focused: this.focus  
124 - // 绑定输入框的值  
125 - // inputValue: this.value  
126 - };  
127 - },  
128 - watch: {  
129 - keyword(nVal) {  
130 - // 双向绑定值,让v-model绑定的值双向变化  
131 - // #ifdef VUE3  
132 - this.$emit("update:modelValue", nVal);  
133 - // #endif  
134 - // #ifdef VUE2  
135 - this.$emit('input', nVal);  
136 - // #endif  
137 - // 触发change事件,事件效果和v-model双向绑定的效果一样,让用户多一个选择  
138 - this.$emit('change', nVal);  
139 - }, 44 +/**
  45 + * search 搜索框
  46 + * @description 搜索组件,集成了常见搜索框所需功能,用户可以一键引入,开箱即用。
  47 + * @tutorial https://ijry.github.io/uview-plus/components/search.html
  48 + * @property {String} shape 搜索框形状,round-圆形,square-方形(默认 'round' )
  49 + * @property {String} bgColor 搜索框背景颜色(默认 '#f2f2f2' )
  50 + * @property {String} placeholder 占位文字内容(默认 '请输入关键字' )
  51 + * @property {Boolean} clearabled 是否启用清除控件(默认 true )
  52 + * @property {Boolean} focus 是否自动获得焦点(默认 false )
  53 + * @property {Boolean} showAction 是否显示右侧控件(默认 true )
  54 + * @property {Object} actionStyle 右侧控件的样式,对象形式
  55 + * @property {String} actionText 右侧控件文字(默认 '搜索' )
  56 + * @property {String} inputAlign 输入框内容水平对齐方式 (默认 'left' )
  57 + * @property {Object} inputStyle 自定义输入框样式,对象形式
  58 + * @property {Boolean} disabled 是否启用输入框(默认 false )
  59 + * @property {String} borderColor 边框颜色,配置了颜色,才会有边框 (默认 'transparent' )
  60 + * @property {String} searchIconColor 搜索图标的颜色,默认同输入框字体颜色 (默认 '#909399' )
  61 + * @property {Number | String} searchIconSize 搜索图标的字体,默认22
  62 + * @property {String} color 输入框字体颜色(默认 '#606266' )
  63 + * @property {String} placeholderColor placeholder的颜色(默认 '#909399' )
  64 + * @property {String} searchIcon 输入框左边的图标,可以为uView图标名称或图片路径 (默认 'search' )
  65 + * @property {String} margin 组件与其他上下左右元素之间的距离,带单位的字符串形式,如"30px" (默认 '0' )
  66 + * @property {Boolean} animation 是否开启动画,见上方说明(默认 false )
  67 + * @property {String} value 输入框初始值
  68 + * @property {String | Number} maxlength 输入框最大能输入的长度,-1为不限制长度 (默认 '-1' )
  69 + * @property {String | Number} height 输入框高度,单位px(默认 64 )
  70 + * @property {String | Number} label 搜索框左边显示内容
  71 + * @property {Object} customStyle 定义需要用到的外部样式
  72 + *
  73 + * @event {Function} change 输入框内容发生变化时触发
  74 + * @event {Function} search 用户确定搜索时触发,用户按回车键,或者手机键盘右下角的"搜索"键时触发
  75 + * @event {Function} custom 用户点击右侧控件时触发
  76 + * @event {Function} clear 用户点击清除按钮时触发
  77 + * @example <u-search placeholder="日照香炉生紫烟" v-model="keyword"></u-search>
  78 + */
  79 +export default {
  80 + name: "u-search",
  81 + mixins: [mpMixin, mixin, props],
  82 + data() {
  83 + return {
  84 + keyword: '',
  85 + showClear: false, // 是否显示右边的清除图标
  86 + show: false,
  87 + // 标记input当前状态是否处于聚焦中,如果是,才会显示右侧的清除控件
  88 + focused: this.focus
  89 + // 绑定输入框的值
  90 + // inputValue: this.value
  91 + };
  92 + },
  93 + watch: {
  94 + keyword(nVal) {
  95 + // 双向绑定值,让v-model绑定的值双向变化
140 // #ifdef VUE3 96 // #ifdef VUE3
141 - modelValue: {  
142 - immediate: true,  
143 - handler(nVal) {  
144 - this.keyword = nVal;  
145 - }  
146 - }, 97 + this.$emit("update:modelValue", nVal);
147 // #endif 98 // #endif
148 // #ifdef VUE2 99 // #ifdef VUE2
149 - value: {  
150 - immediate: true,  
151 - handler(nVal) {  
152 - this.keyword = nVal;  
153 - }  
154 - }, 100 + this.$emit('input', nVal);
155 // #endif 101 // #endif
  102 + // 触发change事件,事件效果和v-model双向绑定的效果一样,让用户多一个选择
  103 + this.$emit('change', nVal);
156 }, 104 },
157 - computed: {  
158 - showActionBtn() {  
159 - return !this.animation && this.showAction 105 + // #ifdef VUE3
  106 + modelValue: {
  107 + immediate: true,
  108 + handler(nVal) {
  109 + this.keyword = nVal;
160 } 110 }
161 }, 111 },
162 - emits: ['clear', 'search', 'custom', 'focus', 'blur', 'click', 'clickIcon', 'update:modelValue', 'change'],  
163 - methods: {  
164 - // 目前HX2.6.9 v-model双向绑定无效,故监听input事件获取输入框内容的变化  
165 - inputChange(e) {  
166 - this.keyword = e.detail.value;  
167 - },  
168 - // 清空输入  
169 - // 也可以作为用户通过this.$refs形式调用清空输入框内容  
170 - clear() {  
171 - this.keyword = '';  
172 - // 延后发出事件,避免在父组件监听clear事件时,value为更新前的值(不为空)  
173 - this.$nextTick(() => {  
174 - this.$emit('clear');  
175 - })  
176 - },  
177 - // 确定搜索  
178 - search(e) {  
179 - this.$emit('search', e.detail.value);  
180 - try {  
181 - // 收起键盘  
182 - uni.hideKeyboard();  
183 - } catch (e) {}  
184 - },  
185 - // 点击右边自定义按钮的事件  
186 - custom() {  
187 - this.$emit('custom', this.keyword);  
188 - try {  
189 - // 收起键盘  
190 - uni.hideKeyboard();  
191 - } catch (e) {}  
192 - },  
193 - // 获取焦点  
194 - getFocus() {  
195 - this.focused = true;  
196 - // 开启右侧搜索按钮展开的动画效果  
197 - if (this.animation && this.showAction) this.show = true;  
198 - this.$emit('focus', this.keyword);  
199 - },  
200 - // 失去焦点  
201 - blur() {  
202 - // 最开始使用的是监听图标@touchstart事件,自从hx2.8.4后,此方法在微信小程序出错  
203 - // 这里改为监听点击事件,手点击清除图标时,同时也发生了@blur事件,导致图标消失而无法点击,这里做一个延时  
204 - setTimeout(() => {  
205 - this.focused = false;  
206 - }, 100)  
207 - this.show = false;  
208 - this.$emit('blur', this.keyword);  
209 - },  
210 - // 点击搜索框,只有disabled=true时才发出事件,因为禁止了输入,意味着是想跳转真正的搜索页  
211 - clickHandler() {  
212 - if (this.disabled) this.$emit('click');  
213 - },  
214 - // 点击左边图标  
215 - clickIcon() {  
216 - this.$emit('clickIcon'); 112 + // #endif
  113 + // #ifdef VUE2
  114 + value: {
  115 + immediate: true,
  116 + handler(nVal) {
  117 + this.keyword = nVal;
217 } 118 }
  119 + },
  120 + // #endif
  121 + },
  122 + computed: {
  123 + showActionBtn() {
  124 + return !this.animation && this.showAction
  125 + }
  126 + },
  127 + emits: ['clear', 'search', 'custom', 'focus', 'blur', 'click', 'clickIcon', 'update:modelValue', 'change'],
  128 + methods: {
  129 + // 目前HX2.6.9 v-model双向绑定无效,故监听input事件获取输入框内容的变化
  130 + inputChange(e) {
  131 + this.keyword = e.detail.value;
  132 + },
  133 + // 清空输入
  134 + // 也可以作为用户通过this.$refs形式调用清空输入框内容
  135 + clear() {
  136 + this.keyword = '';
  137 + // 延后发出事件,避免在父组件监听clear事件时,value为更新前的值(不为空)
  138 + this.$nextTick(() => {
  139 + this.$emit('clear');
  140 + })
  141 + },
  142 + // 确定搜索
  143 + search(e) {
  144 + this.$emit('search', e.detail.value);
  145 + try {
  146 + // 收起键盘
  147 + uni.hideKeyboard();
  148 + } catch (e) { }
  149 + },
  150 + // 点击右边自定义按钮的事件
  151 + custom() {
  152 + this.$emit('custom', this.keyword);
  153 + try {
  154 + // 收起键盘
  155 + uni.hideKeyboard();
  156 + } catch (e) { }
  157 + },
  158 + // 获取焦点
  159 + getFocus() {
  160 + this.focused = true;
  161 + // 开启右侧搜索按钮展开的动画效果
  162 + if (this.animation && this.showAction) this.show = true;
  163 + this.$emit('focus', this.keyword);
  164 + },
  165 + // 失去焦点
  166 + blur() {
  167 + // 最开始使用的是监听图标@touchstart事件,自从hx2.8.4后,此方法在微信小程序出错
  168 + // 这里改为监听点击事件,手点击清除图标时,同时也发生了@blur事件,导致图标消失而无法点击,这里做一个延时
  169 + setTimeout(() => {
  170 + this.focused = false;
  171 + }, 100)
  172 + this.show = false;
  173 + this.$emit('blur', this.keyword);
  174 + },
  175 + // 点击搜索框,只有disabled=true时才发出事件,因为禁止了输入,意味着是想跳转真正的搜索页
  176 + clickHandler() {
  177 + if (this.disabled) this.$emit('click');
  178 + },
  179 + // 点击左边图标
  180 + clickIcon() {
  181 + this.$emit('clickIcon');
218 } 182 }
219 } 183 }
  184 +}
220 </script> 185 </script>
221 186
222 <style lang="scss" scoped> 187 <style lang="scss" scoped>
@@ -242,8 +207,9 @@ $u-search-action-margin-left: 5px !default; @@ -242,8 +207,9 @@ $u-search-action-margin-left: 5px !default;
242 /* #ifdef H5 */ 207 /* #ifdef H5 */
243 // iOS15在H5下,hx的某些版本,input type=search时,会多了一个搜索图标,进行移除 208 // iOS15在H5下,hx的某些版本,input type=search时,会多了一个搜索图标,进行移除
244 [type="search"]::-webkit-search-decoration { 209 [type="search"]::-webkit-search-decoration {
245 - display: none; 210 + display: none;
246 } 211 }
  212 +
247 /* #endif */ 213 /* #endif */
248 214
249 .u-search { 215 .u-search {
garbage-removal/src/uview-plus/components/u-textarea/u-textarea.vue
1 <template> 1 <template>
2 <view class="u-textarea" :class="textareaClass" :style="[textareaStyle]"> 2 <view class="u-textarea" :class="textareaClass" :style="[textareaStyle]">
3 - <textarea  
4 - class="u-textarea__field"  
5 - :value="innerValue"  
6 - :style="{ height: $u.addUnit(height) }"  
7 - :placeholder="placeholder"  
8 - :placeholder-style="$u.addStyle(placeholderStyle, 'string')"  
9 - :placeholder-class="placeholderClass"  
10 - :disabled="disabled"  
11 - :focus="focus"  
12 - :autoHeight="autoHeight"  
13 - :fixed="fixed"  
14 - :cursorSpacing="cursorSpacing"  
15 - :cursor="cursor"  
16 - :showConfirmBar="showConfirmBar"  
17 - :selectionStart="selectionStart"  
18 - :selectionEnd="selectionEnd"  
19 - :adjustPosition="adjustPosition"  
20 - :disableDefaultPadding="disableDefaultPadding"  
21 - :holdKeyboard="holdKeyboard"  
22 - :maxlength="maxlength"  
23 - :confirm-type="confirmType"  
24 - :ignoreCompositionEvent="ignoreCompositionEvent"  
25 - @focus="onFocus"  
26 - @blur="onBlur"  
27 - @linechange="onLinechange"  
28 - @input="onInput"  
29 - @confirm="onConfirm"  
30 - @keyboardheightchange="onKeyboardheightchange"  
31 - ></textarea>  
32 - <text  
33 - class="u-textarea__count"  
34 - :style="{  
35 - 'background-color': disabled ? 'transparent' : '#fff',  
36 - }"  
37 - v-if="count"  
38 - >{{ innerValue.length }}/{{ maxlength }}</text  
39 - > 3 + <textarea class="u-textarea__field" :value="innerValue" :style="{ height: $u.addUnit(height) }"
  4 + :placeholder="placeholder" :placeholder-style="$u.addStyle(placeholderStyle, 'string')"
  5 + :placeholder-class="placeholderClass" :disabled="disabled" :focus="focus" :autoHeight="autoHeight"
  6 + :fixed="fixed" :cursorSpacing="cursorSpacing" :cursor="cursor" :showConfirmBar="showConfirmBar"
  7 + :selectionStart="selectionStart" :selectionEnd="selectionEnd" :adjustPosition="adjustPosition"
  8 + :disableDefaultPadding="disableDefaultPadding" :holdKeyboard="holdKeyboard" :maxlength="maxlength"
  9 + :confirm-type="confirmType" :ignoreCompositionEvent="ignoreCompositionEvent" @focus="onFocus" @blur="onBlur"
  10 + @linechange="onLinechange" @input="onInput" @confirm="onConfirm"
  11 + @keyboardheightchange="onKeyboardheightchange"></textarea>
  12 + <text class="u-textarea__count" :style="{
  13 + 'background-color': disabled ? 'transparent' : '#fff',
  14 + }" v-if="count">{{ innerValue.length }}/{{ maxlength }}</text>
40 </view> 15 </view>
41 </template> 16 </template>
42 17
43 <script> 18 <script>
44 -import props from "./props.js";  
45 -import mpMixin from '../../libs/mixin/mpMixin.js';  
46 import mixin from '../../libs/mixin/mixin.js'; 19 import mixin from '../../libs/mixin/mixin.js';
  20 +import mpMixin from '../../libs/mixin/mpMixin.js';
  21 +import props from "./props.js";
47 /** 22 /**
48 * Textarea 文本域 23 * Textarea 文本域
49 * @description 文本域此组件满足了可能出现的表单信息补充,编辑等实际逻辑的功能,内置了字数校验等 24 * @description 文本域此组件满足了可能出现的表单信息补充,编辑等实际逻辑的功能,内置了字数校验等
@@ -84,64 +59,64 @@ import mixin from &#39;../../libs/mixin/mixin.js&#39;; @@ -84,64 +59,64 @@ import mixin from &#39;../../libs/mixin/mixin.js&#39;;
84 export default { 59 export default {
85 name: "u-textarea", 60 name: "u-textarea",
86 mixins: [mpMixin, mixin, props], 61 mixins: [mpMixin, mixin, props],
87 - data() {  
88 - return {  
89 - // 输入框的值  
90 - innerValue: "",  
91 - // 是否处于获得焦点状态  
92 - focused: false,  
93 - // value是否第一次变化,在watch中,由于加入immediate属性,会在第一次触发,此时不应该认为value发生了变化  
94 - firstChange: true,  
95 - // value绑定值的变化是由内部还是外部引起的  
96 - changeFromInner: false,  
97 - // 过滤处理方法  
98 - innerFormatter: value => value  
99 - }  
100 - },  
101 - created() {  
102 - },  
103 - watch: { 62 + data() {
  63 + return {
  64 + // 输入框的值
  65 + innerValue: "",
  66 + // 是否处于获得焦点状态
  67 + focused: false,
  68 + // value是否第一次变化,在watch中,由于加入immediate属性,会在第一次触发,此时不应该认为value发生了变化
  69 + firstChange: true,
  70 + // value绑定值的变化是由内部还是外部引起的
  71 + changeFromInner: false,
  72 + // 过滤处理方法
  73 + innerFormatter: value => value
  74 + }
  75 + },
  76 + created() {
  77 + },
  78 + watch: {
104 // #ifdef VUE2 79 // #ifdef VUE2
105 - value: {  
106 - immediate: true,  
107 - handler(newVal, oldVal) {  
108 - this.innerValue = newVal;  
109 - /* #ifdef H5 */  
110 - // 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法  
111 - if (  
112 - this.firstChange === false &&  
113 - this.changeFromInner === false  
114 - ) {  
115 - this.valueChange();  
116 - }  
117 - /* #endif */  
118 - this.firstChange = false;  
119 - // 重置changeFromInner的值为false,标识下一次引起默认为外部引起的  
120 - this.changeFromInner = false;  
121 - },  
122 - }, 80 + value: {
  81 + immediate: true,
  82 + handler(newVal, oldVal) {
  83 + this.innerValue = newVal;
  84 + /* #ifdef H5 */
  85 + // 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法
  86 + if (
  87 + this.firstChange === false &&
  88 + this.changeFromInner === false
  89 + ) {
  90 + this.valueChange();
  91 + }
  92 + /* #endif */
  93 + this.firstChange = false;
  94 + // 重置changeFromInner的值为false,标识下一次引起默认为外部引起的
  95 + this.changeFromInner = false;
  96 + },
  97 + },
123 // #endif 98 // #endif
124 // #ifdef VUE3 99 // #ifdef VUE3
125 modelValue: { 100 modelValue: {
126 - immediate: true,  
127 - handler(newVal, oldVal) {  
128 - this.innerValue = newVal;  
129 - /* #ifdef H5 */  
130 - // 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法  
131 - if (  
132 - this.firstChange === false &&  
133 - this.changeFromInner === false  
134 - ) {  
135 - this.valueChange();  
136 - }  
137 - /* #endif */  
138 - this.firstChange = false;  
139 - // 重置changeFromInner的值为false,标识下一次引起默认为外部引起的  
140 - this.changeFromInner = false;  
141 - },  
142 - } 101 + immediate: true,
  102 + handler(newVal, oldVal) {
  103 + this.innerValue = newVal;
  104 + /* #ifdef H5 */
  105 + // 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法
  106 + if (
  107 + this.firstChange === false &&
  108 + this.changeFromInner === false
  109 + ) {
  110 + this.valueChange();
  111 + }
  112 + /* #endif */
  113 + this.firstChange = false;
  114 + // 重置changeFromInner的值为false,标识下一次引起默认为外部引起的
  115 + this.changeFromInner = false;
  116 + },
  117 + }
143 // #endif 118 // #endif
144 - }, 119 + },
145 computed: { 120 computed: {
146 // 组件的类名 121 // 组件的类名
147 textareaClass() { 122 textareaClass() {
@@ -176,10 +151,10 @@ export default { @@ -176,10 +151,10 @@ export default {
176 emits: ['update:modelValue', 'linechange', 'focus', 'blur', 'change', 'confirm', 'keyboardheightchange'], 151 emits: ['update:modelValue', 'linechange', 'focus', 'blur', 'change', 'confirm', 'keyboardheightchange'],
177 // #endif 152 // #endif
178 methods: { 153 methods: {
179 - // 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用  
180 - setFormatter(e) {  
181 - this.innerFormatter = e  
182 - }, 154 + // 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
  155 + setFormatter(e) {
  156 + this.innerFormatter = e
  157 + },
183 onFocus(e) { 158 onFocus(e) {
184 this.$emit("focus", e); 159 this.$emit("focus", e);
185 }, 160 },
@@ -192,34 +167,34 @@ export default { @@ -192,34 +167,34 @@ export default {
192 this.$emit("linechange", e); 167 this.$emit("linechange", e);
193 }, 168 },
194 onInput(e) { 169 onInput(e) {
195 - let { value = "" } = e.detail || {};  
196 - // 格式化过滤方法  
197 - const formatter = this.formatter || this.innerFormatter  
198 - const formatValue = formatter(value)  
199 - // 为了避免props的单向数据流特性,需要先将innerValue值设置为当前值,再在$nextTick中重新赋予设置后的值才有效  
200 - this.innerValue = value  
201 - this.$nextTick(() => {  
202 - this.innerValue = formatValue;  
203 - this.valueChange();  
204 - }) 170 + let { value = "" } = e.detail || {};
  171 + // 格式化过滤方法
  172 + const formatter = this.formatter || this.innerFormatter
  173 + const formatValue = formatter(value)
  174 + // 为了避免props的单向数据流特性,需要先将innerValue值设置为当前值,再在$nextTick中重新赋予设置后的值才有效
  175 + this.innerValue = value
  176 + this.$nextTick(() => {
  177 + this.innerValue = formatValue;
  178 + this.valueChange();
  179 + })
205 }, 180 },
206 - // 内容发生变化,进行处理  
207 - valueChange() {  
208 - const value = this.innerValue;  
209 - this.$nextTick(() => { 181 + // 内容发生变化,进行处理
  182 + valueChange() {
  183 + const value = this.innerValue;
  184 + this.$nextTick(() => {
210 // #ifdef VUE3 185 // #ifdef VUE3
211 this.$emit("update:modelValue", value); 186 this.$emit("update:modelValue", value);
212 // #endif 187 // #endif
213 // #ifdef VUE2 188 // #ifdef VUE2
214 this.$emit("input", value); 189 this.$emit("input", value);
215 // #endif 190 // #endif
216 - // 标识value值的变化是由内部引起的  
217 - this.changeFromInner = true;  
218 - this.$emit("change", value);  
219 - // 尝试调用u-form的验证方法  
220 - uni.$u.formValidate(this, "change");  
221 - });  
222 - }, 191 + // 标识value值的变化是由内部引起的
  192 + this.changeFromInner = true;
  193 + this.$emit("change", value);
  194 + // 尝试调用u-form的验证方法
  195 + uni.$u.formValidate(this, "change");
  196 + });
  197 + },
223 onConfirm(e) { 198 onConfirm(e) {
224 this.$emit("confirm", e); 199 this.$emit("confirm", e);
225 }, 200 },
@@ -239,7 +214,7 @@ export default { @@ -239,7 +214,7 @@ export default {
239 position: relative; 214 position: relative;
240 @include flex; 215 @include flex;
241 flex: 1; 216 flex: 1;
242 - padding: 9px; 217 + padding: 9px;
243 218
244 &--radius { 219 &--radius {
245 border-radius: 4px; 220 border-radius: 4px;
@@ -257,7 +232,7 @@ export default { @@ -257,7 +232,7 @@ export default {
257 flex: 1; 232 flex: 1;
258 font-size: 15px; 233 font-size: 15px;
259 color: $u-content-color; 234 color: $u-content-color;
260 - width: 100%; 235 + width: 100%;
261 } 236 }
262 237
263 &__count { 238 &__count {
garbage-removal/src/uview-plus/components/u-upload/u-upload.vue
@@ -5,14 +5,14 @@ @@ -5,14 +5,14 @@
5 <view class="u-upload__wrap__preview" v-for="(item, index) in lists" :key="index"> 5 <view class="u-upload__wrap__preview" v-for="(item, index) in lists" :key="index">
6 <image v-if="item.isImage || (item.type && item.type === 'image')" :src="item.thumb || item.url" 6 <image v-if="item.isImage || (item.type && item.type === 'image')" :src="item.thumb || item.url"
7 :mode="imageMode" class="u-upload__wrap__preview__image" @tap="onPreviewImage(item)" :style="[{ 7 :mode="imageMode" class="u-upload__wrap__preview__image" @tap="onPreviewImage(item)" :style="[{
8 - width: $u.addUnit(width),  
9 - height: $u.addUnit(height)  
10 - }]" /> 8 + // width: $u.addUnit(width),
  9 + // height: $u.addUnit(height)
  10 + }]" />
11 <view v-else class="u-upload__wrap__preview__other"> 11 <view v-else class="u-upload__wrap__preview__other">
12 <u-icon color="#80CBF9" size="26" 12 <u-icon color="#80CBF9" size="26"
13 :name="item.isVideo || (item.type && item.type === 'video') ? 'movie' : 'folder'"></u-icon> 13 :name="item.isVideo || (item.type && item.type === 'video') ? 'movie' : 'folder'"></u-icon>
14 <text class="u-upload__wrap__preview__other__text">{{ item.isVideo || (item.type && item.type === 'video') ? 14 <text class="u-upload__wrap__preview__other__text">{{ item.isVideo || (item.type && item.type === 'video') ?
15 - '视频' : '文件' }}</text> 15 + '视频' : '文件' }}</text>
16 </view> 16 </view>
17 <view class="u-upload__status" v-if="item.status === 'uploading' || item.status === 'failed'"> 17 <view class="u-upload__status" v-if="item.status === 'uploading' || item.status === 'failed'">
18 <view class="u-upload__status__icon"> 18 <view class="u-upload__status__icon">
@@ -48,9 +48,9 @@ @@ -48,9 +48,9 @@
48 </view> 48 </view>
49 <view v-else class="u-upload__button" :hover-class="!disabled ? 'u-upload__button--hover' : ''" 49 <view v-else class="u-upload__button" :hover-class="!disabled ? 'u-upload__button--hover' : ''"
50 hover-stay-time="150" @tap="chooseFile" :class="[disabled && 'u-upload__button--disabled']" :style="[{ 50 hover-stay-time="150" @tap="chooseFile" :class="[disabled && 'u-upload__button--disabled']" :style="[{
51 - width: $u.addUnit(width),  
52 - height: $u.addUnit(height)  
53 - }]"> 51 + // width: $u.addUnit(width),
  52 + // height: $u.addUnit(height)
  53 + }]">
54 <u-icon :name="uploadIcon" size="26" :color="uploadIconColor"></u-icon> 54 <u-icon :name="uploadIcon" size="26" :color="uploadIconColor"></u-icon>
55 <text v-if="uploadText" class="u-upload__button__text">{{ uploadText }}</text> 55 <text v-if="uploadText" class="u-upload__button__text">{{ uploadText }}</text>
56 </view> 56 </view>
@@ -251,7 +251,7 @@ export default { @@ -251,7 +251,7 @@ export default {
251 // 预览图片 251 // 预览图片
252 onPreviewImage(item) { 252 onPreviewImage(item) {
253 if (!item.isImage || !this.previewFullImage) return 253 if (!item.isImage || !this.previewFullImage) return
254 - let baseUrl = import.meta.env.VITE_BASE_URL; 254 + let baseUrl = item.url.startsWith('/profile/upload/') ? import.meta.env.VITE_BASE_URL : item.url;
255 let imageArray = this.lists.filter((item) => this.accept === 'image' || uni.$u.test.image(item.url || item.thumb)).map((item) => item.url || item.thumb); 255 let imageArray = this.lists.filter((item) => this.accept === 'image' || uni.$u.test.image(item.url || item.thumb)).map((item) => item.url || item.thumb);
256 for (let index = 0; index < imageArray.length; index++) { 256 for (let index = 0; index < imageArray.length; index++) {
257 if (!imageArray[index].startsWith(baseUrl)) { 257 if (!imageArray[index].startsWith(baseUrl)) {
garbage-removal/vite.config.js
@@ -12,5 +12,8 @@ export default defineConfig({ @@ -12,5 +12,8 @@ export default defineConfig({
12 "@": resolve(__dirname, "src"), // 设置@指向src 12 "@": resolve(__dirname, "src"), // 设置@指向src
13 "@components": resolve(__dirname, "src/components"), // 设置@components指向src/components 13 "@components": resolve(__dirname, "src/components"), // 设置@components指向src/components
14 }, 14 },
15 - } 15 + },
  16 + server: {
  17 + port: 9000
  18 + }
16 }) 19 })
garbage-removal/yarn.lock
@@ -4368,6 +4368,11 @@ jpeg-js@^0.3.4: @@ -4368,6 +4368,11 @@ jpeg-js@^0.3.4:
4368 resolved "https://registry.npmmirror.com/jpeg-js/-/jpeg-js-0.3.7.tgz" 4368 resolved "https://registry.npmmirror.com/jpeg-js/-/jpeg-js-0.3.7.tgz"
4369 integrity sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ== 4369 integrity sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==
4370 4370
  4371 +js-md5@^0.8.3:
  4372 + version "0.8.3"
  4373 + resolved "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz"
  4374 + integrity sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==
  4375 +
4371 js-tokens@^4.0.0: 4376 js-tokens@^4.0.0:
4372 version "4.0.0" 4377 version "4.0.0"
4373 resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz" 4378 resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz"