Commit 38584a8dede525a86b0322dada87c216a7b0a9ff

Authored by guzijian
1 parent 6107e055

feat: 新增角色

Showing 35 changed files with 2402 additions and 937 deletions
garbage-removal/.env.production
1 1 VITE_BASE_URL=http://61.169.120.202:10001/workflow
  2 +# VITE_BASE_URL=http://175.6.47.84:10001/workflow
2 3 # VITE_BASE_FILE_UPLOAD_PREFIX=/common/upload
3 4 # VITE_STOMP_URL=http://localhost:8860/ws
... ...
garbage-removal/package-lock.json
... ... @@ -24,6 +24,7 @@
24 24 "@dcloudio/uni-quickapp-webview": "3.0.0-3090620231104002",
25 25 "clipboard": "^2.0.11",
26 26 "dayjs": "^1.11.10",
  27 + "js-md5": "^0.8.3",
27 28 "pinia": "2.0.33",
28 29 "pinia-plugin-persist-uni": "^1.2.0",
29 30 "sass": "1.58.3",
... ... @@ -8603,6 +8604,11 @@
8603 8604 "integrity": "sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==",
8604 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 8612 "node_modules/js-tokens": {
8607 8613 "version": "4.0.0",
8608 8614 "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
... ...
garbage-removal/package.json
... ... @@ -56,6 +56,7 @@
56 56 "@dcloudio/uni-quickapp-webview": "3.0.0-3090620231104002",
57 57 "clipboard": "^2.0.11",
58 58 "dayjs": "^1.11.10",
  59 + "js-md5": "^0.8.3",
59 60 "pinia": "2.0.33",
60 61 "pinia-plugin-persist-uni": "^1.2.0",
61 62 "sass": "1.58.3",
... ...
garbage-removal/src/apis/address.js
... ... @@ -2,7 +2,7 @@ import { request } from "@/utils/request";
2 2 /**
3 3 * @method 新增用户地址
4 4 */
5   -export async function addAddress( params, config) {
  5 +export async function addAddress(params, config) {
6 6 return await request.post(
7 7 `/user/save/address`,
8 8 params,
... ... @@ -12,7 +12,7 @@ export async function addAddress( params, config) {
12 12 /**
13 13 * @method 获取用户地址
14 14 */
15   -export async function queryAddress( type) {
  15 +export async function queryAddress(type) {
16 16 return await request.get(
17 17 `/user/query/address/${type}`
18 18 );
... ... @@ -20,8 +20,8 @@ export async function queryAddress( type) {
20 20 /**
21 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 25 `/user/update/address`,
26 26 params,
27 27 config
... ... @@ -30,8 +30,8 @@ export async function updateAddress( params,config) {
30 30 /**
31 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 35 `/user/delete/address/${id}`
36 36 );
37 37 }
... ...
garbage-removal/src/main.js
1 1 import uviewPlus from '@/uview-plus';
  2 +import md5 from 'js-md5';
2 3 import * as Pinia from 'pinia';
3 4 import piniaPersistUni from "pinia-plugin-persist-uni";
4 5 import { createSSRApp } from "vue";
5 6 import mixin from './common/mixin';
  7 +
6 8 // 引入uView对小程序分享的mixin封装
7 9 import mpShare from '@/uview-plus/libs/mixin/mpShare.js';
8 10 import App from "./App.vue";
... ... @@ -47,7 +49,7 @@ export function createApp() {
47 49 const app = createSSRApp(App);
48 50 const pinia = Pinia.createPinia()
49 51 app.use(uviewPlus)
50   -
  52 + // 配置uView
51 53 // 调用setConfig方法,方法内部会进行对象属性深度合并,可以放心嵌套配置
52 54 // 需要在app.use(uview-plus)之后执行
53 55 uni.$u.setConfig({
... ... @@ -64,6 +66,7 @@ export function createApp() {
64 66 }
65 67 }
66 68 })
  69 + uni.$u.md5 = md5
67 70 pinia.use(piniaPersistUni);
68 71 app.use(pinia);
69 72 app.mixin(mpShare);
... ...
garbage-removal/src/manifest.json
... ... @@ -51,7 +51,14 @@
51 51 /* 小程序特有相关 */
52 52 "mp-weixin" : {
53 53 "lazyCodeLoading" : "requiredComponents",
  54 + "requiredPrivateInfos": ["getLocation", "chooseLocation"],
54 55 "appid" : "wxc3f60667dc9d6cea",
  56 + "permission":{
  57 + "scope.userLocation":{
  58 + "desc":"你的位置信息将用于小程序位置接口的"
  59 + }
  60 + },
  61 + "libVersion": "latest",
55 62 "setting" : {
56 63 "urlCheck" : false
57 64 },
... ...
garbage-removal/src/pages.json
... ... @@ -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 36 "path": "pages/login/index",
30 37 "style": {
31 38 "navigationBarTitleText": "装饰装修垃圾智慧功能模块登录",
... ... @@ -38,12 +45,6 @@
38 45 "enablePullDownRefresh": false
39 46 }
40 47 },{
41   - "path": "pages/wode/choose/index",
42   - "style": {
43   - "navigationBarTitleText": "选择身份",
44   - "enablePullDownRefresh": false
45   - }
46   - },{
47 48 "path": "pages/order/detail/index",
48 49 "style": {
49 50 "navigationBarTitleText": "派单详情",
... ... @@ -123,6 +124,13 @@
123 124 "navigationBarBackgroundColor":"#53c21d",
124 125 "enablePullDownRefresh": false
125 126 }
  127 + },
  128 + {
  129 + "path": "pages/home/search/index",
  130 + "style": {
  131 + "navigationBarTitleText": "公司搜索",
  132 + "enablePullDownRefresh": false
  133 + }
126 134 },{
127 135 "path": "pages/order/index",
128 136 "style": {
... ...
garbage-removal/src/pages/home/address/addSite.vue
... ... @@ -2,29 +2,30 @@
2 2 <view class="wrap">
3 3 <view class="wrap-from-container">
4 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 6 ref="addressFrom">
7 7 <u-form-item :required="true" label="所在地区" prop="addressArea" borderBottom>
8 8 <view @click.stop="showRegionPicker" hover-class="click-box" style="width: 100%;">
9 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 11 </view>
12 12 </u-form-item>
13 13 <u-form-item :required="true" label="详细地址" prop="addressDetail" borderBottom>
14 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 20 </view>
20 21 </u-form-item>
21 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 25 </u-form-item>
25 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 29 </u-form-item>
29 30 </u--form>
30 31 </view>
... ... @@ -103,7 +104,6 @@ const showRegionPicker = () =&gt; {
103 104 }
104 105  
105 106 const handleCityChange = (e) => {
106   - console.log(e);
107 107 addressInfo.addressArea = e.province.label + '-' + e.city.label + '-' + e.area.label;
108 108 }
109 109  
... ... @@ -165,6 +165,7 @@ const submit = () =&gt; {
165 165 * 打开地图选择地址
166 166 */
167 167 const chooseAddressDetail = () => {
  168 + console.log('打开地图选择地址');
168 169 let coordinate = 'gcj02';
169 170 uni.chooseLocation({
170 171 type: coordinate,
... ... @@ -174,7 +175,28 @@ const chooseAddressDetail = () =&gt; {
174 175 addressInfo.garLongitude = res.longitude
175 176 addressInfo.garLatitude = res.latitude
176 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 233 </script>
212 234  
213 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 242 .wrap {
... ...
garbage-removal/src/pages/home/address/index.vue
... ... @@ -58,7 +58,10 @@ const handleClickChangeCurrentAddress = (res) =&gt; {
58 58 contactIphoneNumber: res.garUserContactTel,
59 59 defaultFlag: true,
60 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 65 }).then(res => {
63 66 getData();
64 67 uni.$u.toast(res.data.msg)
... ...
garbage-removal/src/pages/home/clean/company-detail/index.vue
... ... @@ -11,7 +11,12 @@
11 11 {{ headerData.name }}
12 12 </view>
13 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 20 </view>
16 21 </view>
17 22 </view>
... ... @@ -27,7 +32,7 @@
27 32 <view v-if="item.label != '道路运输许可证'" class="company-content-base-data-info-item-txt">
28 33 {{ item.value }}
29 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 36 <u-upload :fileList="[item.value]" name="3" multiple :maxCount="10" :previewFullImage="true"
32 37 :isReadOnly="true"></u-upload>
33 38 </view>
... ... @@ -139,6 +144,25 @@ const handleCleanGarbage = (companyObj, tel, userAddress) =&gt; {
139 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 167 const initData = (baseData) => {
144 168 baseDataList.value[0].value = baseData.legalRepresentative
... ... @@ -221,6 +245,21 @@ $custom-bottom-height: 200rpx;
221 245 .company-content-right-area {
222 246 font-size: 25rpx;
223 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 60 <view class="company-clean-container-car-main">
61 61 <view class="company-clean-container-car-main-content">
62 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 69 <u--input color="#909399" border="none" style="pointer-events:none" :modelValue="paramFrom.carType"
69 70 type="text" placeholder-class="line" readonly />
70 71 </view>
71 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 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 98 <view hover-class="hoverClickStyle" @click.stop="handleGarbageTypeClick(true)">
76 99 <u--input color="#909399" border="none" style="pointer-events:none" :modelValue="paramFrom.garbageType"
77 100 type="text" placeholder-class="line" readonly />
... ... @@ -83,16 +106,6 @@
83 106 <view class="company-clean-container-car-main-content-remark">
84 107 {{ garCarTransportInfo }}
85 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 109 <view class="company-clean-container-car-main-content-prompt">
97 110 温馨提示:垃圾类型不符合,企业有权拒绝清运。
98 111 </view>
... ... @@ -100,26 +113,46 @@
100 113 </view>
101 114 <view class="company-clean-container-site-image-info">
102 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 117 </view>
105 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 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 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 142 </view>
115 143 </view>
116 144 <view class="company-clean-container-site-image-info-sure-button">
117 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 156 </view>
124 157 </view>
125 158 </view>
... ... @@ -141,7 +174,7 @@
141 174 </view>
142 175 </view>
143 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 178 </view>
146 179 </view>
147 180 </view>
... ... @@ -153,16 +186,17 @@ import { queryCarList } from &#39;@/apis/carinfo.js&#39;;
153 186 import { uploadFilePromise } from '@/apis/common.js';
154 187 import { saveOrder } from '@/apis/order.js';
155 188 import liuDeliveryTime from "@/components/liu-delivery-time/liu-delivery-time.vue";
  189 +import garbageUrl from '@/static/image/garbage.png';
156 190 import { useMainStore } from '@/stores/index.js';
157 191 import { onLoad } from '@dcloudio/uni-app';
158 192 import { computed, getCurrentInstance, nextTick, ref, watch } from 'vue';
159 193 const { proxy } = getCurrentInstance();
160   -
161 194 const store = useMainStore();
162 195 const userType = computed(() => store.userType)
163 196 const x = ref(5)
164 197 const y = ref()
165 198 const movableAreaElement = ref()
  199 +const deletable = ref(false)
166 200 const companyObj = ref()
167 201 const tel = ref()
168 202 const carTypeShowFlag = ref(false)
... ... @@ -223,12 +257,19 @@ const paramFrom = ref({
223 257 remark: "",
224 258 sureReadFlag: [],
225 259 carType: "",
226   - garbageType: "装修垃圾"
  260 + garbageType: ["装修垃圾"],
  261 + garInCarStore: false
  262 +
227 263 })
228 264 const dayTime = ref()
229 265  
230 266 const chooseTime = ref()
231   -const fileList = ref([])
  267 +const fileList = ref([
  268 + {
  269 + url: garbageUrl,
  270 + label: '预览'
  271 + }
  272 +])
232 273 const candidates = ref([])
233 274 const handleTimeChoose = () => {
234 275 chooseTime.value.open();
... ... @@ -239,6 +280,7 @@ const changeTime = (e) =&gt; {
239 280 }
240 281 const changeAgree = (e) => {
241 282 // paramFrom.value.sureReadFlag = e
  283 + paramFrom.value.sureReadFlag[0] = !paramFrom.value.sureReadFlag[0]
242 284 }
243 285 const onChange = (e) => {
244 286 // console.log(e);
... ... @@ -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 326 const handleCarInfoClick = (val) => {
282 327 carTypeShowFlag.value = val
... ... @@ -321,6 +366,10 @@ const afterRead = async (event) =&gt; {
321 366 });
322 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 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 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 450 garLongitude: userAddress.value.garLongitude,
402 451 garLatitude: userAddress.value.garLatitude,
403 452 garCoordinate: userAddress.value.garCoordinate,
  453 + garInCarStore: paramFrom.value.garInCarStore
404 454 }
405 455 if (!validateParams(params)) {
406 456 return;
... ... @@ -410,7 +460,7 @@ const handleOderSure = () =&gt; {
410 460 // TODO 派单详情
411 461 if (res.data.success) {
412 462 if (userType.value === "运输驾驶员") {
413   - uni.$u.toast("派单成功,请切换成且角色查看单详情")
  463 + uni.$u.toast("派单成功,请切换成且角色查看单详情")
414 464 setTimeout(() => {
415 465 uni.$u.route({
416 466 type: 'navigateBack',
... ... @@ -438,11 +488,16 @@ const handleOderSure = () =&gt; {
438 488 * @param {Object} params
439 489 */
440 490 const validateParams = (params) => {
  491 +
441 492 if (!paramFrom.value.sureReadFlag[0]) {
442 493 jumpPrompt('请勾选"本人已确认信息真实有效,并将上诉信息告知市容环境卫生主管部门"')
443 494 return false;
444 495 }
445 496 for (const key in params) {
  497 + // 跳过garInCarStore
  498 + if (key == "garInCarStore") {
  499 + continue;
  500 + }
446 501 if (!params[key] && key != "garRemark") {
447 502 switch (key) {
448 503 case "garOrderAgreementTime":
... ... @@ -683,7 +738,7 @@ $custom-bottom-height: 200rpx;
683 738 margin-bottom: $custom-marin-bottom;
684 739  
685 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 758 .company-clean-container-site-image-info-sure-button-radio {
704 759 padding: $custom-page-padding;
705 760 box-sizing: border-box;
706   - // display: flex;
  761 + display: flex;
707 762 // flex-flow: row wrap;
  763 + font-size: 25rpx;
708 764 color: $u-info;
709 765 }
710 766 }
... ... @@ -820,4 +876,12 @@ $custom-bottom-height: 200rpx;
820 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 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 18 <!-- 公司容器 -->
19 19 <view class="company-box">
20 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 22 <view class="info-box-item-icon" :class="item.icon">
23 23 </view>
24 24 <view class="info-box-item-text">{{ item.text }}</view>
25 25 </view>
26 26 </view>
27 27 <view class="company-container">
28   - <span class="company-label-info">可进行垃圾清运单位</span>
29 28 <view class="company-list-box" v-if="addressInfo">
30 29 <view class="company-list-header">
31 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 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 45 </view>
38 46 </view>
39 47 <view class="company-list-content">
40 48 <view class="company-list-content-box">
41 49 <z-paging ref="paging" :fixed="false" v-model="companyList" @query="queryList">
42 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 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 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 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 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 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 108 </view>
72 109 </view>
73   - <view class="company-list-item-main-right-remark">
  110 + <!-- <view class="company-list-item-main-right-remark">
74 111 {{ item.remark }}
75   - </view>
  112 + </view> -->
76 113 </view>
77 114 </view>
78 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 116 </view>
88 117 </view>
89 118 </z-paging>
... ... @@ -108,7 +137,7 @@
108 137 </view>
109 138 </template>
110 139  
111   -<script setup >
  140 +<script setup>
112 141 import { queryAddress } from '@/apis/address.js';
113 142 import { queryEnterpriseList } from '@/apis/company.js';
114 143 import { onLoad, onShow } from '@dcloudio/uni-app';
... ... @@ -121,13 +150,72 @@ const topMargin = ref(null);//状态栏高度
121 150 const musicheadHeight = ref();
122 151 const paging = ref(null)
123 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 158 const userAddress = ref({})
130 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 221 const infoBoxList = ref([{
... ... @@ -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 285 function handleAddressInfo() {
... ... @@ -202,9 +323,7 @@ const handleCleanClick = () =&gt; {
202 323 }
203 324 }
204 325 });
205   -
206 326 }
207   -
208 327 return
209 328  
210 329 }
... ... @@ -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 402 })
282 403 }
283 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 415 paging.value.complete(res.data.data.list);
287 416 })
288 417 }
... ... @@ -310,13 +439,19 @@ const queryList = (pageNo, pageSize) =&gt; {
310 439  
311 440 ::v-deep .u-swiper {
312 441 height: 400rpx !important;
  442 + background-size: 100% 100% !important;
313 443  
314 444 .u-swiper__wrapper {
315 445 height: 400rpx !important;
  446 + background-size: 100% 100% !important;
316 447 }
317 448  
318 449 .u-swiper__wrapper__item__wrapper__image {
319 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 491 z-index: 200;
357 492 box-sizing: border-box;
358 493 padding: 30rpx;
359   - margin-top: 330rpx;
  494 + margin-top: 300rpx;
360 495 flex: 1;
361 496 display: flex;
362 497 flex-direction: column;
... ... @@ -460,16 +595,16 @@ const queryList = (pageNo, pageSize) =&gt; {
460 595 flex: 1;
461 596 display: flex;
462 597 flex-direction: column;
  598 + box-sizing: border-box;
463 599  
464 600 .company-list-header {
465   - display: flex;
466 601 font-size: small;
467 602 font-weight: small;
468 603 align-items: center;
469 604  
470 605 .company-list-header-left {
471   - width: 200rpx;
472 606 text-align: center;
  607 + margin-bottom: 15rpx;
473 608 }
474 609  
475 610 .company-list-header-right {
... ... @@ -520,14 +655,49 @@ const queryList = (pageNo, pageSize) =&gt; {
520 655 font-size: 25rpx;
521 656  
522 657 .company-list-item-main-right-name {
523   - font-weight: bold;
  658 + // font-weight: bold;
524 659 color: $u-main-color;
525 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 697 .company-list-item-main-right-score {
529 698 display: flex;
530 699 font-size: small;
  700 + font-size: 24rpx;
531 701  
532 702 .company-list-item-main-right-text {
533 703 text-align: center;
... ... @@ -571,7 +741,9 @@ const queryList = (pageNo, pageSize) =&gt; {
571 741 .company-list-item-bottom {
572 742 display: flex;
573 743 justify-content: space-around;
574   - margin-top: 20rpx;
  744 + font-size: 25rpx;
  745 + color: #909399;
  746 + margin-bottom: 50rpx;
575 747  
576 748 .company-list-item-bottom-contact-company {
577 749 flex: 1;
... ... @@ -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 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 74 if (res.data.success) {
75 75 verifyFlag.value = false;
76 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 80 } else {
79 81 verifyFlag.value = true;
80 82 }
... ...
garbage-removal/src/pages/login/index.vue
... ... @@ -21,11 +21,14 @@
21 21 </view>
22 22 </view> -->
23 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 32 <view class="prompt-txt">
30 33 登录代表同意
31 34 <text class="link" @click="handleUserAgreement">用户协议、隐私政策,</text>
... ... @@ -41,7 +44,7 @@ import { userLogin } from &quot;@/apis/user.js&quot;;
41 44 export default {
42 45 data() {
43 46 return {
44   - tel: '18977778888',
  47 + tel: '13222222222',
45 48 agree: []
46 49 }
47 50 },
... ... @@ -92,8 +95,8 @@ export default {
92 95 handleUserAgreement() {
93 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 101 handleWeixinLogin(wxInfo) {
99 102 uni.login({
... ... @@ -190,7 +193,7 @@ export default {
190 193  
191 194 .hint {
192 195 padding: 20rpx 40rpx;
193   - font-size: 20rpx;
  196 + font-size: 25rpx;
194 197 color: $u-tips-color;
195 198 display: flex;
196 199 justify-content: flex-start;
... ...
garbage-removal/src/pages/order/detail/index.vue
... ... @@ -33,7 +33,7 @@
33 33 @click.stop="handlerJumpOtherApp(dataGram.garLatitude, dataGram.garLongitude, dataGram.garCoordinate)">
34 34 <text class="order-detail-container-header-title">派单地点:</text>
35 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 37 </view>
38 38 </view>
39 39 <view class="order-detail-container-header-item">
... ... @@ -58,7 +58,7 @@
58 58 <view class="order-detail-container-header-item">
59 59 <text class="order-detail-container-header-title">派单号:</text>
60 60 <view class="order-detail-container-header-content">
61   - {{ orderId }}
  61 + <text selectable="true">{{ orderId }}</text>
62 62 </view>
63 63 <!-- 生成二维码 -->
64 64 <view class="order-detail-container-header-qrCode" style="display: flex; align-items: center;">
... ... @@ -104,7 +104,7 @@
104 104 <view class="order-detail-container-header-item">
105 105 <text class="order-detail-container-header-title">联系电话:</text>
106 106 <view class="order-detail-container-header-content">
107   - {{ dataGram.garOrderContactTel }}
  107 + <text selectable="true">{{ dataGram.garOrderContactTel }}</text>
108 108 <view class="icon-box" style="display: flex; align-items: center; justify-content: center;">
109 109 <u-icon v-if="dataGram.handleFlag" name="phone" size="28"
110 110 @click="handleContactClick(dataGram.garOrderContactTel)"></u-icon>
... ... @@ -170,50 +170,50 @@
170 170 <view class="order-detail-bottom-box">
171 171 <view class=" order-detail-bottom-left">
172 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 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 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 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 180 :text="dataGram.garOrderMatchFlag === 0 ? '派单下发' : '继续下发'"></u-button>
181 181 </view>
182 182 <view class="order-detail-bottom-right">
183 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 185 <u-button @click="driverHandleOrder(orderId)"
186 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 188 <u-button @click="handleOrder(orderId)"
189 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 191 <u-button @click="handleUploadImage(orderId, 'putOnImages')"
192 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 194 <!-- <u-button @click="handleUploadImage(orderId, 'putOnImages')"
195 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 197 <u-button @click="handleUploadImage(orderId, 'putDownImages')"
198 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 200 <!-- <u-button @click="handleUploadImage(orderId, 'putDownImages')"
201 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 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 205 text="去评价"></u-button>
206 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 208 text="去评价"></u-button>
209 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 211 text="查看评价"></u-button>
212 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 214 text="查看评价"></u-button>
215 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 217 </view>
218 218 </view>
219 219 </view>
... ... @@ -253,30 +253,39 @@ const cancelShow = ref(false)
253 253 const currentCancelName = ref("")
254 254 const qrCodeRef = ref()
255 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 287 const createQrCodeLocal = (orderId) => {
279   - // 获取本地地址拼接单id
  288 + // 获取本地地址拼接单id
280 289 showUQRcode.value = true;
281 290 const hostname = window.location.hostname;
282 291 const port = window.location.port;
... ... @@ -362,7 +371,6 @@ const handleContactClick = (val) =&gt; {
362 371 }
363 372  
364 373 const handlerJumpOtherApp = (latitude, longitude, garCoordinate) => {
365   - console.log(latitude, longitude);
366 374 // 给出提示确定要跳转吗
367 375 uni.showModal({
368 376 title: '提示',
... ...
garbage-removal/src/pages/order/upload/index.vue
... ... @@ -20,7 +20,7 @@
20 20 <view class="upload-image-box-submit-box">
21 21 <view class="upload-image-box-submit-box-button" @click="handleSubmit(orderId, putType)">
22 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 24 </view>
25 25 </view>
26 26 </view>
... ...
garbage-removal/src/pages/wode/choose/index.vue
1 1 <template>
2 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 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 31 </view>
31 32 </view>
32 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 38 </view>
36 39 </view>
  40 +
  41 +
37 42 </template>
38 43  
39 44 <script setup>
... ... @@ -42,25 +47,72 @@ import { useMainStore } from &#39;@/stores/index.js&#39;;
42 47 import { setRequestToken } from '@/utils/request/request.js';
43 48 import { onLoad } from "@dcloudio/uni-app";
44 49 import { ref } from 'vue';
  50 +const userType = ref('')
  51 +const imageBase = "data:image/jpeg;base64,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";
45 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 108 const submit = (userType) => {
56 109 setRequestToken(store.tempToken)
57 110 updateUserInfo({ garUserType: userType }).then(res => {
58   - store.token = store.tempToken
59   - store.tempToken = "";
60 111 if (res.data.success) {
  112 + store.token = store.tempToken
  113 + store.tempToken = "";
61 114 store.userType = userType;
62   - unitInfo.value.userType = userType
63   - store.userInfo = unitInfo.value
  115 + store.userInfo = unitInfo.value[userType]
64 116 uni.$u.route({
65 117 type: "switchTab",
66 118 url: `pages/home/index`,
... ... @@ -70,10 +122,29 @@ const submit = (userType) =&gt; {
70 122  
71 123 }
72 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 149 </script>
79 150  
... ... @@ -82,50 +153,177 @@ onLoad((options) =&gt; {
82 153 height: 100%;
83 154 width: 100%;
84 155 box-sizing: border-box;
85   - padding: 20rpx;
  156 + // padding: 20rpx;
86 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 162 display: flex;
96   - align-items: center;
  163 + flex-direction: column;
97 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 308 width: 100%;
125   - height: 100%;
  309 + height: 80rpx;
126 310 display: flex;
127   - justify-content: center;
128 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 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 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 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 14 </scroll-view>
49 15 <slot name="footer" v-if="showConfirm">
50 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 19 </view>
61 20 </slot>
62 21 </view>
... ... @@ -67,12 +26,11 @@
67 26 import uHeader from './header.vue'
68 27 import uMonth from './month.vue'
69 28 import props from './props.js'
70   -import util from './util.js'
71 29 // import dayjs from '../../libs/util/dayjs.min.js'
72 30 import dayjs from 'dayjs/esm/index'
73   -import Calendar from '../../libs/util/calendar.js'
74   -import mpMixin from '../../libs/mixin/mpMixin.js'
75 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 35 * Calendar 日历
78 36 * @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中.
... ... @@ -129,7 +87,7 @@ export default {
129 87 // month组件中选择的日期数组
130 88 selected: [],
131 89 scrollIntoView: '',
132   - scrollTop:0,
  90 + scrollTop: 0,
133 91 // 过滤处理方法
134 92 innerFormatter: (value) => value
135 93 }
... ... @@ -168,9 +126,8 @@ export default {
168 126 subtitle() {
169 127 // 初始化时,this.months为空数组,所以需要特别判断处理
170 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 131 } else {
175 132 return ''
176 133 }
... ... @@ -320,9 +277,9 @@ export default {
320 277 scrollIntoDefaultMonth(selected) {
321 278 // 查询默认日期在可选列表的下标
322 279 const _index = this.months.findIndex(({
323   - year,
324   - month
325   - }) => {
  280 + year,
  281 + month
  282 + }) => {
326 283 month = uni.$u.padZero(month)
327 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 10 border: {
11 11 type: Boolean,
12 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 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 5 <text class="u-cell-group__title__text">{{ title }}</text>
6 6 </slot>
7   - </view>
8   - <view class="u-cell-group__wrapper">
  7 + </view>
  8 + <view class="u-cell-group__wrapper">
9 9 <u-line v-if="border"></u-line>
10   - <slot />
11   - </view>
12   - </view>
  10 + <slot />
  11 + </view>
  12 + </view>
13 13 </template>
14 14  
15 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 35 </script>
36 36  
37 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 7 </slot>
8 8 </view>
9 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 14 </view>
15 15 </template>
16 16  
... ... @@ -89,7 +89,7 @@ export default {
89 89 },
90 90 // 组件选中激活时的颜色
91 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 95 elInactiveColor() {
... ...
garbage-removal/src/uview-plus/components/u-dropdown-item/props.js
1   -import defprops from '../../libs/config/props';
2 1 export default {
3 2 props: {
  3 + // #ifdef VUE3
4 4 // 当前选中项的value值
  5 + modelValue: {
  6 + type: [Number, String, Array],
  7 + default: ''
  8 + },
  9 + // #endif
  10 + // #ifdef VUE2
  11 + // 当前选中项的value值
5 12 value: {
6 13 type: [Number, String, Array],
7 14 default: ''
8 15 },
  16 + // #endif
9 17 // 菜单项标题
10 18 title: {
11 19 type: [String, Number],
... ... @@ -32,6 +40,11 @@ export default {
32 40 closeOnClickOverlay: {
33 41 type: Boolean,
34 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 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 17 </view>
18 18 </template>
19 19  
20 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 91 title: this.title,
86 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 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 127 </style>
... ...
garbage-removal/src/uview-plus/components/u-dropdown/props.js
1   -import defprops from '../../libs/config/props';
2 1 export default {
3 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 14 closeOnClickMask: {
... ... @@ -45,7 +38,7 @@ export default {
45 38 // 标题的字体大小
46 39 titleSize: {
47 40 type: [Number, String],
48   - default: 14
  41 + default: 28
49 42 },
50 43 // 下拉出来的内容部分的圆角值
51 44 borderRadius: {
... ...
garbage-removal/src/uview-plus/components/u-dropdown/u-dropdown.vue
1 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 19 </view>
30 20 </view>
31 21 </view>
32 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 32 </view>
36 33 </view>
37 34 </template>
38 35  
39 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 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 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 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 252 </style>
... ...
garbage-removal/src/uview-plus/components/u-form-item/u-form-item.vue
... ... @@ -7,19 +7,20 @@
7 7 <slot name="label">
8 8 <!-- {{required}} -->
9 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 14 <view class="u-form-item__body__left__content">
15 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 18 <view class="u-form-item__body__left__content__icon" v-if="leftIcon">
18 19 <u-icon :name="leftIcon" :custom-style="leftIconStyle"></u-icon>
19 20 </view>
20 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 24 </view>
24 25 </view>
25 26 </slot>
... ... @@ -36,8 +37,8 @@
36 37 </view>
37 38 <slot name="error">
38 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 42 </slot>
42 43 <u-line v-if="borderBottom"
43 44 :color="message && parentData.errorType === 'border-bottom' ? $u.color.error : propsLine.color"
... ...
garbage-removal/src/uview-plus/components/u-search/u-search.vue
1 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 10 <template v-if="$slots.label || label !== null">
18 11 <slot name="label">
19 12 <text class="u-search__content__label">{{ label }}</text>
20 13 </slot>
21 14 </template>
22 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 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 31 </view>
64 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 36 </view>
72 37 </template>
73 38  
74 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 96 // #ifdef VUE3
141   - modelValue: {
142   - immediate: true,
143   - handler(nVal) {
144   - this.keyword = nVal;
145   - }
146   - },
  97 + this.$emit("update:modelValue", nVal);
147 98 // #endif
148 99 // #ifdef VUE2
149   - value: {
150   - immediate: true,
151   - handler(nVal) {
152   - this.keyword = nVal;
153   - }
154   - },
  100 + this.$emit('input', nVal);
155 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 185 </script>
221 186  
222 187 <style lang="scss" scoped>
... ... @@ -242,8 +207,9 @@ $u-search-action-margin-left: 5px !default;
242 207 /* #ifdef H5 */
243 208 // iOS15在H5下,hx的某些版本,input type=search时,会多了一个搜索图标,进行移除
244 209 [type="search"]::-webkit-search-decoration {
245   - display: none;
  210 + display: none;
246 211 }
  212 +
247 213 /* #endif */
248 214  
249 215 .u-search {
... ...
garbage-removal/src/uview-plus/components/u-textarea/u-textarea.vue
1 1 <template>
2 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 15 </view>
41 16 </template>
42 17  
43 18 <script>
44   -import props from "./props.js";
45   -import mpMixin from '../../libs/mixin/mpMixin.js';
46 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 23 * Textarea 文本域
49 24 * @description 文本域此组件满足了可能出现的表单信息补充,编辑等实际逻辑的功能,内置了字数校验等
... ... @@ -84,64 +59,64 @@ import mixin from &#39;../../libs/mixin/mixin.js&#39;;
84 59 export default {
85 60 name: "u-textarea",
86 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 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 98 // #endif
124 99 // #ifdef VUE3
125 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 118 // #endif
144   - },
  119 + },
145 120 computed: {
146 121 // 组件的类名
147 122 textareaClass() {
... ... @@ -176,10 +151,10 @@ export default {
176 151 emits: ['update:modelValue', 'linechange', 'focus', 'blur', 'change', 'confirm', 'keyboardheightchange'],
177 152 // #endif
178 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 158 onFocus(e) {
184 159 this.$emit("focus", e);
185 160 },
... ... @@ -192,34 +167,34 @@ export default {
192 167 this.$emit("linechange", e);
193 168 },
194 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 185 // #ifdef VUE3
211 186 this.$emit("update:modelValue", value);
212 187 // #endif
213 188 // #ifdef VUE2
214 189 this.$emit("input", value);
215 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 198 onConfirm(e) {
224 199 this.$emit("confirm", e);
225 200 },
... ... @@ -239,7 +214,7 @@ export default {
239 214 position: relative;
240 215 @include flex;
241 216 flex: 1;
242   - padding: 9px;
  217 + padding: 9px;
243 218  
244 219 &--radius {
245 220 border-radius: 4px;
... ... @@ -257,7 +232,7 @@ export default {
257 232 flex: 1;
258 233 font-size: 15px;
259 234 color: $u-content-color;
260   - width: 100%;
  235 + width: 100%;
261 236 }
262 237  
263 238 &__count {
... ...
garbage-removal/src/uview-plus/components/u-upload/u-upload.vue
... ... @@ -5,14 +5,14 @@
5 5 <view class="u-upload__wrap__preview" v-for="(item, index) in lists" :key="index">
6 6 <image v-if="item.isImage || (item.type && item.type === 'image')" :src="item.thumb || item.url"
7 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 11 <view v-else class="u-upload__wrap__preview__other">
12 12 <u-icon color="#80CBF9" size="26"
13 13 :name="item.isVideo || (item.type && item.type === 'video') ? 'movie' : 'folder'"></u-icon>
14 14 <text class="u-upload__wrap__preview__other__text">{{ item.isVideo || (item.type && item.type === 'video') ?
15   - '视频' : '文件' }}</text>
  15 + '视频' : '文件' }}</text>
16 16 </view>
17 17 <view class="u-upload__status" v-if="item.status === 'uploading' || item.status === 'failed'">
18 18 <view class="u-upload__status__icon">
... ... @@ -48,9 +48,9 @@
48 48 </view>
49 49 <view v-else class="u-upload__button" :hover-class="!disabled ? 'u-upload__button--hover' : ''"
50 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 54 <u-icon :name="uploadIcon" size="26" :color="uploadIconColor"></u-icon>
55 55 <text v-if="uploadText" class="u-upload__button__text">{{ uploadText }}</text>
56 56 </view>
... ... @@ -251,7 +251,7 @@ export default {
251 251 // 预览图片
252 252 onPreviewImage(item) {
253 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 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 256 for (let index = 0; index < imageArray.length; index++) {
257 257 if (!imageArray[index].startsWith(baseUrl)) {
... ...
garbage-removal/vite.config.js
... ... @@ -12,5 +12,8 @@ export default defineConfig({
12 12 "@": resolve(__dirname, "src"), // 设置@指向src
13 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 4368 resolved "https://registry.npmmirror.com/jpeg-js/-/jpeg-js-0.3.7.tgz"
4369 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 4376 js-tokens@^4.0.0:
4372 4377 version "4.0.0"
4373 4378 resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz"
... ...