Commit fec135c8dcdbe9ce2e604420090cbe2affbc378f

Authored by guzijian
1 parent dda8d67e

feat: 新增派单下发,增加企业负责人角色

Showing 29 changed files with 3487 additions and 921 deletions
garbage-removal/src/apis/order.js
... ... @@ -44,7 +44,28 @@ export async function uploadEvaluate(params, config) {
44 44 return await request.post(`/order/evaluate`, params, config);
45 45 }
46 46  
47   -
  47 +/**
  48 + * 匿名访问
  49 + * @param {*} orderId
  50 + * @returns
  51 + */
48 52 export async function queryGuestOrderDetail(orderId) {
49 53 return await request.get(`/order/webDetail/${orderId}`);
50 54 }
  55 +
  56 +/**
  57 + * 查询公司下运输驾驶员
  58 + * @param {*} companyId
  59 + */
  60 +export async function queryOrderDispatch(orderId) {
  61 + return await request.get(`/order/queryDispatch/${orderId}`);
  62 +}
  63 +
  64 +
  65 +export async function dispatchOrders(params,config) {
  66 + return await request.put('/order/dispatch', params,config);
  67 +}
  68 +
  69 +export async function queryOrderHandlerStatus(orderId, config) {
  70 + return await request.get(`/order/queryOrderHandlerStatus/${orderId}`, config);
  71 +}
... ...
garbage-removal/src/components/clash-dispatch/index.vue 0 → 100644
  1 +<template>
  2 + <next-tree :changeVerify="changeVerify" :title="getTitle" ref="nextTreeRef" :checkStrictly="checkStrictly"
  3 + :selectParent="selectParent" :multiple="multiple" :treeData="treeData" @cancel="close" @confirm="onconfirm">
  4 + <!-- label插槽示意代码 -->
  5 + <!-- <template #label="{data: {id, label, iconSrc, prev, post}}">
  6 + <view class="line-block">
  7 + <image class="img" v-if="iconSrc" :src="iconSrc"></image>
  8 + <text space="nbsp" v-if="prev">{{prev}}&nbsp;</text><text>{{label}}</text><text space="nbsp" v-if="post">&nbsp;{{post}}</text>
  9 + </view>
  10 + </template> -->
  11 + <!-- <template #topBar>
  12 + <view style="color: #666;padding:5px;"><text style="font-size: 12px;">历史记录</text></view>
  13 + <view style="display: flex;justify-content: space-between;padding-bottom: 10px;border-bottom: 1rpx solid #f0f0f0;">
  14 + <button @click="checkedFunc('1-3-3-4')" :style="'background-color:'+ (activeId === '1-3-3-4' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">北京区-4</button>
  15 + <button @click="checkedFunc('3-1-2')" :style="'background-color:'+ (activeId === '3-1-2' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">海珠区-2</button>
  16 + <button @click="checkedFunc('3-1-6')" :style="'background-color:'+ (activeId === '3-1-6' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">海珠区-5</button>
  17 + </view>
  18 + </template> -->
  19 + </next-tree>
  20 +</template>
  21 +
  22 +<script setup >
  23 +import { nextTick, ref, unref } from 'vue';
  24 +// @ts-ignore
  25 +import nextTree from '../next-tree/next-tree.vue';
  26 +const props = defineProps({
  27 + dataList: {
  28 + type: Array,
  29 + default: []
  30 + },
  31 + valueKey: {
  32 + type: String,
  33 + default: 'id'
  34 + },
  35 + multiple: {
  36 + type: Boolean,
  37 + default: true
  38 + },
  39 + selectParent: {
  40 + type: Boolean,
  41 + default: false
  42 + },
  43 + checkStrictly: {
  44 + type: Boolean,
  45 + default: false
  46 + },
  47 + onconfirm: {
  48 + type: Function,
  49 + default: () => { }
  50 + }
  51 +
  52 +})
  53 +const treeData = ref([])
  54 +const nextTreeRef = ref()
  55 +function getTitle(checked) {
  56 + return `已选:${checked.length}位驾驶员`
  57 +}
  58 +function changeVerify(current, chooseList) {
  59 + // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串
  60 + // 如果函数体不做return返回值,即验证通过,控件正常处理业务
  61 + // 限制条件
  62 + if (chooseList) {
  63 + for (let index = 0; index < chooseList.length; index++) {
  64 + const element = chooseList[index];
  65 + if (current.id.indexOf(element.id) === -1 && element.label.indexOf(current.label) != -1) {
  66 + return "该驾驶员已经被选中了"
  67 + }
  68 + }
  69 + }
  70 +}
  71 +function open(dataList) {
  72 + treeData.value = handlerTreeData(dataList)
  73 + treeData.value = treeData.value.filter(item => {
  74 + return item.children[0].id
  75 + })
  76 + setTimeout(() => {
  77 + nextTick(() => {
  78 + unref(nextTreeRef).showTree = true
  79 + })
  80 + }, 0)
  81 +}
  82 +
  83 +function handlerTreeData(dataList) {
  84 + return dataList
  85 + .map((item, index) => {
  86 + return {
  87 + "id": (index + 1),
  88 + "licensePlateNumber": item.licensePlateNumber,
  89 + "containerVolume": item.containerVolume + "方车",
  90 + "label": item.containerVolume + "方车" + '-' + item.licensePlateNumber,
  91 + "children": item.personnelInfo.map((childrenItem, childrenIndex) => {
  92 + return {
  93 + "id": (index + 1) + '-' + (childrenIndex + 1),
  94 + "tel": childrenItem.tel,
  95 + "name": childrenItem.name,
  96 + "label": childrenItem.name + '-' + childrenItem.tel,
  97 + "checked": childrenItem.checked,
  98 + "carCode": item.licensePlateNumber,
  99 + "disabled": childrenItem.checked ? true : childrenItem.tel ? false : true
  100 + }
  101 + })
  102 + }
  103 + })
  104 +}
  105 +function cleanTreeData(treeData) {
  106 + treeData.map(item => {
  107 + item.checked = false
  108 + if (item.children && item.children.length) {
  109 + cleanTreeData(item.children)
  110 + }
  111 + })
  112 +}
  113 +function close() {
  114 + // 清除treeData的选中状态
  115 + cleanTreeData(unref(treeData))
  116 +}
  117 +defineExpose({
  118 + open, close, nextTreeRef
  119 +})
  120 +</script>
  121 +<style lang="scss">
  122 +.line-block {
  123 + display: flex;
  124 + flex-direction: row;
  125 + justify-content: flex-start;
  126 + align-items: center;
  127 +
  128 + .img {
  129 + width: 40rpx;
  130 + height: 40rpx;
  131 + border-radius: 10rpx;
  132 + margin: 0 20rpx;
  133 + }
  134 +}
  135 +</style>
... ...
garbage-removal/src/components/liu-delivery-time/liu-delivery-time.vue
... ... @@ -103,11 +103,21 @@ const getFutureDays = () =&gt; {
103 103 const year = date.getFullYear();
104 104 const month = (date.getMonth() + 1).toString().padStart(2, '0');
105 105 const day = date.getDate().toString().padStart(2, '0');
106   -
107   - days.push({
108   - day: `${year}-${month}-${day}`,
109   - timeList: getTimeList()
110   - });
  106 + if (i === 0) {
  107 + let hours = new Date().getHours();
  108 + if (hours >= 13) {
  109 + continue;
  110 + }
  111 + days.push({
  112 + day: `${year}-${month}-${day}`,
  113 + timeList: getCurrentDayTimeList(9, hours, 3)
  114 + });
  115 + } else {
  116 + days.push({
  117 + day: `${year}-${month}-${day}`,
  118 + timeList: getTimeList()
  119 + });
  120 + }
111 121 }
112 122 return days;
113 123 }
... ... @@ -115,47 +125,58 @@ const getFutureDays = () =&gt; {
115 125  
116 126 const getTimeList = () => {
117 127 const timeList = [{
118   - time: '06:00-08:00',
119   - start: '06:00',
120   - end: '08:00'
121   - }, {
122   - time: '08:00-10:00',
123   - start: '08:00',
  128 + time: '09:00-10:00',
  129 + start: '09:00',
124 130 end: '10:00'
125 131 },
126 132 {
127   - time: '10:00-12:00',
  133 + time: '10:00-11:00',
128 134 start: '10:00',
129   - end: '12:00'
  135 + end: '11:00'
130 136 },
131 137 {
132   - time: '12:00-14:00',
133   - start: '12:00',
134   - end: '14:00'
  138 + time: '11:00-12:00',
  139 + start: '11:00',
  140 + end: '12:00'
135 141 },
136 142 {
137   - time: '14:00-16:00',
138   - start: '14:00',
139   - end: '16:00'
  143 + time: '12:00-13:00',
  144 + start: '12:00',
  145 + end: '13:00'
140 146 },
141 147 {
142   - time: '16:00-18:00',
143   - start: '16:00',
144   - end: '18:00'
  148 + time: '13:00-14:00',
  149 + start: '13:00',
  150 + end: '14:00'
145 151 },
146 152 {
147   - time: '18:00-20:00',
148   - start: '18:00',
149   - end: '20:00'
  153 + time: '14:00-15:00',
  154 + start: '14:00',
  155 + end: '15:00'
150 156 },
151 157 {
152   - time: '20:00-22:00',
153   - start: '20:00',
154   - end: '22:00'
  158 + time: '15:00-16:00',
  159 + start: '15:00',
  160 + end: '16:00'
155 161 }
156 162 ];
157 163 return timeList
158 164 }
  165 +
  166 +/**
  167 + *
  168 + * @param {*} startTime 从几点开始
  169 + * @param {*} hours 当前几点
  170 + * @param {*} skip 跳过几个
  171 + */
  172 +const getCurrentDayTimeList = (startTime, hours, skip) => {
  173 + const timeList = getTimeList();
  174 + // 因为从9点开始所以从9点开始截取
  175 + // let startIndex = startTime + skip;
  176 + let abs = startTime > hours ? 1 : -1;
  177 + let index = startTime - hours >= skip ? 0 : (startTime - hours) * abs + skip;
  178 + return timeList.slice(index, timeList.length + 1)
  179 +}
159 180 const open = () => {
160 181 isShow.value = true;
161 182 init();
... ... @@ -163,7 +184,7 @@ const open = () =&gt; {
163 184 const handleDateClick = (index) => {
164 185 selectedIndex.value = index;
165 186 selectedDay.value = days.value[index];
166   - selectedTimeIndex.value = 999;
  187 + selectedTimeIndex.value = 10075;
167 188  
168 189 }
169 190 const handleTimeClick = (index) => {
... ... @@ -387,7 +408,7 @@ defineExpose({ open })
387 408 }
388 409  
389 410 .scroll-animation {
390   - transition: all 0.25s linear;
  411 + transition: all 0.4s linear;
391 412 }
392 413  
393 414 .scroll-temp {
... ... @@ -402,7 +423,8 @@ defineExpose({ open })
402 423 right: 0;
403 424 bottom: 0;
404 425 background: rgba(0, 0, 0, 0.3);
405   - z-index: 998;
  426 + z-index: 10075;
  427 + transition-property: opacity;
406 428 }
407 429  
408 430 .time-picker {
... ... @@ -469,7 +491,7 @@ defineExpose({ open })
469 491 .date.active {
470 492 font-size: 30rpx;
471 493 font-weight: bold;
472   - color: #007aff;
  494 + color: #a9e08f;
473 495 }
474 496  
475 497 .time-scroll {
... ... @@ -492,6 +514,6 @@ defineExpose({ open })
492 514 .time.active {
493 515 font-size: 30rpx;
494 516 font-weight: bold;
495   - color: #007aff;
  517 + color: #a9e08f;
496 518 }
497 519 </style>
... ...
garbage-removal/src/components/next-tree/next-tree.vue 0 → 100644
  1 +<template>
  2 + <view class="next-tree">
  3 + <view class="next-tree-mask" :class="{ 'show': showTree }" @tap="_cancel"></view>
  4 + <view class="next-tree-cnt" :style="'top:' + top"
  5 + :class="{ 'show': showTree, 'next-tree-cnt-page': uiMode === 'page' }">
  6 + <view v-if="_showTreeBar" class="next-tree-bar">
  7 + <view class="next-tree-bar-cancel" :style="{ 'color': cancelColor }" hover-class="hover-c" @tap="_cancel">取消
  8 + </view>
  9 + <view class="next-tree-bar-title" :style="{ 'color': titleColor }">{{ customTitle }}</view>
  10 + <view class="next-tree-bar-btns">
  11 + <view class="next-tree-bar-cancel" :style="{ 'color': cancelColor }" hover-class="hover-c" @tap="_clear">清空
  12 + </view>
  13 + <view class="btn-divid"></view>
  14 + <view class="next-tree-bar-confirm" :style="{ 'color': _themeColor }" hover-class="hover-c" @tap="_confirm">确定
  15 + </view>
  16 + </view>
  17 + </view>
  18 + <view class="next-tree-view" :style="'top:' + (_showTreeBar ? '72rpx' : '0rpx')">
  19 + <next-search-more v-if="ifSearch" @search="onSearch" mode="center" placeholder="请输入关键字"
  20 + :isFixedSearchBtn="false" />
  21 + <slot name="topBar"></slot>
  22 + <scroll-view class="next-tree-view-sc" :scroll-y="true">
  23 + <view v-show="_treeList.length">
  24 + <block v-for="(item, index) in _treeList" :key="index">
  25 + <view class="next-tree-item-block" v-if="item.show">
  26 + <view class="next-tree-item" :style="[{
  27 + paddingLeft: item.rank * 15 + 'px',
  28 + zIndex: item.rank * -1 + 50
  29 + }]" :class="{
  30 + border: border === true,
  31 + show: item.show,
  32 + last: item.lastRank,
  33 + showchild: item.showChild,
  34 + open: item.open,
  35 + disabled: item.disabled === true
  36 +}">
  37 + <block v-if="showAuxiliaryLine">
  38 + <template v-if="item.rank > 1">
  39 + <view :key="i" v-for="i in (item.rank - 1)"
  40 + :style="{ left: (6 * (2 * i - 1) + 3 * (i - 1)) + 'px' }" class="parent-horizontal-line"></view>
  41 + </template>
  42 + <view class="left-line">
  43 + <view v-if="item.lastRank" class="horizontal-line"></view>
  44 + </view>
  45 + </block>
  46 + <view class="next-tree-label" @tap.stop="_treeItemTap(item, index)">
  47 + <image class="next-tree-icon"
  48 + :src="item.lastRank ? lastIcon : item.showChild ? currentIcon : defaultIcon"></image>
  49 + <rich-text :nodes="getNodes(item.ouputText)" :selectable="false"
  50 + v-if="ifSearch && searchModel === 'depHighlight' && keywords"></rich-text>
  51 + <slot v-else-if="$slots.label" name="label" :data="_getLabelSlotData(item)"></slot>
  52 + <rich-text v-else-if="item.checked && !item.disabled" :nodes="getThemeNodes(item.name)"></rich-text>
  53 + <text v-else>{{ item.name }}</text>
  54 + </view>
  55 + <view class="next-tree-check" @tap.stop="_treeItemSelect(item, index)"
  56 + v-if="selectParent ? true : item.lastRank">
  57 + <view class="next-tree-check-yes" v-if="item.checked" :class="{ 'radio': !multiple }"
  58 + :style="{ 'border-color': item.disabled ? '#ccc' : _themeColor, 'background-color': item.disabled ? '#ccc' : _themeColor }">
  59 + <view class="next-tree-check-yes-b"
  60 + :style="{ 'background-color': item.disabled ? '#ccc' : _themeColor }">
  61 + <text v-if="item.checked" class="icon-text">✔</text>
  62 + </view>
  63 + </view>
  64 + <view class="next-tree-check-no" v-else :class="{ 'radio': !multiple }"
  65 + :style="{ 'border-color': item.disabled ? '#ccc' : _themeColor }">
  66 + <text v-if="showHalfChecked(item) && showHalfCheckedTips"
  67 + :style="{ 'color': item.disabled ? '#ccc' : _themeColor, 'font-weight': 'blod', 'font-size': '10px' }"
  68 + class="icon-text">一</text>
  69 + </view>
  70 + </view>
  71 + </view>
  72 + </view>
  73 + </block>
  74 + </view>
  75 + <view v-show="!_treeList.length">
  76 + <slot v-if="$slots.empty" name="empty"></slot>
  77 + <view class="empty" v-else><text>暂无数据</text></view>
  78 + </view>
  79 + <view v-if="ifSearch" style="height: 80rpx"></view>
  80 + <slot name="bottomBar"></slot>
  81 + </scroll-view>
  82 + </view>
  83 + </view>
  84 + <view class="fixed-bottom-bar">
  85 + <slot name="fixedBottomBar"></slot>
  86 + </view>
  87 + </view>
  88 +</template>
  89 +
  90 +<script>
  91 +export default {
  92 + name: "next-tree",
  93 + props: {
  94 + uiMode: {
  95 + type: String,
  96 + default: 'popup' // popup(弹窗), page(页面)
  97 + },
  98 + treeData: {
  99 + type: Array,
  100 + default: function () {
  101 + return []
  102 + }
  103 + },
  104 + valueKey: {
  105 + type: String,
  106 + default: 'id'
  107 + },
  108 + labelKey: {
  109 + type: String,
  110 + default: 'label'
  111 + },
  112 + disabledKey: {
  113 + type: String,
  114 + default: 'disabled'
  115 + },
  116 + childrenKey: {
  117 + type: String,
  118 + default: 'children'
  119 + },
  120 + title: {
  121 + type: [String, Function],
  122 + default: ''
  123 + },
  124 + multiple: { // 是否可以多选
  125 + type: Boolean,
  126 + default: false
  127 + // default: true
  128 + },
  129 + selectParent: { //是否可以选父级
  130 + type: Boolean,
  131 + default: false
  132 + },
  133 + foldAll: { //折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开
  134 + type: Boolean,
  135 + default: false
  136 + },
  137 + themeColor: { // 主题颜色
  138 + type: String,
  139 + default: '#53C21D' // #f9ae3d
  140 + },
  141 + cancelColor: { // 取消按钮颜色
  142 + type: String,
  143 + default: '' // #757575
  144 + },
  145 + titleColor: { // 标题颜色
  146 + type: String,
  147 + default: '' // #757575
  148 + },
  149 + currentIcon: { // 展开时候的ic
  150 + type: String,
  151 + default: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MEQ0QTM0MzQ1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MEQ0QTM0MzU1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowRDRBMzQzMjVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowRDRBMzQzMzVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PidwepsAAAK0SURBVHja7JxbTsJAFIYHww7ciStgCeoGvGxAiOsgURegoL5720AXYLiIr0aJviq3Zx3PhIEnKG3ndtr+f3KixrSUj/ZjzjClIqUUiFm2gAAQAREQEUAEREAERAQQAREQAREBREAEREBEEqa67h9RFDWllDv0awWYlqlQHmu1WjMRRMoV1QFttA12y3xRtdNczq8EsE4/f8FumX2q77ROvNXk8UGMEKdUz6tYJHljaZAbuyUH+UR1to5BEohTuqwPCeS4pAA/qY6o/kyHOAMCeRK3owJnj+rH1jjxhqpVsstaebCz6TmnHWyXyY+xHjSBWBY/bvSgadtXBj9u9KCN3rnIfkzkQVsTEEX0Y2IP2oKo/HhMICcFAThUcwVZNGU6FdbX/XURzkbVF4+ybGhjPrFdgP66QdXNurGtSdk6Xdb9nAJ8oDo3OQlsQZzkdPw41ONBo6vI5scDefRjZg+6gpg3Pxp50CXEvPjR2IOuIXL3oxUPuobI3Y9WPOgDIlc/WvOgL4iL/vqFCcD7LH0xB4hj7cfQ/fWH9qCT+FhG0tN+DBk1PzjOM0SVllixcsBT1AvYc/kAPhc0hRg/3uvxoCgKRN9+dOrBUBB9+9GpB0NC9OVH5x4MDdG1H714kANEV3705kEOEBf9dcPi/lQnsuvLg1wgSu3Ha0v7Uh4MMgUXeuG71H407a+VBy9CPQkOdw+MtB+nGbd/D+FBbhBNxo9SjwcngJjNj0E9yBFiFj8G9SBXiGn8GNyDnCEm8SMLD3KHGOdHNh7kDjHOj2w8mAeIi/5arX+c6b/fxHz9oADEdGdjR/fXCw/OOB5oVfCOgnepz8IB14PMw03jCmTE+QBx5z0gAmKSqK9OUF+hcAeIhu/QYr4Qie8rjW83hhMBERARQAREQAREBBABERCLnH8BBgA+TQI7U4t53AAAAABJRU5ErkJggg=='
  152 + },
  153 + defaultIcon: { // 折叠时候的ic
  154 + type: String,
  155 + default: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAACE0lEQVR4Xu3c200DMRCF4XEltJAOkEugA+ggpUAHoQMqiFMCdEAJUMEiS4mEELlIO7bPOeN9i6K1rG/952myyea1WiCtXmEuYBPR4RBMxInoIOCwhOtJLKVszWyXc/5y2BvNEq6I+/3+kFK6M7OHnPM7jcLKjbZAvD/uaZtzflm5P4rbWyJWgDcze1LPuzVihfxUz7sH4ilJ2bx7Isrm3RtRMu8RiHJ5j0SUyXs0okTeCIj0eSMh0uaNhkiZNyIiXd7IiDR5oyNS5M2ACJ83EyJs3myIkHkzIsLlzYwIkzc7IkTeCojD81ZCHJa3GuKQvBURu+etjNgtb3XELnlHQGyedyTEZnlHQ2ySd0RE97wjI7rlHR3RJe+JeIrbLOecD6ePpZQ6W1kn2epo4MUrPOKyLN8ppYq1+y1VStncOjIdGnFZlo+U0uOtWOeOY2TE12Ouq//pEA7xXL7XfvcufR8K0Svfv6CREN3yDYfYIt9QiK3yjYTYLF95xB75SiP2ylcZsVu+cogj8pVCHJWvEuKwfOkREfKlRkTJlxkRJl86RMR8qRBR82VChM0XHpEhX2hElnyREWnyhUNkzBcKkTVfJETafIcjKuQ7FFEl35GIMvl2R1TMtyuiar49EWXzbY5oZpv/hibXTF2h3+s60FRKeT6+3TjMS3nrA3ZFRD8xrfY3ER1kJ+JEdBBwWGKeRAfEH1wS5WFZSDB/AAAAAElFTkSuQmCC'
  156 + },
  157 + lastIcon: { // 没有子集的ic
  158 + type: String,
  159 + default: ''
  160 + },
  161 + border: { // 是否有分割线
  162 + type: Boolean,
  163 + default: false
  164 + },
  165 + checkStrictly: { // 只有在multiple为true状态下生效; 状态下节点选择完全受控(父子节点选中状态不再关联)
  166 + type: Boolean,
  167 + default: false
  168 + },
  169 + checkStrictlyModel: { // 关联模式 weak: 弱关联;strong: 强关联
  170 + type: String,
  171 + default: 'weak'
  172 + },
  173 + showHalfCheckedTips: { // 只有在multiple为true, checkStrictly为false状态下生效; 父子节点选中状态不再关联,显示半选提示
  174 + type: Boolean,
  175 + default: true
  176 + },
  177 + ifSearch: { // 是否开启search模式
  178 + type: Boolean,
  179 + default: true
  180 + },
  181 + searchModel: { // 搜索模式配置
  182 + type: String,
  183 + default: 'common' // depHighlight: 从属高亮;common: 一般
  184 + },
  185 + showAuxiliaryLine: { // 辅助线模式
  186 + type: Boolean,
  187 + default: false
  188 + },
  189 + loadData: {
  190 + type: Function
  191 + },
  192 + height: {
  193 + type: Number,
  194 + default: 500
  195 + },
  196 + changeVerify: {
  197 + type: Function
  198 + }
  199 + },
  200 + data() {
  201 + return {
  202 + showTree: false,
  203 + treeList: [],
  204 + currentTreeData: [],
  205 + selectIndex: -1,
  206 + keywords: '',
  207 + nodeInitContrl: {},
  208 + top: ''
  209 + }
  210 + },
  211 + computed: {
  212 + _showTreeBar() {
  213 + return this.uiMode === 'popup'
  214 + },
  215 + _themeColor() {
  216 + return this.themeColor || '#53C21D'
  217 + },
  218 + _treeList() {
  219 + if (this.ifSearch && this.keywords) {
  220 + return this.treeList.filter(item => {
  221 + return (item.name && item.name.indexOf(this.keywords) !== -1)
  222 + }).map(item => {
  223 + const o = JSON.parse(JSON.stringify(item));
  224 + if (o.showChild === false) {
  225 + o.showChild = true;
  226 + }
  227 + if (o.show === false) {
  228 + o.show = true;
  229 + }
  230 + return o
  231 + })
  232 + } else {
  233 + return this.treeList
  234 + }
  235 + },
  236 + customTitle() {
  237 + if (typeof this.title === 'function') {
  238 + return this.title(this._getCheckedParams());
  239 + } else {
  240 + return this.title
  241 + }
  242 + }
  243 + },
  244 + methods: {
  245 + _show() {
  246 + this.showTree = true
  247 + },
  248 + _hide() {
  249 + this.showTree = false
  250 + },
  251 + _cancel() {
  252 + this._hide()
  253 + this.$emit("cancel", '');
  254 + },
  255 + _confirm() {
  256 + // 处理所选数据
  257 + let rt = this._getCheckedParams();
  258 + this._hide()
  259 + this.$emit("confirm", rt);
  260 + },
  261 + _getLabelSlotData(item) {
  262 + const _it = this.getItemFromTreeData(this.currentTreeData, item.id);
  263 + const it = Object.assign({}, _it);
  264 + delete it[this.childrenKey];
  265 + return it
  266 + },
  267 + _getCheckedParams() {
  268 + // 处理所选数据
  269 + let rt = [],
  270 + obj = {};
  271 + this.treeList.forEach((v, i) => {
  272 + if (this.treeList[i].checked) {
  273 + obj = {}
  274 + obj.parents = this.treeList[i].parents
  275 + obj = Object.assign(obj, this.treeList[i].source)
  276 + // 移除子元素
  277 + delete obj.children
  278 + rt.push(obj)
  279 + }
  280 + });
  281 + return rt;
  282 + },
  283 + checkedFunc(values, state = true) {
  284 + if (values instanceof Array) {
  285 + values.map(id => {
  286 + const item = this.treeList.find(it => it.id === id);
  287 + if (item) {
  288 + item.checked = !!state
  289 + }
  290 + })
  291 + } else {
  292 + const _item = this.treeList.find(it => it.id === values);
  293 + if (_item) {
  294 + _item.checked = !!state
  295 + }
  296 + }
  297 + },
  298 + getRenderTreeList(list = [], rank = 0, parentId = [], parents = []) {
  299 + const treeList = [];
  300 + list.forEach(item => {
  301 + const halfChecked = this.getHalfCheckedFormTreeData(item);
  302 + let ouputText = '';
  303 + if (this.searchModel === 'depHighlight') {
  304 + if (parents && parents.length) {
  305 + ouputText = parents.map(item => item[this.labelKey]).join(' > ');
  306 + ouputText = ouputText + ' > ' + item[this.labelKey];
  307 + } else {
  308 + ouputText = item[this.labelKey];
  309 + }
  310 + }
  311 + treeList.push({
  312 + id: item[this.valueKey],
  313 + name: item[this.labelKey],
  314 + source: item,
  315 + parentId, // 父级id数组
  316 + parents, // 父级id数组
  317 + rank, // 层级
  318 + showChild: false, //子级是否显示
  319 + open: false, //是否打开
  320 + show: rank === 0, // 自身是否显示
  321 + hideArr: [],
  322 + ouputText,
  323 + orChecked: item.checked ? item.checked : false,
  324 + checked: item.checked ? item.checked : false,
  325 + halfChecked,
  326 + disabled: this.disabledKey && item[this.disabledKey] === true
  327 + })
  328 + if (
  329 + (Array.isArray(item[this.childrenKey]) && item[this.childrenKey].length > 0) ||
  330 + (this.loadData && Array.isArray(item[this.childrenKey]) && item[this.childrenKey].length === 0)
  331 + ) {
  332 + let parentid = [...parentId],
  333 + parentArr = [...parents],
  334 + childrenid = [];
  335 + delete parentArr.children
  336 + parentid.push(item[this.valueKey]);
  337 + parentArr.push({
  338 + [this.valueKey]: item[this.valueKey],
  339 + [this.labelKey]: item[this.labelKey],
  340 + })
  341 + // this._renderTreeList(item[this.childrenKey], rank + 1, parentid, parentArr);
  342 + } else {
  343 + treeList[treeList.length - 1].lastRank = true;
  344 + }
  345 + })
  346 + return treeList;
  347 + },
  348 + //扁平化树结构
  349 + _renderTreeList(list = [], rank = 0, parentId = [], parents = []) {
  350 + list.forEach(item => {
  351 + const halfChecked = this.getHalfCheckedFormTreeData(item);
  352 + let ouputText = '';
  353 + if (this.searchModel === 'depHighlight') {
  354 + if (parents && parents.length) {
  355 + ouputText = parents.map(item => item[this.labelKey]).join(' > ');
  356 + ouputText = ouputText + ' > ' + item[this.labelKey];
  357 + } else {
  358 + ouputText = item[this.labelKey];
  359 + }
  360 + }
  361 + this.treeList.push({
  362 + id: item[this.valueKey],
  363 + name: item[this.labelKey],
  364 + source: item,
  365 + parentId, // 父级id数组
  366 + parents, // 父级id数组
  367 + rank, // 层级
  368 + showChild: false, //子级是否显示
  369 + open: false, //是否打开
  370 + show: rank === 0, // 自身是否显示
  371 + hideArr: [],
  372 + ouputText,
  373 + orChecked: item.checked ? item.checked : false,
  374 + checked: item.checked ? item.checked : false,
  375 + halfChecked,
  376 + disabled: this.disabledKey && item[this.disabledKey] === true
  377 + })
  378 + if (
  379 + (Array.isArray(item[this.childrenKey]) && item[this.childrenKey].length > 0) ||
  380 + (this.loadData && Array.isArray(item[this.childrenKey]) && item[this.childrenKey].length === 0)
  381 + ) {
  382 + let parentid = [...parentId],
  383 + parentArr = [...parents],
  384 + childrenid = [];
  385 + delete parentArr.children
  386 + parentid.push(item[this.valueKey]);
  387 + parentArr.push({
  388 + [this.valueKey]: item[this.valueKey],
  389 + [this.labelKey]: item[this.labelKey],
  390 + "data": item
  391 + })
  392 + this._renderTreeList(item[this.childrenKey], rank + 1, parentid, parentArr);
  393 + } else {
  394 + this.treeList[this.treeList.length - 1].lastRank = true;
  395 + }
  396 + })
  397 + },
  398 + // 处理默认选择
  399 + _defaultSelect() {
  400 + this.treeList.forEach((v, i) => {
  401 + if (v.checked) {
  402 + this.treeList.forEach((v2, i2) => {
  403 + if (v.parentId.toString().indexOf(v2.parentId.toString()) >= 0) {
  404 + v2.show = true
  405 + if (v.parentId.includes(v2.id)) {
  406 + v2.showChild = true;
  407 + v2.open = true;
  408 + }
  409 + }
  410 + })
  411 + }
  412 + })
  413 + },
  414 + // 点击
  415 + async _treeItemTap(item, _index) {
  416 + const index = this.treeList.findIndex(it => it.id === item.id);
  417 + if (item.lastRank === true) {
  418 + if (item.disabled === true) return
  419 + //点击最后一级时触发事件
  420 + this.treeList[index].checked = !this.treeList[index].checked;
  421 + if (this.changeVerify && (typeof this.changeVerify === 'function')) {
  422 + const current = Object.assign({}, item.source);
  423 + current.checked = item.checked;
  424 + const tip = this.changeVerify(current, this.multiple ? this._getCheckedParams() : [current]);
  425 + if (tip) {
  426 + this.treeList[index].checked = !this.treeList[index].checked;
  427 + uni.showToast({
  428 + title: tip,
  429 + icon: 'none'
  430 + });
  431 + return
  432 + }
  433 + };
  434 + this.treeList[index].halfChecked = false;
  435 + if (this.multiple && !this.checkStrictly && this.showHalfCheckedTips) {
  436 + this.updateHalfChecked(index);
  437 + } else if (this.multiple && this.checkStrictly) {
  438 + this.updateParentChecked(index);
  439 + }
  440 + this._fixMultiple(index)
  441 + return;
  442 + }
  443 + // loadData实现
  444 + const isLoadData = this.loadData && !this.nodeInitContrl[item.id];
  445 + if (isLoadData) {
  446 + uni && uni.showLoading({ title: "请稍后..." });
  447 + const newChild = await this.loadData(this.treeList[index].source);
  448 + // 为了保证treeData数据的完整性,异步加载的数据需要添加到treeData上;
  449 + const treeItem = this.getItemFromTreeData(this.currentTreeData, item.id);
  450 + treeItem[this.childrenKey] = newChild && newChild.length ? newChild : undefined;
  451 + const parentId = item.parentId || [];
  452 + const lists = this.getRenderTreeList(newChild || [], item.rank + 1, parentId.concat([item.id]), [{ [this.valueKey]: item[this.valueKey], [this.labelKey]: item[this.labelKey] }]);
  453 + this.nodeInitContrl[item.id] = true;
  454 + this.treeList.splice(index + 1, 0, ...lists);
  455 + }
  456 + const childLen = this.treeList.filter(it => it.parentId.includes(item.id)).length;
  457 + if (!isLoadData && childLen > 50) {
  458 + uni && uni.showLoading({ title: "请稍后..." });
  459 + }
  460 + let list = this.treeList;
  461 + let id = item.id;
  462 + item.showChild = !item.showChild;
  463 + item.open = item.showChild ? true : !item.open;
  464 + list.forEach((childItem, i) => {
  465 + if (item.showChild === false) {
  466 + //隐藏所有子级
  467 + if (!childItem.parentId.includes(id)) {
  468 + return;
  469 + }
  470 + if (!this.foldAll) {
  471 + if (childItem.lastRank !== true && !childItem.open) {
  472 + childItem.showChild = false;
  473 + }
  474 + // 为隐藏的内容添加一个标记
  475 + if (childItem.show) {
  476 + childItem.hideArr[item.rank] = id
  477 + }
  478 + } else {
  479 + if (childItem.lastRank !== true) {
  480 + childItem.showChild = false;
  481 + }
  482 + }
  483 + childItem.show = false;
  484 + } else {
  485 + // 打开子集
  486 + if (childItem.parentId[childItem.parentId.length - 1] === id) {
  487 + childItem.show = true;
  488 + }
  489 + // 打开被隐藏的子集
  490 + if (childItem.parentId.includes(id) && !this.foldAll) {
  491 + // console.log(childItem.hideArr)
  492 + if (childItem.hideArr[item.rank] === id) {
  493 + childItem.show = true;
  494 + if (childItem.open && childItem.showChild) {
  495 + childItem.showChild = true
  496 + } else {
  497 + childItem.showChild = false
  498 + }
  499 + childItem.hideArr[item.rank] = null
  500 + }
  501 + }
  502 + }
  503 + });
  504 + setTimeout(() => {
  505 + uni && uni.hideLoading()
  506 + })
  507 + },
  508 + getThemeNodes(text) {
  509 + const regex = new RegExp(`(${text || ''})`, 'gi');
  510 + return text ? text.replace(regex, `<span style="color: ${this._themeColor}">$1</span>`) : '';
  511 + },
  512 + getNodes(ouputText) {
  513 + if (this.keywords && ouputText) {
  514 + const regex = new RegExp(`(${this.keywords})`, 'gi');
  515 + return ouputText.replace(regex, `<span style="color: ${this._themeColor}">$1</span>`);
  516 + }
  517 + return ouputText
  518 + },
  519 + getHalfCheckedFormTreeData(item) {
  520 + if (this.checkStrictly) {
  521 + return false;
  522 + } else if (!this.showHalfCheckedTips) {
  523 + return false
  524 + } else {
  525 + if (item[this.childrenKey] && item[this.childrenKey].length) {
  526 + return item[this.childrenKey].some(it => {
  527 + if (it.checked === true) {
  528 + return true;
  529 + } else if (it[this.childrenKey] && it[this.childrenKey].length) {
  530 + return this.getHalfCheckedFormTreeData(it);
  531 + } else {
  532 + return false;
  533 + };
  534 + });
  535 + } else {
  536 + return false;
  537 + }
  538 + }
  539 + },
  540 + getItemFromTreeData(treeData, id) {
  541 + if (id) {
  542 + let item = null;
  543 + (treeData || []).some(it => {
  544 + if (it[this.valueKey] === id) {
  545 + item = it
  546 + return true
  547 + } else if (it[this.childrenKey] && it[this.childrenKey].length) {
  548 + item = this.getItemFromTreeData(it[this.childrenKey], id)
  549 + return !!item
  550 + } else {
  551 + return false
  552 + }
  553 + });
  554 + return item
  555 + };
  556 + return null
  557 + },
  558 + _treeItemSelect(item, _index) {
  559 + const index = this.treeList.findIndex(it => it.id === item.id);
  560 + if (item.disabled === true) return
  561 + this.treeList[index].checked = !this.treeList[index].checked;
  562 + // console.log(index)
  563 + if (this.changeVerify && (typeof this.changeVerify === 'function')) {
  564 + const current = Object.assign({}, item.source);
  565 + current.checked = item.checked;
  566 + const tip = this.changeVerify(current, this.multiple ? this._getCheckedParams() : [current]);
  567 + if (tip) {
  568 + this.treeList[index].checked = !this.treeList[index].checked;
  569 + uni.showToast({
  570 + title: tip,
  571 + icon: 'none'
  572 + });
  573 + return
  574 + }
  575 + };
  576 + this.treeList[index].halfChecked = false;
  577 + if (this.multiple && this.checkStrictly) {
  578 + if (!item.lastRank) {
  579 + const source = item.source || {};
  580 + const children = source[this.childrenKey] || [];
  581 + const checkedKeyList = this.getChildrenKeys(children);
  582 + this.treeList.forEach((v, i) => {
  583 + if (checkedKeyList.indexOf(v.id) !== -1) {
  584 + if (this.checkStrictlyModel === 'weak') {
  585 + if (!this.treeList[i].disabled) {
  586 + this.treeList[i].checked = this.treeList[index].checked
  587 + }
  588 + } else if (this.checkStrictlyModel === 'strong') {
  589 + this.treeList[i].checked = this.treeList[index].checked
  590 + }
  591 + }
  592 + })
  593 + }
  594 + this.updateParentChecked(index)
  595 + } else if (this.multiple && !this.checkStrictly && this.showHalfCheckedTips) {
  596 + this.updateHalfChecked(index);
  597 + } else {
  598 + this._fixMultiple(index);
  599 + }
  600 + },
  601 + updateParentChecked(index) {
  602 + const parentId = (this.treeList[index].parentId || []).concat([]).reverse();
  603 + if (parentId && parentId.length) {
  604 + parentId.map(id => {
  605 + const parentTreeDataItem = this.getItemFromTreeData(this.currentTreeData, id);
  606 + const childrenIds = (parentTreeDataItem[this.childrenKey] || []).map(item => item[this.valueKey]);
  607 + const bool = this.treeList
  608 + .filter(it => childrenIds.indexOf(it.id) !== -1)
  609 + .every(it => it.checked === true);
  610 +
  611 + const _bool = this.treeList
  612 + .filter(it => childrenIds.indexOf(it.id) !== -1)
  613 + .every(it => it.checked === false);
  614 +
  615 + const parentItem = this.treeList.find(it => it.id === id);
  616 + if (parentItem) {
  617 + if (this.checkStrictlyModel === 'weak') {
  618 + if (bool && !parentItem.disabled) {
  619 + parentItem.checked = true;
  620 + } else if (_bool && !parentItem.disabled) {
  621 + parentItem.checked = false;
  622 + }
  623 + } else if (this.checkStrictlyModel === 'strong') {
  624 + if (bool) {
  625 + parentItem.checked = true;
  626 + } else {
  627 + parentItem.checked = false;
  628 + }
  629 + }
  630 + }
  631 + })
  632 + }
  633 + },
  634 + updateHalfChecked(index) {
  635 + const _parentId = this.treeList[index].parentId || [];
  636 + const parentId = _parentId.concat([]).reverse();
  637 + if (parentId && parentId.length) {
  638 + parentId.map(id => {
  639 + const parentTreeDataItem = this.getItemFromTreeData(this.currentTreeData, id);
  640 + const childrenIds = (parentTreeDataItem[this.childrenKey] || []).map(item => item[this.valueKey]);
  641 +
  642 + const bool = this.treeList
  643 + .filter(it => childrenIds.indexOf(it.id) !== -1)
  644 + .every(it => it.checked === false && it.halfChecked === false);
  645 +
  646 + const _bool = this.treeList
  647 + .filter(it => childrenIds.indexOf(it.id) !== -1)
  648 + .some(it => it.checked === true || it.halfChecked === true);
  649 +
  650 + const parentItem = this.treeList.find(it => it.id === id);
  651 + if (parentItem) {
  652 + if (!parentItem.checked) {
  653 + if (bool) {
  654 + parentItem.halfChecked = false
  655 + } else if (_bool) {
  656 + parentItem.halfChecked = true
  657 + } else {
  658 + parentItem.halfChecked = false
  659 + }
  660 + }
  661 + }
  662 + })
  663 + }
  664 + if (this.treeList[index].checked == false) {
  665 + const source = this.treeList[index].source || {};
  666 + const children = source[this.childrenKey] || [];
  667 + const checkedKeyList = this.getChildrenKeys(children);
  668 + const bool = this.treeList.filter(item => checkedKeyList.indexOf(item.id) !== -1).some(item => item.checked);
  669 + if (bool) {
  670 + this.treeList[index].halfChecked = true;
  671 + }
  672 + }
  673 + },
  674 + showHalfChecked(item) {
  675 + if (this.multiple && !this.checkStrictly && item.halfChecked === true) {
  676 + return true
  677 + } else {
  678 + return false
  679 + }
  680 + },
  681 + getChildrenKeys(children) {
  682 + let keys = [];
  683 + (children || []).map(item => {
  684 + keys.push(item[this.valueKey])
  685 + if (item[this.childrenKey] && item[this.childrenKey].length) {
  686 + keys = keys.concat(this.getChildrenKeys(item[this.childrenKey]))
  687 + }
  688 + })
  689 + return keys
  690 + },
  691 + // 处理单选多选
  692 + _fixMultiple(index) {
  693 + if (!this.multiple) {
  694 + // 如果是单选
  695 + this.treeList.forEach((v, i) => {
  696 + if (i != index) {
  697 + this.treeList[i].checked = false
  698 + } else {
  699 + this.treeList[i].checked = true
  700 + }
  701 + })
  702 + }
  703 + },
  704 + // 重置数据
  705 + _reTreeList() {
  706 + this.treeList.forEach((v, i) => {
  707 + this.treeList[i].checked = v.orChecked
  708 + })
  709 + },
  710 + _initTree() {
  711 + this.treeList.length = 0;
  712 + if (this.loadData) {
  713 + this.currentTreeData = JSON.parse(JSON.stringify(this.treeData));
  714 + } else {
  715 + this.currentTreeData = this.treeData;
  716 + }
  717 + this._renderTreeList(this.currentTreeData);
  718 + this.$nextTick(() => {
  719 + this._defaultSelect(this.currentTreeData);
  720 + })
  721 + },
  722 + _clear() {
  723 + this.treeList.map(item => {
  724 + if (this.multiple && this.checkStrictly) {
  725 + if (this.checkStrictlyModel === 'strong') {
  726 + item.checked = false;
  727 + } else if (this.checkStrictlyModel === 'weak') {
  728 + if (!item.disabled) {
  729 + item.checked = false;
  730 + };
  731 + } else {
  732 + item.checked = false;
  733 + }
  734 + } else {
  735 + if (!item.disabled) {
  736 + item.checked = false;
  737 + }
  738 + };
  739 +
  740 + item.halfChecked = false;
  741 + })
  742 + this.$emit("clear");
  743 + },
  744 + onSearch(val) {
  745 + this.keywords = val;
  746 + },
  747 + initUiModePopup(watched) {
  748 + uni.getSystemInfo({
  749 + success: (res) => {
  750 + this.top = (res.windowHeight - this.height) + 'px';
  751 + }
  752 + });
  753 + watched && watched();
  754 + watched = this.$watch(() => this.showTree, (bool) => {
  755 + if (bool) {
  756 + this._initTree();
  757 + } else {
  758 + this.treeList.length = 0;
  759 + this.nodeInitContrl = {};
  760 + }
  761 + }, { immediate: true });
  762 + },
  763 + initUiModePage(watched) {
  764 + this.top = '0px';
  765 + watched && watched();
  766 + watched = this.$watch(() => this.treeData, () => {
  767 + this.treeList.length = 0;
  768 + this.nodeInitContrl = {};
  769 + this.$nextTick(() => {
  770 + this._initTree();
  771 + });
  772 + }, { immediate: true, deep: true })
  773 + this.$nextTick(() => {
  774 + this.showTree = true;
  775 + });
  776 + },
  777 + uiModeInit() {
  778 + let watched = null;
  779 + if (this.uiMode === 'popup') {
  780 + this.initUiModePopup(watched);
  781 + } else if (this.uiMode === 'page') {
  782 + this.initUiModePage(watched);
  783 + } else {
  784 + this.initUiModePopup(watched);
  785 + }
  786 + }
  787 + },
  788 + mounted() {
  789 + this.uiModeInit();
  790 + }
  791 +}
  792 +</script>
  793 +
  794 +<style scoped>
  795 +@import "./style.css";
  796 +</style>
... ...
garbage-removal/src/components/next-tree/readme/changelog.md 0 → 100644
  1 +## 1.6.7(2024-01-04)
  2 +修复异步加载节点搜索展示bug
  3 +## 1.6.6(2023-12-29)
  4 +修复next-tree异步加载节点关闭bug
  5 +## 1.6.5(2023-12-21)
  6 +fix bug
  7 +## 1.6.4(2023-12-21)
  8 +fix bug
  9 +## 1.6.3(2023-12-21)
  10 +更新vue2版本说明文档
  11 +## 1.6.2(2023-12-21)
  12 +修复说明文档
  13 +## 1.6.1(2023-12-18)
  14 +增加empty插槽
  15 +## 1.6.0(2023-12-18)
  16 +增加empty插槽
  17 +## 1.5.9(2023-12-15)
  18 +修改说明文件
  19 +## 1.5.8(2023-12-15)
  20 +修复changeVerify函数单选时,返回参数bug
  21 +## 1.5.7(2023-12-14)
  22 +修复checkStrictlyModel === 'strong'的bug
  23 +## 1.5.6(2023-12-13)
  24 +代码优化
  25 +## 1.5.5(2023-12-13)
  26 +优化changeVerify的使用
  27 +## 1.5.4(2023-12-12)
  28 +修复提示层级问题
  29 +## 1.5.3(2023-12-12)
  30 +优化uiMode=page模式下的使用
  31 +## 1.5.2(2023-12-11)
  32 +增加uiMode配置,实现页面模式展示
  33 +## 1.5.1(2023-12-06)
  34 +更新说明
  35 +## 1.5.0(2023-12-06)
  36 +更新插件使用注意事项
  37 +## 1.4.9(2023-12-01)
  38 +增加topBar插槽
  39 +## 1.4.8(2023-11-30)
  40 +增加changeVerify验证函数,实现change的各种控制
  41 +## 1.4.7(2023-11-30)
  42 +增加弹层容器高度可配置
  43 +## 1.4.6(2023-11-28)
  44 +修复bug
  45 +## 1.4.5(2023-11-28)
  46 +修复disabled是,需要显示灰色不可操作
  47 +## 1.4.4(2023-11-28)
  48 +增加说明
  49 +## 1.4.3(2023-11-28)
  50 +增加主题配置
  51 +## 1.4.2(2023-11-28)
  52 +增加异步加载时,子节点说明
  53 +## 1.4.1(2023-11-27)
  54 +修复说明bug
  55 +## 1.4.0(2023-11-27)
  56 +next-tree 全面说明文档
  57 +## 1.3.6(2023-11-27)
  58 +增加远程加载loadData,全面实现全功能覆盖
  59 +## 1.3.5(2023-11-27)
  60 +增加title的定义
  61 +## 1.3.4(2023-11-27)
  62 +增加title支持自定义定制
  63 +## 1.3.3(2023-11-21)
  64 +增加搜索模式searchModel=depHighlight模式,从属高亮显示模式
  65 +## 1.3.2(2023-11-20)
  66 +修复valueKey设置bug
  67 +## 1.3.1(2023-11-17)
  68 +增加说明文件,和demo
  69 +## 1.3.0(2023-11-17)
  70 +修复clear时不支持关联模式的设置
  71 +## 1.2.9(2023-11-17)
  72 +增加checkStrictlyModel模式设置,强关联,和弱关联
  73 +## 1.2.8(2023-11-16)
  74 +增加next-tree的辅助线模式
  75 +## 1.2.7(2023-11-16)
  76 +优化next-tree
  77 +## 1.2.6(2023-11-16)
  78 +修复搜索时,隐藏未打开的数据
  79 +## 1.2.5(2023-11-16)
  80 +修复搜索无法点击,和级联半选不生效问题
  81 +## 1.2.4(2023-11-16)
  82 +更新新功能插件使用说明
  83 +## 1.2.3(2023-11-16)
  84 +增加插槽模式,只是高ui要求定制
  85 +## 1.2.2(2023-11-15)
  86 +修复checkStrictly配置下,子关联父的选择状态
  87 +## 1.2.1(2023-11-15)
  88 +增加半选提示功能配置showHalfCheckedTips
  89 +## 1.2.0(2023-11-14)
  90 +修复disabled配置状态下,父子级联,不需要改变disabled设置项的选择状态
  91 +## 1.1.9(2023-11-13)
  92 +增强大数据量体验交互,增加筛选搜索模式
  93 +## 1.1.8(2023-11-13)
  94 +增加清除clear和取消cancel事件
  95 +## 1.1.7(2023-11-08)
  96 +更新next-tree插件功能清单说明
  97 +## 1.1.6(2023-11-07)
  98 +update说明文档
  99 +## 1.1.5(2023-11-07)
  100 +update
  101 +## 1.1.4(2023-11-07)
  102 +更新readme.md说明
  103 +## 1.1.3(2023-11-07)
  104 +更新说明demo
  105 +## 1.1.2(2023-11-07)
  106 +增加子节点按需渲染演示demo
  107 +## 1.1.1(2023-11-07)
  108 +增加清空功能
  109 +## 1.1.0(2023-11-07)
  110 +增加子孙节点按需渲染,扩展本插件支持大数据量渲染;
  111 +## 1.0.9(2023-10-26)
  112 +增加文件说明
  113 +## 1.0.8(2023-09-14)
  114 +增加禁用节点属性配置disabledKey
  115 +## 1.0.7(2023-09-06)
  116 +增加checkStrictly,实现父子节点关联
  117 +## 1.0.6(2023-09-06)
  118 +更新vue2使用过程视图不更新的技术说明
  119 +## 1.0.5(2023-09-06)
  120 +修复说明文档
  121 +## 1.0.4(2023-06-19)
  122 +修改demo
  123 +## 1.0.3(2023-06-19)
  124 +更新vue2的使用demo
  125 +## 1.0.2(2023-06-19)
  126 +修复说明文档
  127 +
  128 +## 1.0.1(2023-05-10)
  129 +更新说明文件
  130 +## 1.0.0(2023-05-09)
  131 +初始化项目
... ...
garbage-removal/src/components/next-tree/readme/package.json 0 → 100644
  1 +{
  2 + "id": "next-tree",
  3 + "displayName": "next-tree(超强树选择器、树组件、树插件、无限级联树、单选树、多选树、自定义样式树、树形选择器)",
  4 + "version": "1.6.7",
  5 + "description": "next-tree 弹窗树形选择器,支持多选,支持大数据, 无限级联,单选,父子级级联,远程/ajax加载,子节点增量/异步渲染,自定义样式定制,具名插槽等;支持h5/小程序/APP,全端通用",
  6 + "keywords": [
  7 + "树选择",
  8 + "tree",
  9 + "弹窗树选择器",
  10 + "多选树",
  11 + "单选树"
  12 +],
  13 +"engines": {
  14 + },
  15 +"dcloudext": {
  16 + "sale": {
  17 + "regular": {
  18 + "price": "0.00"
  19 + },
  20 + "sourcecode": {
  21 + "price": "0.00"
  22 + }
  23 + },
  24 + "contact": {
  25 + "qq": ""
  26 + },
  27 + "declaration": {
  28 + "ads": "无",
  29 + "data": "修改版本说明",
  30 + "permissions": "无"
  31 + },
  32 + "npmurl": "",
  33 + "type": "component-vue"
  34 + },
  35 + "uni_modules": {
  36 + "dependencies": ["next-search-more"],
  37 + "encrypt": [],
  38 + "platforms": {
  39 + "cloud": {
  40 + "tcb": "y",
  41 + "aliyun": "y"
  42 + },
  43 + "client": {
  44 + "Vue": {
  45 + "vue2": "y",
  46 + "vue3": "y"
  47 + },
  48 + "App": {
  49 + "app-vue": "y",
  50 + "app-nvue": "u"
  51 + },
  52 + "H5-mobile": {
  53 + "Safari": "y",
  54 + "Android Browser": "y",
  55 + "微信浏览器(Android)": "y",
  56 + "QQ浏览器(Android)": "y"
  57 + },
  58 + "H5-pc": {
  59 + "Chrome": "y",
  60 + "IE": "n",
  61 + "Edge": "y",
  62 + "Firefox": "y",
  63 + "Safari": "u"
  64 + },
  65 + "小程序": {
  66 + "微信": "y",
  67 + "阿里": "y",
  68 + "百度": "y",
  69 + "字节跳动": "u",
  70 + "QQ": "y",
  71 + "钉钉": "y",
  72 + "快手": "u",
  73 + "飞书": "u",
  74 + "京东": "u"
  75 + },
  76 + "快应用": {
  77 + "华为": "u",
  78 + "联盟": "u"
  79 + }
  80 + }
  81 + }
  82 + }
  83 +}
0 84 \ No newline at end of file
... ...
garbage-removal/src/components/next-tree/readme/readme.md 0 → 100644
  1 +
  2 +## next-tree --下拉树
  3 +
  4 +> 遇到问题或有建议可以加入QQ群(<font color=#f00>455948571</font>)反馈
  5 +> 如果觉得组件不错,<font color=#f00>给五星鼓励鼓励</font>咯!
  6 +
  7 +## 亮点功能说明(打造你不得不用的好插件)
  8 +
  9 +### 本插件自1.5.0版本后支持一下功能
  10 +
  11 + > 1.大数据量渲染(本插件智能判断,如果子孙集数据量大于50时,会响应等待渲染视图;)
  12 + > 2.子节点按需渲染(自动启用,无需配置)
  13 + > 3.父子级联选择设置
  14 + > 4.单选多选设置
  15 + > 5.父节点是否可选设置
  16 + > 6.回显默认选中值
  17 + > 7.不可选项disabled设置
  18 + > 8.增强大数据量体验交互,增加筛选搜索模式
  19 + > 9.增强样式定制,提供自定插槽,实现高要求样式定制
  20 + > 10.增加辅助线模式,外观更加精美
  21 + > 11.支持动态配置title
  22 + > 12.支持搜索模式searchModel=depHighlight模式,从属高亮显示模式
  23 + > 13.支持异步加载子节点,ajax加载子节点
  24 + > 14.增加可配置主题,自由定制插件主题颜色
  25 + > 15.支持动态校验,可以进行提示控制校验
  26 + > 16.支持页面模式,可以进行单页面展示
  27 + > 17.支持半选提示状态显示
  28 +
  29 +## 注意
  30 +
  31 +### 作者不介意你对组件源码进行改造使用,为了开源更加高效,谢谢你的配合;为了节省不必要的沟通浪费,以下情况请不要再反馈给作者,请自行解决;
  32 +### 在这感各位的理解,我支持开源,但是作者时间有限;谢谢各位的配合;在这里期望我写的小小插件能为你提供便捷;
  33 +
  34 + > 1.如果你对源码进行了修改使用,请不需要对作者做任何的反馈,作者确实没有空陪你做技术分析解答;
  35 + > 2.如果你引入插件,连插件是否有正常被uniapp框架识别解析都不清楚,请你换个插件使用;
  36 + > 3.如果你引入插件,针对自己项目进行功能改造的,请自行仔细阅读源码并了解其原理,自行改造;这里作者不愿意浪费过多时间进行技术解答;
  37 + > 4.如果你不想进行全局加载next-tree,需要按需加载;next-tree中有相关依赖的组件,需要你自行在组件内部单独引入;依赖组件可以在package.json中找到;
  38 + > 5.理论上作者不再解决由于本地开发环境问题所导致的插件使用问题,请自行到uniapp官网学习解决;
  39 +
  40 +## 使用
  41 +
  42 +>[从uniapp插件市场导入](https://ext.dcloud.net.cn/plugin?name=next-tree)
  43 +
  44 +## 关注作者其他开源
  45 +
  46 +npm开源包:[npm](https://www.npmjs.com/~lixueshiaa);
  47 +github开源项目:[github](https://github.com/lixueshiaa);
  48 +
  49 +
  50 +```html
  51 +<template>
  52 + <view style="padding:10px;color: #333;font-weight: 500;">
  53 + <view style="padding: 10px 0"><text>1、设置单选和父级不可选</text></view>
  54 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(false, false)">设置</button>
  55 + <view style="padding: 10px 0"><text>2、设置多选和父级不可选</text></view>
  56 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(true, false)">设置</button>
  57 + <view style="padding: 10px 0"><text>3、设置单选和父级可选</text></view>
  58 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(false, true)">设置</button>
  59 + <view style="padding: 10px 0"><text>4、设置多选和父级可选</text></view>
  60 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(true, true)" >设置</button>
  61 + <view style="padding: 10px 0"><text>4、设置多选和父级可选和父级关联子级选择</text></view>
  62 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(true, true, true)" >设置</button>
  63 + <view style="padding: 10px 0"><text>5、设置默认回显(默认选中: '上海-2', '黄埔区-35')</text></view>
  64 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="echoDefault()" >设置</button>
  65 + <!-- 异步加载demo -->
  66 + <view style="padding: 10px 0"><text>6、异步加载渲染demo</text></view>
  67 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="openTree()" >设置</button>
  68 + </view>
  69 +
  70 + <!-- 异步加载demo -->
  71 + <next-tree :selectParent="false" :checkStrictly="true" :multiple="true" ref="nextTreeAsyncRef" :treeData="asyncTreeData" :loadData="loadData" />
  72 +
  73 + <next-tree :changeVerify="changeVerify" :title="getTitle" ref="nextTreeRef" :checkStrictly="checkStrictly" :selectParent="selectParent" :multiple="multiple" :treeData="treeData" @cancel="oncancel" @confirm="onconfirm">
  74 + <!-- label插槽示意代码 -->
  75 + <!-- <template #label="{data: {id, label, iconSrc, prev, post}}">
  76 + <view class="line-block">
  77 + <image class="img" v-if="iconSrc" :src="iconSrc"></image>
  78 + <text space="nbsp" v-if="prev">{{prev}}&nbsp;</text><text>{{label}}</text><text space="nbsp" v-if="post">&nbsp;{{post}}</text>
  79 + </view>
  80 + </template> -->
  81 + <!-- <template #topBar>
  82 + <view style="color: #666;padding:5px;"><text style="font-size: 12px;">历史记录</text></view>
  83 + <view style="display: flex;justify-content: space-between;padding-bottom: 10px;border-bottom: 1rpx solid #f0f0f0;">
  84 + <button @click="checkedFunc('1-3-3-4')" :style="'background-color:'+ (activeId === '1-3-3-4' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">北京区-4</button>
  85 + <button @click="checkedFunc('3-1-2')" :style="'background-color:'+ (activeId === '3-1-2' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">海珠区-2</button>
  86 + <button @click="checkedFunc('3-1-6')" :style="'background-color:'+ (activeId === '3-1-6' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">海珠区-5</button>
  87 + </view>
  88 + </template> -->
  89 + </next-tree>
  90 +</template>
  91 +```
  92 +
  93 +### vue3 + ts 使用
  94 +
  95 +```ts
  96 +<script setup lang="ts">
  97 +import { ref, unref } from 'vue'
  98 +import nextTree from '@/components/next-tree/next-tree.vue'
  99 +
  100 +const multiple = ref(false)
  101 +const selectParent = ref(false)
  102 +const nextTreeRef = ref()
  103 +const nextTreeAsyncRef = ref()
  104 +const activeId = ref('')
  105 +
  106 +const localData: any = {
  107 + 'a1': [{id: 'a1-1', label: 'a1-1'}, {id: 'a1-2', label: 'a1-2',children: [] },{id: 'a1-3', label: 'a1-3'}],
  108 + 'b1': [{id: 'b1-1', label: 'b1-1',children: []}, {id: 'b1-2', label: 'b1-2'},{id: 'b1-3', label: 'b1-3'}],
  109 + 'c1': [{id: 'c1-1', label: 'c1-1'}, {id: 'c1-2', label: 'c1-2'},{id: 'c1-3', label: 'c1-3',children: []}],
  110 + 'a1-2': [{id: 'a1-2-1', label: 'a1-2-1'}, {id: 'a1-2-2', label: 'a1-2-2'}],
  111 + 'b1-1': [{id: 'b1-1-1', label: 'b1-1-1'}, {id: 'b1-1-2', label: 'b1-1-2'}],
  112 + 'c1-3': [{id: 'c1-3-1', label: 'c1-3-1'}, {id: 'c1-3-2', label: 'c1-3-2'}]
  113 +}
  114 +
  115 +const checkStrictly = ref(false)
  116 +const asyncTreeData = ref([{id: 'a1', label: 'a1', children: []},{id: 'b1', label: 'b1', children: []},{id: 'c1', label: 'c1', children: []}])
  117 +const treeData = ref([
  118 + {id: '1', label: '北京'},
  119 + {id: '2', label: '上海', children: [
  120 + {id: '2-1', label: '上海-1'},
  121 + {id: '2-2', label: '上海-2'},
  122 + {id: '2-3', label: '上海-3'},
  123 + ] },
  124 + {id: '3', label: '广州', children: [
  125 + {id: '3-1', label: '海珠区', children: [
  126 + {id: '3-1-1', label: '海珠区-1'},
  127 + {id: '3-1-2', label: '海珠区-2'},
  128 + {id: '3-1-4', label: '海珠区-3'},
  129 + {id: '3-1-5', label: '海珠区-4'},
  130 + {id: '3-1-6', label: '海珠区-5'},
  131 + {id: '3-1-7', label: '海珠区-6'},
  132 + {id: '3-1-8', label: '海珠区-7'},
  133 + {id: '3-1-9', label: '海珠区-8'},
  134 + {id: '3-1-10', label: '海珠区-9'},
  135 + {id: '3-1-11', label: '海珠区-10'},
  136 + ]},
  137 + {id: '3-2', label: '番禺区', children: [
  138 + {id: '3-2-1', label: '番禺区-1'},
  139 + {id: '3-2-2', label: '番禺区-2'},
  140 + {id: '3-2-4', label: '番禺区-3'},
  141 + {id: '3-2-5', label: '番禺区-4'},
  142 + {id: '3-2-6', label: '番禺区-5'},
  143 + {id: '3-2-7', label: '番禺区-6'},
  144 + {id: '3-2-8', label: '番禺区-7'},
  145 + {id: '3-2-9', label: '番禺区-8'},
  146 + {id: '3-2-10', label: '番禺区-9'},
  147 + {id: '3-2-11', label: '番禺区-10'},
  148 + ]},
  149 + {id: '3-3', label: '黄埔区', children: [
  150 + {id: '3-3-1', label: '黄埔区-1'},
  151 + {id: '3-3-2', label: '黄埔区-2'},
  152 + {id: '3-3-3', label: '黄埔区-3'},
  153 + {id: '3-3-4', label: '黄埔区-4'},
  154 + {id: '3-3-5', label: '黄埔区-5'},
  155 + {id: '3-3-6', label: '黄埔区-6'},
  156 + {id: '3-3-7', label: '黄埔区-7'},
  157 + {id: '3-3-8', label: '黄埔区-8'},
  158 + {id: '3-3-9', label: '黄埔区-9'},
  159 + {id: '3-3-10', label: '黄埔区-10'},
  160 + {id: '3-3-12', label: '黄埔区-11'},
  161 + {id: '3-3-13', label: '黄埔区-12'},
  162 + {id: '3-3-13', label: '黄埔区-13'},
  163 + {id: '3-3-14', label: '黄埔区-14'},
  164 + {id: '3-3-15', label: '黄埔区-15'},
  165 + {id: '3-3-16', label: '黄埔区-16'},
  166 + {id: '3-3-17', label: '黄埔区-17'},
  167 + {id: '3-3-18', label: '黄埔区-18'},
  168 + {id: '3-3-19', label: '黄埔区-19'},
  169 + {id: '3-3-20', label: '黄埔区-20'},
  170 + {id: '3-3-21', label: '黄埔区-21'},
  171 + {id: '3-3-22', label: '黄埔区-22'},
  172 + {id: '3-3-23', label: '黄埔区-23'},
  173 + {id: '3-3-24', label: '黄埔区-24'},
  174 + {id: '3-3-25', label: '黄埔区-25'},
  175 + {id: '3-3-26', label: '黄埔区-26'},
  176 + {id: '3-3-27', label: '黄埔区-27'},
  177 + {id: '3-3-28', label: '黄埔区-28'},
  178 + {id: '3-3-29', label: '黄埔区-29'},
  179 + {id: '3-3-30', label: '黄埔区-30'},
  180 + {id: '3-3-31', label: '黄埔区-31'},
  181 + {id: '3-3-32', label: '黄埔区-32'},
  182 + {id: '3-3-33', label: '黄埔区-33'},
  183 + {id: '3-3-34', label: '黄埔区-34'},
  184 + {id: '3-3-35', label: '黄埔区-35'},
  185 + {id: '3-3-36', label: '黄埔区-36'},
  186 +
  187 + ]},
  188 + ],
  189 + }])
  190 +function getTitle(checked) {
  191 + return `已选:${checked.length}项`
  192 +}
  193 +function itemclick (_multiple, _selectParent, _checkStrictly = false) {
  194 + multiple.value = _multiple
  195 + selectParent.value = _selectParent
  196 + checkStrictly.value = _checkStrictly
  197 + unref(nextTreeRef).showTree = true
  198 +}
  199 +function checkedFunc(id) {
  200 + if(unref(activeId) === id) {
  201 + activeId.value = '';
  202 + unref(nextTreeRef).checkedFunc(id, false)
  203 + } else {
  204 + activeId.value = id;
  205 + unref(nextTreeRef).checkedFunc(id)
  206 + }
  207 +}
  208 +function changeVerify(current, chooseList) {
  209 + // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串
  210 + // 如果函数体不做return返回值,即验证通过,控件正常处理业务
  211 + console.log('当前变化的数据', current)
  212 + console.log('已选择的数据', chooseList)
  213 + if(chooseList && chooseList.length > 4) {
  214 +
  215 + return '最多可以选择4个节点'
  216 + }
  217 +}
  218 +function openTree() {
  219 + unref(nextTreeAsyncRef).showTree = true
  220 +}
  221 +function echoDefault () {
  222 + const selectIds = ['2-1','3-3-35']
  223 + checkedTreeData(unref(treeData), selectIds)
  224 + console.log('treeData的数据:', unref(treeData))
  225 + multiple.value = true
  226 + unref(nextTreeRef).showTree = true
  227 +}
  228 +function loadData(nodeItem) {
  229 + // 同步实现的代码处理方式
  230 + // 如果期望子集节点中还存在孙子节点可以打开,请在初始化数据的时候,初始化个空数组的子节点配置值{[this.childrenKey]: []}
  231 +
  232 + // if(nodeItem && localData[nodeItem.id]) {
  233 + // return localData[nodeItem.id]
  234 + // } else {
  235 + // return []
  236 + // }
  237 +
  238 + // 异步的代码实现方式
  239 + // 如果期望子集节点中还存在孙子节点可以打开,请在初始化数据的时候,初始化个空数组的子节点配置值{[this.childrenKey]: []}
  240 +
  241 + return new Promise((resolve, reject) => {
  242 + setTimeout(() => {
  243 + if(nodeItem && localData[nodeItem.id]) {
  244 + return resolve(localData[nodeItem.id])
  245 + } else {
  246 + return resolve([])
  247 + }
  248 + }, 1000)
  249 + })
  250 +}
  251 +function checkedTreeData (treeData, selectIds) {
  252 + treeData.map(item => {
  253 + if (selectIds.indexOf(item.id) !== -1) {
  254 + item.checked = true
  255 + } else {
  256 + item.checked = false
  257 + }
  258 + if (item.children && item.children.length) {
  259 + checkedTreeData(item.children, selectIds)
  260 + }
  261 + })
  262 +}
  263 +function oncancel() {
  264 + // 清除treeData的选中状态
  265 + checkedTreeData(unref(treeData), [])
  266 +}
  267 +function onconfirm(list) {
  268 + console.log('选中项的数量列表list:', list)
  269 +}
  270 +</script>
  271 +<style lang="scss">
  272 + .line-block {
  273 + display: flex;
  274 + flex-direction: row;
  275 + justify-content: flex-start;
  276 + align-items: center;
  277 + .img {
  278 + width: 40rpx;
  279 + height: 40rpx;
  280 + border-radius: 10rpx;
  281 + margin: 0 20rpx;
  282 + }
  283 + }
  284 +</style>
  285 +
  286 +```
  287 +
  288 +### vue2 使用
  289 +```html
  290 +<template>
  291 + <view>
  292 + <view style="padding:10px;color: #333;font-weight: 500;">
  293 + <view style="padding: 10px 0"><text>1、设置单选和父级不可选</text></view>
  294 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(false, false)">设置</button>
  295 + <view style="padding: 10px 0"><text>2、设置多选和父级不可选</text></view>
  296 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(true, false)">设置</button>
  297 + <view style="padding: 10px 0"><text>3、设置单选和父级可选</text></view>
  298 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(false, true)">设置</button>
  299 + <view style="padding: 10px 0"><text>4、设置多选和父级可选</text></view>
  300 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(true, true)" >设置</button>
  301 + <view style="padding: 10px 0"><text>4、设置多选和父级可选和父级关联子级选择</text></view>
  302 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="itemclick(true, true, true)" >设置</button>
  303 + <view style="padding: 10px 0"><text>5、设置默认回显(默认选中: '上海-2', '黄埔区-35')</text></view>
  304 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="echoDefault()" >设置</button>
  305 + <!-- 异步加载demo -->
  306 + <view style="padding: 10px 0"><text>6、异步加载渲染demo</text></view>
  307 + <button style="width: 100%;background-color: #f9ae3d;color:#fff" size="mini" @click="openTree()" >设置</button>
  308 + </view>
  309 + <!-- 异步加载demo -->
  310 + <next-tree :selectParent="false" :checkStrictly="true" :multiple="true" ref="nextTreeAsyncRef" :treeData="asyncTreeData" :loadData="loadData" />
  311 +
  312 + <next-tree :changeVerify="changeVerify" :title="getTitle" ref="nextTreeRef" :checkStrictly="checkStrictly" :selectParent="selectParent" :multiple="multiple" :treeData="treeData" @cancel="oncancel" @confirm="onconfirm">
  313 + <!-- label插槽示意代码 -->
  314 + <!-- <template v-slot:label="{data: {id, label, iconSrc, prev, post}}">
  315 + <view class="line-block">
  316 + <image class="img" v-if="iconSrc" :src="iconSrc"></image>
  317 + <text space="nbsp" v-if="prev">{{prev}}&nbsp;</text><text>{{label}}</text><text space="nbsp" v-if="post">&nbsp;{{post}}</text>
  318 + </view>
  319 + </template> -->
  320 + <!-- <template #topBar>
  321 + <view style="color: #666;padding:5px;"><text style="font-size: 12px;">历史记录</text></view>
  322 + <view style="display: flex;justify-content: space-between;padding-bottom: 10px;border-bottom: 1rpx solid #f0f0f0;">
  323 + <button @click="checkedFunc('1-3-3-4')" :style="'background-color:'+ (activeId === '1-3-3-4' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">北京区-4</button>
  324 + <button @click="checkedFunc('3-1-2')" :style="'background-color:'+ (activeId === '3-1-2' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">海珠区-2</button>
  325 + <button @click="checkedFunc('3-1-6')" :style="'background-color:'+ (activeId === '3-1-6' ? '#f9ae3d' : '#ccc') + ';color:#fff;margin: 5px'" size="mini">海珠区-5</button>
  326 + </view>
  327 + </template> -->
  328 + </next-tree>
  329 + </view>
  330 +</template>
  331 +```
  332 +
  333 +```js
  334 +<script>
  335 +let self = null;
  336 +export default {
  337 + data () {
  338 + return {
  339 + multiple: false,
  340 + selectParent: false,
  341 + checkStrictly: false,
  342 + activeId: '',
  343 + localData:{
  344 + 'a1': [{id: 'a1-1', label: 'a1-1'}, {id: 'a1-2', label: 'a1-2',children: [] },{id: 'a1-3', label: 'a1-3'}],
  345 + 'b1': [{id: 'b1-1', label: 'b1-1',children: []}, {id: 'b1-2', label: 'b1-2'},{id: 'b1-3', label: 'b1-3'}],
  346 + 'c1': [{id: 'c1-1', label: 'c1-1'}, {id: 'c1-2', label: 'c1-2'},{id: 'c1-3', label: 'c1-3',children: []}],
  347 + 'a1-2': [{id: 'a1-2-1', label: 'a1-2-1'}, {id: 'a1-2-2', label: 'a1-2-2'}],
  348 + 'b1-1': [{id: 'b1-1-1', label: 'b1-1-1'}, {id: 'b1-1-2', label: 'b1-1-2'}],
  349 + 'c1-3': [{id: 'c1-3-1', label: 'c1-3-1'}, {id: 'c1-3-2', label: 'c1-3-2'}]
  350 + },
  351 + asyncTreeData: [{id: 'a1', label: 'a1', children: []},{id: 'b1', label: 'b1', children: []},{id: 'c1', label: 'c1', children: []}],
  352 + treeData: [
  353 + {id: '1', label: '北京', checked: false},
  354 + {id: '2', label: '上海', checked: false, children: [
  355 + {id: '2-1', label: '上海-1', checked: false},
  356 + {id: '2-2', label: '上海-2', checked: false},
  357 + {id: '2-3', label: '上海-3', checked: false},
  358 + ] },
  359 + {id: '3', label: '广州', children: [
  360 + {id: '3-1', label: '海珠区', checked: false, children: [
  361 + {id: '3-1-1', label: '海珠区-1', checked: false, disabled: true},
  362 + {id: '3-1-2', label: '海珠区-2', checked: false},
  363 + {id: '3-1-4', label: '海珠区-3', checked: false},
  364 + {id: '3-1-5', label: '海珠区-4', checked: false},
  365 + {id: '3-1-6', label: '海珠区-5', checked: false},
  366 + {id: '3-1-7', label: '海珠区-6', checked: false},
  367 + {id: '3-1-8', label: '海珠区-7', checked: false},
  368 + {id: '3-1-9', label: '海珠区-8', checked: false},
  369 + {id: '3-1-10', label: '海珠区-9', checked: false},
  370 + {id: '3-1-11', label: '海珠区-10', checked: false},
  371 + ]},
  372 + {id: '3-2', label: '番禺区', checked: false, children: [
  373 + {id: '3-2-1', label: '番禺区-1', checked: false},
  374 + {id: '3-2-2', label: '番禺区-2', checked: false},
  375 + {id: '3-2-4', label: '番禺区-3', checked: false},
  376 + {id: '3-2-5', label: '番禺区-4', checked: false},
  377 + {id: '3-2-6', label: '番禺区-5', checked: false},
  378 + {id: '3-2-7', label: '番禺区-6', checked: false},
  379 + {id: '3-2-8', label: '番禺区-7', checked: false},
  380 + {id: '3-2-9', label: '番禺区-8', checked: false},
  381 + {id: '3-2-10', label: '番禺区-9', checked: false},
  382 + {id: '3-2-11', label: '番禺区-10', checked: false},
  383 + ]},
  384 + {id: '3-3', label: '黄埔区', checked: false, children: [
  385 + {id: '3-3-1', label: '黄埔区-1', checked: false},
  386 + {id: '3-3-2', label: '黄埔区-2', checked: false},
  387 + {id: '3-3-3', label: '黄埔区-3', checked: false},
  388 + {id: '3-3-4', label: '黄埔区-4', checked: false},
  389 + {id: '3-3-5', label: '黄埔区-5', checked: false},
  390 + {id: '3-3-6', label: '黄埔区-6', checked: false},
  391 + {id: '3-3-7', label: '黄埔区-7', checked: false},
  392 + {id: '3-3-8', label: '黄埔区-8', checked: false},
  393 + {id: '3-3-9', label: '黄埔区-9', checked: false},
  394 + {id: '3-3-10', label: '黄埔区-10', checked: false},
  395 + {id: '3-3-12', label: '黄埔区-11', checked: false},
  396 + {id: '3-3-13', label: '黄埔区-12', checked: false},
  397 + {id: '3-3-13', label: '黄埔区-13', checked: false},
  398 + {id: '3-3-14', label: '黄埔区-14', checked: false},
  399 + {id: '3-3-15', label: '黄埔区-15', checked: false},
  400 + {id: '3-3-16', label: '黄埔区-16', checked: false},
  401 + {id: '3-3-17', label: '黄埔区-17', checked: false},
  402 + {id: '3-3-18', label: '黄埔区-18', checked: false},
  403 + {id: '3-3-19', label: '黄埔区-19', checked: false},
  404 + {id: '3-3-20', label: '黄埔区-20', checked: false},
  405 + {id: '3-3-21', label: '黄埔区-21', checked: false},
  406 + {id: '3-3-22', label: '黄埔区-22', checked: false},
  407 + {id: '3-3-23', label: '黄埔区-23', checked: false},
  408 + {id: '3-3-24', label: '黄埔区-24', checked: false},
  409 + {id: '3-3-25', label: '黄埔区-25', checked: false},
  410 + {id: '3-3-26', label: '黄埔区-26', checked: false},
  411 + {id: '3-3-27', label: '黄埔区-27', checked: false},
  412 + {id: '3-3-28', label: '黄埔区-28', checked: false},
  413 + {id: '3-3-29', label: '黄埔区-29', checked: false},
  414 + {id: '3-3-30', label: '黄埔区-30', checked: false},
  415 + {id: '3-3-31', label: '黄埔区-31', checked: false},
  416 + {id: '3-3-32', label: '黄埔区-32', checked: false},
  417 + {id: '3-3-33', label: '黄埔区-33', checked: false},
  418 + {id: '3-3-34', label: '黄埔区-34', checked: false},
  419 + {id: '3-3-35', label: '黄埔区-35', checked: false},
  420 + {id: '3-3-36', label: '黄埔区-36', checked: false},
  421 + ]},
  422 + ],
  423 + }]
  424 + }
  425 + },
  426 + methods: {
  427 + openTree: function() {
  428 + this.$refs.nextTreeAsyncRef.showTree = true
  429 + },
  430 + changeVerify: function(current, chooseList) {
  431 + // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串
  432 + // 如果函数体不做return返回值,即验证通过,控件正常处理业务
  433 + console.log('当前变化的数据', current)
  434 + console.log('已选择的数据', chooseList)
  435 + if(chooseList && chooseList.length > 4) {
  436 +
  437 + return '最多可以选择4个节点'
  438 + }
  439 + },
  440 + checkedFunc: function(id) {
  441 + if(this.activeId === id) {
  442 + this.activeId = '';
  443 + this.$refs.nextTreeRef.checkedFunc(id, false)
  444 + } else {
  445 + this.activeId = id;
  446 + this.$refs.nextTreeRef.checkedFunc(id)
  447 + }
  448 + },
  449 + loadData(nodeItem) {
  450 + // 同步实现的代码处理方式 可以返回单个子节点的集合也可以返回子孙节点的集合
  451 + // 如果期望子集节点中还存在孙子节点可以打开,请在初始化数据的时候,初始化个空数组的子节点配置值{[this.childrenKey]: []}
  452 +
  453 + // if(nodeItem && this.localData[nodeItem.id]) {
  454 + // return this.localData[nodeItem.id]
  455 + // } else {
  456 + // return []
  457 + // }
  458 + // 异步的代码实现方式 可以返回单个子节点的集合也可以返回子孙节点的集合
  459 + // 如果期望子集节点中还存在孙子节点可以打开,请在初始化数据的时候,初始化个空数组的子节点配置值{[this.childrenKey]: []}
  460 + return new Promise((resolve, reject) => {
  461 + setTimeout(() => {
  462 + if(nodeItem && self.localData[nodeItem.id]) {
  463 + return resolve(self.localData[nodeItem.id])
  464 + } else {
  465 + return resolve([])
  466 + }
  467 + }, 1000)
  468 + })
  469 + },
  470 + getTitle: function(checked) {
  471 + return `已选:${checked.length}项`
  472 + },
  473 + echoDefault: function() {
  474 + const selectIds = ['2-1','3-3-35']
  475 + this.checkedTreeData(this.treeData, selectIds)
  476 + console.log('treeData的数据:', this.treeData)
  477 + this.multiple = true
  478 + this.$refs.nextTreeRef.showTree = true
  479 + },
  480 + itemclick: function(_multiple, _selectParent, _checkStrictly = false) {
  481 + this.multiple = _multiple
  482 + this.selectParent = _selectParent
  483 + this.checkStrictly = _checkStrictly
  484 + this.$refs.nextTreeRef.showTree = true
  485 + },
  486 + checkedTreeData: function(treeData, selectIds) {
  487 + // 注意 vue2当数据深嵌套时,如果没有在treeData里面初始化checked属性,那在改变数据的时候直接将checked属性赋值为true,这时候ui界面有可能不会更新,
  488 + // 这时候建议使用this.$set去更新checked属性值,或者在初始化this.treeData的时候初始化checked属性
  489 + (treeData || []).map(item => {
  490 + if (selectIds.indexOf(item.id) !== -1) {
  491 + item.checked = true
  492 + } else {
  493 + item.checked = false
  494 + }
  495 + if (item.children && item.children.length) {
  496 + this.checkedTreeData(item.children, selectIds)
  497 + }
  498 + })
  499 + },
  500 + onconfirm: function(list) {
  501 + console.log('选中项的数量列表list:', list)
  502 + },
  503 + oncancel: function() {
  504 + // 清除treeData的选中状态
  505 + this.checkedTreeData(this.treeData, [])
  506 + }
  507 + },
  508 + created() {
  509 + self = this
  510 + }
  511 +}
  512 +</script>
  513 +<style lang="scss">
  514 + .line-block {
  515 + display: flex;
  516 + flex-direction: row;
  517 + justify-content: flex-start;
  518 + align-items: center;
  519 + .img {
  520 + width: 40rpx;
  521 + height: 40rpx;
  522 + border-radius: 10rpx;
  523 + margin: 0 20rpx;
  524 + }
  525 + }
  526 +</style>
  527 +
  528 +```
  529 +
  530 +### 个性化自定义样式渲染
  531 +
  532 +如果你的需求对样式需求比较高,请使用插槽模式渲染,本组件提供label插槽供你自定义定制;
  533 +
  534 +```js
  535 +<script>
  536 +// 提供参考一组自定义渲染数据demo,treeData如下;
  537 +const treeData = [
  538 + {id: '1', label: '北京', prev: 'PonderNext-', iconSrc: 'https://img95.699pic.com/xsj/03/fg/hj.jpg%21/fh/300', children: [
  539 + {id: '1-3-3-1', label: '北京区-1', prev: '前置-'},
  540 + {id: '1-3-3-2', label: '北京区-2', post: '-后置'},
  541 + {id: '1-3-3-3', label: '北京区-3', post: '-后置', prev: '前置-'},
  542 + {id: '1-3-3-4', label: '北京区-4'},
  543 + {id: '1-3-3-5', label: '北京区-5'},
  544 + {id: '1-3-3-6', label: '北京区-6'},
  545 + {id: '1-3-3-7', label: '北京区-7'},
  546 + {id: '1-3-3-8', label: '北京区-8'},
  547 + {id: '1-3-3-9', label: '北京区-9'},
  548 + {id: '1-3-3-10', label: '北京区-10'},
  549 + {id: '1-3-3-12', label: '北京区-11'},
  550 + {id: '1-3-3-13', label: '北京区-12'},
  551 + {id: '1-3-3-13', label: '北京区-13'},
  552 + {id: '1-3-3-14', label: '北京区-14'},
  553 + {id: '1-3-3-15', label: '北京区-15'},
  554 + {id: '1-3-3-16', label: '北京区-16'},
  555 + {id: '1-3-3-17', label: '北京区-17'},
  556 + {id: '1-3-3-18', label: '北京区-18'},
  557 + {id: '1-3-3-19', label: '北京区-19'},
  558 + {id: '1-3-3-20', label: '北京区-20'},
  559 + {id: '1-3-3-21', label: '北京区-21'},
  560 + {id: '1-3-3-22', label: '北京区-22'},
  561 + {id: '1-3-3-23', label: '北京区-23'},
  562 + {id: '1-3-3-24', label: '北京区-24'},
  563 + {id: '1-3-3-25', label: '北京区-25'},
  564 + {id: '1-3-3-26', label: '北京区-26'},
  565 + {id: '1-3-3-27', label: '北京区-27'},
  566 + {id: '1-3-3-28', label: '北京区-28'},
  567 + {id: '1-3-3-29', label: '北京区-29'},
  568 + {id: '1-1-3-3-30', label: '北京区-30'},
  569 + {id: '1-3-3-31', label: '北京区-31'},
  570 + {id: '1-3-3-32', label: '北京区-32'},
  571 + {id: '1-3-3-33', label: '北京区-33'},
  572 + {id: '1-3-3-34', label: '北京区-34'},
  573 + {id: '1-3-3-35', label: '北京区-35'},
  574 + {id: '1-3-3-36', label: '北京区-36'},
  575 + {id: '1-3-3-37', label: '北京区-37'},
  576 + {id: '1-3-3-38', label: '北京区-38'},
  577 + {id: '1-3-3-39', label: '北京区-39'},
  578 + {id: '1-3-3-40', label: '北京区-40'},
  579 + {id: '1-3-3-41', label: '北京区-41'},
  580 + {id: '1-3-3-42', label: '北京区-42'},
  581 + {id: '1-3-3-43', label: '北京区-43'},
  582 + {id: '1-3-3-44', label: '北京区-44'},
  583 + {id: '1-3-3-45', label: '北京区-45'},
  584 + {id: '1-3-3-46', label: '北京区-46'},
  585 + {id: '1-3-3-47', label: '北京区-47'},
  586 + {id: '1-3-3-48', label: '北京区-48'},
  587 + {id: '1-3-3-49', label: '北京区-49'},
  588 + {id: '1-3-3-50', label: '北京区-50'},
  589 + {id: '1-3-3-51', label: '北京区-51'},
  590 + {id: '1-3-3-52', label: '北京区-52'},
  591 + {id: '1-3-3-53', label: '北京区-53'},
  592 + {id: '1-3-3-54', label: '北京区-54'},
  593 + ]},
  594 + {id: '2', label: '上海', prev: 'PonderNext-', iconSrc: 'https://img95.699pic.com/xsj/0g/hb/tc.jpg%21/fh/300', children: [
  595 + {id: '2-1', label: '上海-1', iconSrc: 'https://img1.baidu.com/it/u=1997340124,765201109&fm=253&fmt=auto&app=120&f=JPEG?w=285&h=285'},
  596 + {id: '2-2', label: '上海-2', iconSrc: 'https://img1.baidu.com/it/u=1997340124,765201109&fm=253&fmt=auto&app=120&f=JPEG?w=285&h=285'},
  597 + {id: '2-3', label: '上海-3', iconSrc: 'https://img1.baidu.com/it/u=1997340124,765201109&fm=253&fmt=auto&app=120&f=JPEG?w=285&h=285'},
  598 + ] },
  599 + {id: '3', label: '广州', prev: 'PonderNext-', iconSrc: 'https://storage-public.zhaopin.cn/user/avatar/1589350028141684980/d00a1afa-e3ec-40a5-a68e-aef1f684b189.jpg', children: [
  600 + {id: '3-1', label: '海珠区', iconSrc: 'https://img95.699pic.com/xsj/0u/f3/5h.jpg%21/fh/300', children: [
  601 + {id: '3-1-1', label: '海珠区-1', disabled: true},
  602 + {id: '3-1-2', label: '海珠区-2', post: '-后置', prev: '前置-'},
  603 + {id: '3-1-4', label: '海珠区-3', post: '-后置',},
  604 + {id: '3-1-5', label: '海珠区-4'},
  605 + {id: '3-1-6', label: '海珠区-5'},
  606 + {id: '3-1-7', label: '海珠区-6'},
  607 + {id: '3-1-8', label: '海珠区-7', post: '-后置',},
  608 + {id: '3-1-9', label: '海珠区-8'},
  609 + {id: '3-1-10', label: '海珠区-9'},
  610 + {id: '3-1-11', label: '海珠区-10'},
  611 + {id: '3-1-1', label: '海珠区-11', disabled: true},
  612 + {id: '3-1-2', label: '海珠区-12'},
  613 + {id: '3-1-4', label: '海珠区-13'},
  614 + {id: '3-1-5', label: '海珠区-14'},
  615 + {id: '3-1-6', label: '海珠区-15'},
  616 + {id: '3-1-7', label: '海珠区-16'},
  617 + {id: '3-1-8', label: '海珠区-17'},
  618 + {id: '3-1-9', label: '海珠区-18'},
  619 + {id: '3-1-10', label: '海珠区-19', prev: '前置-'},
  620 + {id: '3-1-11', label: '海珠区-20'},
  621 + {id: '3-1-1', label: '海珠区-21', disabled: true},
  622 + {id: '3-1-2', label: '海珠区-22'},
  623 + {id: '3-1-4', label: '海珠区-23'},
  624 + {id: '3-1-5', label: '海珠区-24'},
  625 + {id: '3-1-6', label: '海珠区-25'},
  626 + {id: '3-1-7', label: '海珠区-26'},
  627 + {id: '3-1-8', label: '海珠区-27'},
  628 + {id: '3-1-9', label: '海珠区-28'},
  629 + {id: '3-1-10', label: '海珠区-29'},
  630 + {id: '3-1-11', label: '海珠区-30'},
  631 + {id: '3-1-1', label: '海珠区-31', disabled: true},
  632 + {id: '3-1-2', label: '海珠区-32'},
  633 + {id: '3-1-4', label: '海珠区-33'},
  634 + {id: '3-1-5', label: '海珠区-34'},
  635 + {id: '3-1-6', label: '海珠区-35'},
  636 + {id: '3-1-7', label: '海珠区-36'},
  637 + {id: '3-1-8', label: '海珠区-37'},
  638 + {id: '3-1-9', label: '海珠区-38'},
  639 + {id: '3-1-10', label: '海珠区-39'},
  640 + {id: '3-1-11', label: '海珠区-40'},
  641 + {id: '3-1-1', label: '海珠区-41', disabled: true},
  642 + {id: '3-1-2', label: '海珠区-42'},
  643 + {id: '3-1-4', label: '海珠区-43'},
  644 + {id: '3-1-5', label: '海珠区-44'},
  645 + {id: '3-1-6', label: '海珠区-45'},
  646 + {id: '3-1-7', label: '海珠区-46'},
  647 + {id: '3-1-8', label: '海珠区-47'},
  648 + {id: '3-1-9', label: '海珠区-48'},
  649 + {id: '3-1-10', label: '海珠区-49'},
  650 + {id: '3-1-11', label: '海珠区-50'},
  651 + {id: '3-1-11', label: '海珠区-51'},
  652 + ]},
  653 + {id: '3-2', label: '番禺区', iconSrc: 'https://img1.baidu.com/it/u=931648192,3196263841&fm=253&fmt=auto&app=120&f=JPEG?w=285&h=285', disabled: true, checked: true, children: [
  654 + {id: '3-2-1', label: '番禺区-1'},
  655 + {id: '3-2-2', label: '番禺区-2'},
  656 + {id: '3-2-4', label: '番禺区-3'},
  657 + {id: '3-2-5', label: '番禺区-4'},
  658 + {id: '3-2-6', label: '番禺区-5'},
  659 + {id: '3-2-7', label: '番禺区-6'},
  660 + {id: '3-2-8', label: '番禺区-7'},
  661 + {id: '3-2-9', label: '番禺区-8'},
  662 + {id: '3-2-10', label: '番禺区-9'},
  663 + {id: '3-2-11', label: '番禺区-10'},
  664 + ]},
  665 + {id: '3-3', label: '黄埔区', iconSrc: 'https://img.jiaoyubao.cn/43423/20210423113959473-20210423114005024.jpeg', children: [
  666 + {id: '3-3-1', label: '黄埔区-1'},
  667 + {id: '3-3-2', label: '黄埔区-2'},
  668 + {id: '3-3-3', label: '黄埔区-3'},
  669 + {id: '3-3-4', label: '黄埔区-4'},
  670 + {id: '3-3-5', label: '黄埔区-5'},
  671 + {id: '3-3-6', label: '黄埔区-6'},
  672 + {id: '3-3-7', label: '黄埔区-7'},
  673 + {id: '3-3-8', label: '黄埔区-8'},
  674 + {id: '3-3-9', label: '黄埔区-9'},
  675 + {id: '3-3-10', label: '黄埔区-10'},
  676 + {id: '3-3-12', label: '黄埔区-11'},
  677 + {id: '3-3-13', label: '黄埔区-12'},
  678 + {id: '3-3-13', label: '黄埔区-13'},
  679 + {id: '3-3-14', label: '黄埔区-14'},
  680 + {id: '3-3-15', label: '黄埔区-15'},
  681 + {id: '3-3-16', label: '黄埔区-16'},
  682 + {id: '3-3-17', label: '黄埔区-17'},
  683 + {id: '3-3-18', label: '黄埔区-18'},
  684 + {id: '3-3-19', label: '黄埔区-19'},
  685 + {id: '3-3-20', label: '黄埔区-20'},
  686 + {id: '3-3-21', label: '黄埔区-21'},
  687 + {id: '3-3-22', label: '黄埔区-22'},
  688 + {id: '3-3-23', label: '黄埔区-23'},
  689 + {id: '3-3-24', label: '黄埔区-24'},
  690 + {id: '3-3-25', label: '黄埔区-25'},
  691 + {id: '3-3-26', label: '黄埔区-26'},
  692 + {id: '3-3-27', label: '黄埔区-27'},
  693 + {id: '3-3-28', label: '黄埔区-28'},
  694 + {id: '3-3-29', label: '黄埔区-29'},
  695 + {id: '3-3-30', label: '黄埔区-30'},
  696 + {id: '3-3-31', label: '黄埔区-31'},
  697 + {id: '3-3-32', label: '黄埔区-32'},
  698 + {id: '3-3-33', label: '黄埔区-33'},
  699 + {id: '3-3-34', label: '黄埔区-34'},
  700 + {id: '3-3-35', label: '黄埔区-35'},
  701 + {id: '3-3-36', label: '黄埔区-36'},
  702 + {id: '3-3-37', label: '黄埔区-37'},
  703 + {id: '3-3-38', label: '黄埔区-38'},
  704 + {id: '3-3-39', label: '黄埔区-39'},
  705 + {id: '3-3-40', label: '黄埔区-40'},
  706 + {id: '3-3-41', label: '黄埔区-41'},
  707 + {id: '3-3-42', label: '黄埔区-42'},
  708 + {id: '3-3-43', label: '黄埔区-43'},
  709 + {id: '3-3-44', label: '黄埔区-44'},
  710 + {id: '3-3-45', label: '黄埔区-45'},
  711 + {id: '3-3-46', label: '黄埔区-46'},
  712 + {id: '3-3-47', label: '黄埔区-47'},
  713 + {id: '3-3-48', label: '黄埔区-48'},
  714 + {id: '3-3-49', label: '黄埔区-49'},
  715 + {id: '3-3-50', label: '黄埔区-50'},
  716 + {id: '3-3-51', label: '黄埔区-51'},
  717 + {id: '3-3-52', label: '黄埔区-52'},
  718 + {id: '3-3-53', label: '黄埔区-53'},
  719 + {id: '3-3-54', label: '黄埔区-54'},
  720 + ]},
  721 + ],
  722 + }]
  723 +</script>
  724 +```
  725 +
  726 +### 预览
  727 +###
  728 +***
  729 +
  730 +| 功能预览 | 父子级关联演示 | 全面支持大数据量,子孙节点ui按需渲染(按需渲染数据) |
  731 +| :------------------------------------------------------------------: | :------------------------------------------------------------------: | :------------------------------------------------------------------: |
  732 +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-b.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-d.gif) |
  733 +
  734 +
  735 +
  736 +| 增强控件交互能力,增加筛选search模式,全面支持大数据量交互 | 超强的样式定制能力,满足你高精美组件的需求 | 打开精美的辅助线模式,让你的控件更加友好 |
  737 +| :------------------------------------------------------------------: | :------------------------------------------------------------------: | :------------------------------------------------------------------: |
  738 +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-e.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-f.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-u.gif) |
  739 +
  740 +
  741 +| 增加搜索模式searchModel=depHighlight模式,从属高亮显示模式 | 支持异步加载子节点,子树集,ajax远程加载数据等 | 支持不同主题的切换,ui定制更简单 |
  742 +| :------------------------------------------------------------------: | :------------------------------------------------------------------: | :------------------------------------------------------------------: |
  743 +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-p.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-k.gif) | ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-n.gif) |
  744 +
  745 +| 增加验证函数和topBar插槽使得更加容易和组件进行交互 | 增加页面模式,支持整页ui展示模式 |
  746 +| :------------------------------------------------------------------: | :------------------------------------------------------------------: |
  747 +| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-cc.gif)| ![](https://lixueshiaa.github.io/webtest/www/static/next-tree-uu.gif)|
  748 +## 参数
  749 +可选参数属性列表
  750 +
  751 +|参数名 |说明 |类型 |是否必填 |默认值 |可选值 |
  752 +|---- |---- |---- |---- |---- |---- |
  753 +|uiMode |ui表现方式;popup<弹窗>, page<页面>;默认是 popup |String |是 |popup |page |
  754 +|treeData |树源数据列表 |Array |是 |[] |- |
  755 +|valueKey |绑定value的键属性(项的唯一key标识) |String |否 |id |- |
  756 +|labelKey |用于显示的字段 |String |否 |label |- |
  757 +|disabledKey |禁用节点绑定属性 |String |否 |disabled |- |
  758 +|childrenKey |子节点绑定属性 |String |否 |children |- |
  759 +|title | 弹出标题(如果是函数时会返回所选项的值作为回调参数如;title: (checked):String => {}) |String, Function |否 |'' |- |
  760 +|multiple |是否可以多选 |Boolean |否 |false |true |
  761 +|selectParent |是否可以选父级 |Boolean |否 |false |true |
  762 +|foldAll| 折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开 |Boolean |否 |false |true |
  763 +|themeColor |主题颜色 |String |否 |#f9ae3d |- |
  764 +|cancelColor |取消按钮颜色 |String |否 |#757575 |- |
  765 +|titleColor |标题颜色 |String |否 |#757575 |- |
  766 +|border |是否有分割线 |Boolean |否 |false |true |
  767 +|checkStrictly|只有在multiple为true状态下生效; 状态下节点选择完全受控(父子节点选中状态不再关联) |Boolean |否 |false |true |
  768 +|checkStrictlyModel|只有在multiple为true状态下生效;父子节点关联模式:strong:强关联(不再受限节点的disabled控制),weak:弱关联(节点关联受disabled控制) |String |是 |weak |strong |
  769 +|showHalfCheckedTips|半选提示;只有在multiple为true, checkStrictly为false的状态下生效;父子节点选中状态不再关联,是否展示半选提示; |Boolean |否 |false |true |
  770 +|ifSearch| 筛选search模式 |Boolean |否 |true |false |
  771 +|searchModel| 搜索模式配置 depHighlight: 从属高亮(显示层级并高亮显示);common: 一般 |String |否 |common |depHighlight |
  772 +|showAuxiliaryLine| 是否打开辅助线 |Boolean |否 |false |true |
  773 +|loadData| 异步加载函数 (node):Promise([childData]) => {} // demo有说明 |Function |否 |- |- |
  774 +|height| 只在uiMode=popup时生效;弹层容器的高度,默认是500 |Number |否 |500 |- |
  775 +|changeVerify| 验证函数 (current as any, chooseList as any []):String => {} // 验证函数会把当前控件的选择值作为参数返给函数体,demo有说明 |Function |否 |- |- |
  776 +
  777 +
  778 +# Event 事件
  779 +|事件名 |说明 |类型 |回调参数 |
  780 +|---- |---- |---- |---- |
  781 +|confirm|菜单收起时返回的筛选结果 |emit |array |
  782 +|clear|点击清除按钮时触发 |emit |- |
  783 +|cancel|关闭弹层和点击取消时触发 |emit |- |
  784 +
  785 +## Slot 插槽
  786 +
  787 +|名称 |说明 |参数 |
  788 +|---- |---- |---- |
  789 +|label |label插槽 |data(当前项对于treeData里面的数据) |
  790 +|topBar |topBar插槽 |----滚动区域顶部topBar插槽 |
  791 +|bottomBar |bottomBar插槽 |----滚动区域底部bottomBar插槽 |
  792 +|fixedBottomBar |fixedBottomBar插槽 |----固定在页面的底部,使用fixed进行定位 |
  793 +|empty |empty插槽 |----数据为空的插槽 |
  794 +
... ...
garbage-removal/src/components/next-tree/style.css 0 → 100644
  1 +.next-tree-mask {
  2 + position: fixed;
  3 + top: 0rpx;
  4 + right: 0rpx;
  5 + bottom: 0rpx;
  6 + left: 0rpx;
  7 + z-index: 997;
  8 + background-color: rgba(0, 0, 0, 0.6);
  9 + opacity: 0;
  10 + transition: all 0.3s ease;
  11 + visibility: hidden;
  12 +}
  13 +.next-tree-mask.show {
  14 + visibility: visible;
  15 + opacity: 1;
  16 +}
  17 +.next-tree-cnt {
  18 + position: fixed;
  19 + top: 0rpx;
  20 + right: 0rpx;
  21 + bottom: 0rpx;
  22 + left: 0rpx;
  23 + z-index: 997;
  24 + top: 360rpx;
  25 + transition: all 0.3s ease;
  26 + transform: translateY(100%);
  27 +}
  28 +.next-tree-cnt.next-tree-cnt-page {
  29 + transition: none;
  30 +}
  31 +.next-tree-cnt.show {
  32 + transform: translateY(0);
  33 +}
  34 +.next-tree-bar {
  35 + background-color: #fff;
  36 + height: 72rpx;
  37 + padding-left: 20rpx;
  38 + padding-right: 20rpx;
  39 + display: flex;
  40 + justify-content: space-between;
  41 + align-items: center;
  42 + box-sizing: border-box;
  43 + border-bottom-width: 1rpx !important;
  44 + border-bottom-style: solid;
  45 + border-bottom-color: #f5f5f5;
  46 + font-size: 32rpx;
  47 + color: #757575;
  48 + line-height: 1;
  49 +}
  50 +.next-tree-bar-btns {
  51 + display: inline-block;
  52 + display: flex;
  53 + flex-direction: row;
  54 +}
  55 +.btn-divid {
  56 + display: inline-block;
  57 + width: 1px;
  58 + margin: 0 10px;
  59 + background-color: #ccc;
  60 +}
  61 +.next-tree-bar-confirm {
  62 + color: #f9ae3d;
  63 +}
  64 +.next-tree-view {
  65 + position: absolute;
  66 + top: 0rpx;
  67 + right: 0rpx;
  68 + bottom: 0rpx;
  69 + left: 0rpx;
  70 + top: 72rpx;
  71 + background-color: #fff;
  72 + padding-top: 20rpx;
  73 + padding-right: 20rpx;
  74 + padding-bottom: 20rpx;
  75 + padding-left: 20rpx;
  76 +}
  77 +.next-tree-view-sc {
  78 + height: 100%;
  79 + overflow: hidden;
  80 +}
  81 +.next-tree-view-sc .empty {
  82 + text-align: center;
  83 + color: #757575;
  84 + padding: 30rpx;
  85 +}
  86 +.next-tree-item-block {
  87 +
  88 +}
  89 +.next-tree-item {
  90 + display: flex;
  91 + justify-content: space-between;
  92 + align-items: center;
  93 + font-size: 26rpx;
  94 + color: #757575;
  95 + line-height: 1;
  96 + height: 0;
  97 + opacity: 0;
  98 + transition: 0.2s;
  99 + position: relative;
  100 + overflow: hidden;
  101 +}
  102 +.next-tree-item .left-line {
  103 + position: relative;
  104 + width: 1rpx;
  105 + height: 100%;
  106 + box-sizing: border-box;
  107 +}
  108 +.next-tree-item .left-line::before {
  109 + position: absolute;
  110 + content: "";
  111 + width: 1rpx;
  112 + height: 100%;
  113 + background-color: rgba(204,204,204,0.9);
  114 + box-sizing: border-box;
  115 +
  116 + left: -18rpx;
  117 +}
  118 +.next-tree-item .parent-horizontal-line {
  119 + width: 1rpx;
  120 + height: 100%;
  121 + position: absolute;
  122 + top: 0;
  123 + left: 0rpx;
  124 + box-sizing: border-box;
  125 + background-color: rgba(204,204,204,0.9);
  126 +}
  127 +.next-tree-item .left-line .horizontal-line {
  128 + width: 20rpx;
  129 + height: 1rpx;
  130 + position: absolute;
  131 + top: 40rpx;
  132 + left: 0rpx;
  133 + background-color: rgba(204,204,204,0.9);
  134 + box-sizing: border-box;
  135 +}
  136 +
  137 +.next-tree-item.show {
  138 + height: 80rpx;
  139 + opacity: 1;
  140 +}
  141 +.next-tree-item.showchild:before {
  142 + transform: rotate(90deg);
  143 +}
  144 +.next-tree-item.border {
  145 + border-bottom: 1rpx solid rgba(204,204,204,0.2);
  146 +}
  147 +.next-tree-item.last:before {
  148 + opacity: 0;
  149 +}
  150 +.next-tree-item.disabled {
  151 + color: #ccc!important;
  152 +}
  153 +
  154 +.next-tree-icon {
  155 + width: 26rpx;
  156 + height: 26rpx;
  157 + margin-right: 8rpx;
  158 +}
  159 +.next-tree-label {
  160 + flex: 1;
  161 + display: flex;
  162 + align-items: center;
  163 + height: 100%;
  164 + line-height: 1.2;
  165 +}
  166 +.next-tree-check {
  167 + width: 40px;
  168 + height: 40px;
  169 + display: flex;
  170 + justify-content: center;
  171 + align-items: center;
  172 +}
  173 +.next-tree-check-yes,
  174 +.next-tree-check-no {
  175 + width: 20px;
  176 + height: 20px;
  177 + border-top-left-radius: 20%;
  178 + border-top-right-radius: 20%;
  179 + border-bottom-right-radius: 20%;
  180 + border-bottom-left-radius: 20%;
  181 + border-top-width: 1rpx;
  182 + border-left-width: 1rpx;
  183 + border-bottom-width: 1rpx;
  184 + border-right-width: 1rpx;
  185 + border-style: solid;
  186 + border-color: #f9ae3d;
  187 + display: flex;
  188 + justify-content: center;
  189 + align-items: center;
  190 + box-sizing: border-box;
  191 +}
  192 +.next-tree-check-yes-b {
  193 + border-top-left-radius: 20%;
  194 + border-top-right-radius: 20%;
  195 + border-bottom-right-radius: 20%;
  196 + border-bottom-left-radius: 20%;
  197 + background-color: #f9ae3d;
  198 + color: #fff;
  199 +}
  200 +.next-tree-check-yes-b .icon-text {
  201 + font-size: 14px;
  202 + font-weight: normal;
  203 + font-family: uicon-iconfont;
  204 + display: flex;
  205 + flex-direction: row;
  206 + align-items: center;
  207 +}
  208 +.next-tree-check .radio {
  209 + border-top-left-radius: 50%;
  210 + border-top-right-radius: 50%;
  211 + border-bottom-right-radius: 50%;
  212 + border-bottom-left-radius: 50%;
  213 +}
  214 +.next-tree-check .radio .next-tree-check-yes-b {
  215 + border-top-left-radius: 50%;
  216 + border-top-right-radius: 50%;
  217 + border-bottom-right-radius: 50%;
  218 + border-bottom-left-radius: 50%;
  219 +}
  220 +
  221 +.next-tree-item.disabled .next-tree-check-no {
  222 + color: #ccc!important;
  223 +}
  224 +.next-tree-item.disabled .next-tree-check-yes-b {
  225 + background-color: #ccc!important;
  226 +}
  227 +.hover-c {
  228 + opacity: 0.6;
  229 +}
  230 +
  231 +.fixed-bottom-bar {
  232 + position: fixed;
  233 + bottom: 0rpx;
  234 + left: 0rpx;
  235 + right: 0rpx;
  236 + z-index: 998;
  237 +}
  238 +
  239 +
... ...
garbage-removal/src/main.js
... ... @@ -9,11 +9,9 @@ import App from &quot;./App.vue&quot;;
9 9 // 拦截器
10 10 let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"];
11 11 list.forEach(item => { //用遍历的方式分别为,uni.navigateTo,uni.redirectTo,uni.reLaunch,uni.switchTab这4个路由方法添加拦截器
12   - console.log(item, 'router list item')
13 12 uni.addInterceptor(item, {
14 13 invoke(e) { // 调用前拦截
15 14 //获取用户的token
16   - console.log(e, 'routerjs invoke')
17 15 const flag = uni.getStorageSync('cancelFlag');
18 16 //获取当前页面路径(即url去掉"?"和"?"后的参数)
19 17 if (flag) {
... ...
garbage-removal/src/pages.json
... ... @@ -52,6 +52,14 @@
52 52 "enablePullDownRefresh": false
53 53 }
54 54 },{
  55 + "path": "pages/order/success/index",
  56 + "style": {
  57 + "navigationBarTitleText": "完成派单",
  58 + "navigationBarTextStyle": "white",
  59 + "navigationBarBackgroundColor": "#53c21d",
  60 + "enablePullDownRefresh": false
  61 + }
  62 + },{
55 63 "path": "pages/order/guest/index",
56 64 "style": {
57 65 "navigationBarTitleText": "详情",
... ...
garbage-removal/src/pages/home/address/addSite.vue
... ... @@ -5,7 +5,7 @@
5 5 <u--form :labelStyle="{ color: '#909399' }" labelPosition="left" labelWidth="140" :model="addressInfo"
6 6 ref="addressFrom">
7 7 <u-form-item :required="true" label="所在地区" prop="addressArea" borderBottom>
8   - <view @click="showRegionPicker" class="input-box">
  8 + <view @click.stop="showRegionPicker" hover-class="click-box">
9 9 <u--input border="none" readonly style="pointer-events:none" type="text" v-model="addressInfo.addressArea"
10 10 placeholder-class="line" placeholder="省市区县、乡镇等"></u--input>
11 11 </view>
... ... @@ -38,10 +38,10 @@
38 38 </view>
39 39 </view>
40 40 <view class="submit-button">
41   - <view v-if="addFlag" @click="submit" class="add">新增地址</view>
  41 + <view v-if="addFlag" @click="submit" class="add" hover-class="click-box">新增地址</view>
42 42 <view v-else class="update-box">
43   - <view class="del" @click="handleDeleteClick">删除地址</view>
44   - <view class="update" @click="handleUpdateClick">保存地址</view>
  43 + <view class="del" @click="handleDeleteClick" hover-class="click-box">删除地址</view>
  44 + <view class="update" @click="handleUpdateClick" hover-class="click-box">保存地址</view>
45 45 </view>
46 46 </view>
47 47 </view>
... ... @@ -239,9 +239,7 @@ const reset = () =&gt; {
239 239 }
240 240 }
241 241  
242   - .input-box {
243   - @include handleClick;
244   - }
  242 +
245 243  
246 244  
247 245 .submit-button {
... ... @@ -291,7 +289,9 @@ const reset = () =&gt; {
291 289  
292 290 }
293 291 }
  292 +}
294 293  
295   -
  294 +.click-box {
  295 + @include handleClick;
296 296 }
297 297 </style>
... ...
garbage-removal/src/pages/home/address/index.vue
... ... @@ -18,7 +18,7 @@
18 18 </view>
19 19  
20 20 </view>
21   - <view class="addSite" @tap="toAddSite">
  21 + <view class="addSite" @click.stop="toAddSite" hover-class="click-box">
22 22 <view class="add">添加地址</view>
23 23 </view>
24 24 </view>
... ... @@ -166,4 +166,8 @@ onShow(() =&gt; {
166 166 }
167 167 }
168 168 }
  169 +
  170 +.click-box {
  171 + @include handleClick;
  172 +}
169 173 </style>
... ...
garbage-removal/src/pages/home/clean/index.vue
1 1 <template>
2   - <liu-delivery-time :isMask="true" :change="changeTime" ref="chooseTime" title="请选择预约时间"></liu-delivery-time>
  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"></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>
3 41 <view class="company-clean-container">
4 42 <view class="company-clean-container-box">
5 43 <view class="company-clean-container-header">
... ... @@ -21,34 +59,42 @@
21 59 </view>
22 60 <view class="company-clean-container-car-main">
23 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>
24 72 <view class="company-clean-container-car-main-content-type">
25 73 <text class="company-clean-container-car-main-content-type-price-area"><text
26 74 style="color: red;">*</text>垃圾类型:</text>
27   - <uni-combox label="" :candidates="garbageTypeList" placeholder="请选择垃圾类型"
28   - v-model="paramFrom.garbageType"></uni-combox>
  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>
29 79 </view>
30   - <!-- <view class="company-clean-container-car-main-content-img">
31   - <image class="company-clean-container-car-main-content-img" />
  80 + <view class="company-clean-container-car-main-content-img">
  81 + <image class="company-clean-container-car-main-content-img" :src="carFront" />
32 82 </view>
33 83 <view class="company-clean-container-car-main-content-remark">
34   - 箱体长4.2m宽1.1,高0.7,最多课容纳约110袋袋装修垃圾(75cm*45每袋)
35   - </view> -->
36   - <view class="company-clean-container-car-main-content-type">
37   - <text class="company-clean-container-car-main-content-type-price-area"><text
38   - style="color: red;">*</text>车辆类型:</text>
39   - <uni-combox label="" :candidates="candidates" placeholder="请选择运输车辆类型"
40   - v-model="paramFrom.carType"></uni-combox>
  84 + {{ garCarTransportInfo }}
41 85 </view>
42   - <view class="company-clean-container-car-main-content-number">
  86 +
  87 + <view v-if="paramFrom.carType" class="company-clean-container-car-main-content-number">
43 88 <view class="company-clean-container-car-main-content-number-txt">
44 89 <text style="color: red;">*</text>添加车辆数量
45 90 </view>
46 91 <view class="company-clean-container-car-main-content-number-button">
47   - <u-number-box :min="1" integer buttonSize="46" v-model="paramFrom.carNumber"></u-number-box>
  92 + <u-number-box :min="0" :max="9999" integer buttonSize="46" :inputWidth="100"
  93 + v-model="garCarInfoList[paramFrom.carType].garOrderCarNumber"></u-number-box>
48 94 </view>
49 95 </view>
50 96 <view class="company-clean-container-car-main-content-prompt">
51   - 温馨提示:垃圾类型不符合,有权拒绝清运。
  97 + 温馨提示:垃圾类型不符合,企业有权拒绝清运。
52 98 </view>
53 99 </view>
54 100 </view>
... ... @@ -77,8 +123,8 @@
77 123 </view>
78 124 </view>
79 125 </view>
80   - <view class="company-clean-bottom">
81   - <movable-area ref="movableAreaElement" class="movableArea">
  126 + <view class="company-clean-bottom" style="z-index: 10074;">
  127 + <movable-area v-if="!carPopupShowFlag" ref="movableAreaElement" class="movableArea">
82 128 <movable-view class="movableView" :x="x" :y="y" direction="all" @change="onChange">
83 129 <view class="company-clean-call-box-container">
84 130 <u-icon @click="handleContactClick(tel)" name="phone-fill" color="#ffffff" size="50"></u-icon>
... ... @@ -87,7 +133,12 @@
87 133 </movable-area>
88 134 <view class="company-clean-bottom-box">
89 135 <view class="company-clean-bottom-left">
90   - <u-icon @click="handleCarInfo" :stop="true" size="50" name="car-fill"></u-icon>
  136 + <view class="company-clean-bottom-left-icon">
  137 + <u-icon @click="carPopupShowFlag = true" :stop="true" size="50" name="car-fill"></u-icon>
  138 + </view>
  139 + <view class="company-clean-bottom-left-number">
  140 + <up-badge :type="type" max="99" :value="garCarNumberCount"></up-badge>
  141 + </view>
91 142 </view>
92 143 <view class="company-clean-bottom-right">
93 144 <u-button @click="handleOderSure" shape="circle" color="#a9e08f" text="立即派单"></u-button>
... ... @@ -102,24 +153,66 @@ import { queryCarList } from &#39;@/apis/carinfo.js&#39;;
102 153 import { uploadFilePromise } from '@/apis/common.js';
103 154 import { saveOrder } from '@/apis/order.js';
104 155 import liuDeliveryTime from "@/components/liu-delivery-time/liu-delivery-time.vue";
105   -import uniCombox from "@/components/uni-combox/index.vue";
  156 +import { useMainStore } from '@/stores/index.js';
106 157 import { onLoad } from '@dcloudio/uni-app';
107   -import { getCurrentInstance, onMounted, ref } from 'vue';
  158 +import { computed, getCurrentInstance, nextTick, ref, watch } from 'vue';
108 159 const { proxy } = getCurrentInstance();
  160 +
  161 +const store = useMainStore();
  162 +const userType = computed(() => store.userType)
109 163 const x = ref(5)
110 164 const y = ref()
111 165 const movableAreaElement = ref()
112 166 const companyObj = ref()
113 167 const tel = ref()
  168 +const carTypeShowFlag = ref(false)
  169 +const garbageTypeShowFlag = ref(false)
  170 +const carPopupShowFlag = ref(false)
114 171 const userAddress = ref({
115 172 garUserContactName: "",
116 173 garUserContactTel: "",
117 174 garRemark: "",
118 175 garUserAddress: ""
119 176 })
120   -const garbageTypeList = ref(["建筑垃圾", "装修垃圾"])
  177 +// 车辆信息
  178 +const garCarInfoList = ref({})
  179 +const garCarLabelInfoList = ref({})
  180 +const garCarLabelInfoNow = ref()
  181 +const garCarTransportInfo = computed(() => {
  182 + try {
  183 + let carInfo = garCarLabelInfoNow.value
  184 + let lengthWidthHeight = carInfo.lengthWidthHeight.split(";");
  185 + let boxLength = lengthWidthHeight[0]; // 箱子的长度(单位:米)
  186 + let boxWidth = lengthWidthHeight[1]; // 箱子的宽度(单位:米)
  187 + let boxHeight = lengthWidthHeight[2]; // 箱子的高度(单位:米)
  188 +
  189 + let bagLength = 0.75; // 袋子的长度(单位:米)
  190 + let bagWidth = 0.45; // 袋子的宽度(单位:米)
  191 + let bagHeight = 0.22; // 袋子的高度(单位:米)
  192 +
  193 + let boxVolume = boxLength * boxWidth * boxHeight; // 箱子的体积(单位:立方米)
  194 + let bagVolume = bagLength * bagWidth * bagHeight; // 袋子的体积(单位:立方米)
  195 +
  196 + let bagCount = Math.floor(boxVolume / bagVolume); // 箱子可以容纳的袋子数量(向下取整)
  197 +
  198 + return `箱体长${boxLength}m宽${boxWidth}m高${boxHeight}m,最多课容纳约${bagCount}袋袋装修垃圾(75cm * 45cm每袋)。`
  199 + } catch (error) {
  200 + return "符合装修垃圾运输管理规范的新型环保智能装修垃圾运输车。"
  201 + }
  202 +
  203 +})
  204 +// 车辆数量
  205 +const garCarNumberCount = computed(() => {
  206 + let count = 0;
  207 + for (const key in garCarInfoList.value) {
  208 + const element = garCarInfoList.value[key];
  209 + count += element.garOrderCarNumber;
  210 + }
  211 + return count;
  212 +})
  213 +const garbageTypeList = ref([["装修垃圾", "建筑垃圾"]])
121 214 const paramFrom = ref({
122   - carNumber: 1,
  215 + carNumber: 0,
123 216 remark: "",
124 217 sureReadFlag: [],
125 218 carType: "",
... ... @@ -143,18 +236,48 @@ const changeAgree = (e) =&gt; {
143 236 const onChange = (e) => {
144 237 // console.log(e);
145 238 }
  239 +
  240 +const handlePopupClick = (val) => {
  241 + carPopupShowFlag.value = val
  242 +}
  243 +
146 244 /**
147 245 * 初始化信息
148 246 */
149 247 onLoad((options) => {
  248 +
150 249 companyObj.value = JSON.parse(options.companyObj);
151 250 tel.value = options.tel;
152 251 userAddress.value = JSON.parse(options.userAddress);
153 252 queryCarList({ companyId: companyObj.value.id }).then(res => {
154   - candidates.value = [...new Set(res.data.rows.map(item => item.carType))];
  253 + // 设置车辆类型
  254 + candidates.value = [[...new Set(res.data.rows
  255 + .filter(item => item.containerVolume)
  256 + .map(item => {
  257 + garCarLabelInfoList.value[item.containerVolume + "方车"] = item
  258 + return item.containerVolume + "方车"
  259 + }))
  260 + ]];
  261 + // 设置初始车辆数量
  262 + candidates.value[0].forEach((item, index) => {
  263 + garCarInfoList.value[item] = {
  264 + garOrderCarNumber: 0,
  265 + garOrderCarType: item
  266 + }
  267 + })
  268 + // 设置默认车辆
  269 + paramFrom.value.carType = candidates.value[0][0];
  270 + garCarLabelInfoNow.value = garCarLabelInfoList.value[paramFrom.value.carType]
155 271 })
156 272 })
157 273  
  274 +
  275 +const handleCarInfoClick = (val) => {
  276 + carTypeShowFlag.value = val
  277 +}
  278 +const handleGarbageTypeClick = (val) => {
  279 + garbageTypeShowFlag.value = val
  280 +}
158 281 /**
159 282 * 拨打电话回调
160 283 */
... ... @@ -195,18 +318,26 @@ const afterRead = async (event) =&gt; {
195 318 };
196 319  
197 320  
198   -
199   -/**
200   - * 处理车子数量
201   - */
202   -const handleCarInfo = () => {
203   -
  321 +const handlePickerGarbageTypeConfirm = (e) => {
  322 + paramFrom.value.garbageType = e.value
  323 + garbageTypeShowFlag.value = false
  324 +}
  325 +const handlePickerCarInfoConfirm = (e) => {
  326 + paramFrom.value.carType = e.value
  327 + garCarLabelInfoNow.value = garCarLabelInfoList.value[paramFrom.value.carType]
  328 + carTypeShowFlag.value = false
  329 + console.log(garCarLabelInfoNow.value);
204 330 }
205 331  
206 332 /**
207 333 * 处理下单
208 334 */
209 335 const handleOderSure = () => {
  336 + let garCarInfos = [];
  337 + for (const key in garCarInfoList.value) {
  338 + garCarInfos.push(garCarInfoList.value[key])
  339 + }
  340 +
210 341 let params = {
211 342 /**
212 343 * 派单地址
... ... @@ -222,8 +353,7 @@ const handleOderSure = () =&gt; {
222 353 * 派单姓名
223 354 */
224 355 garOrderContactName: userAddress.value.garUserContactName,
225   - garOrderCarNumber: paramFrom.value.carNumber,
226   - garOrderCarType: paramFrom.value.carType,
  356 + garCarInfoList: garCarInfos,
227 357  
228 358 /**
229 359 * 垃圾类型
... ... @@ -248,7 +378,7 @@ const handleOderSure = () =&gt; {
248 378 /**
249 379 * 公司负责人电话
250 380 */
251   - garOrderCompanyTel: companyObj.value.safetyManagerPhone,
  381 + garOrderCompanyTel: companyObj.value.servicePhone,
252 382  
253 383 /**
254 384 * 约定时间
... ... @@ -266,34 +396,32 @@ const handleOderSure = () =&gt; {
266 396 if (!validateParams(params)) {
267 397 return;
268 398 }
  399 +
269 400 saveOrder(params).then(res => {
270 401 // TODO 派单详情
271 402 if (res.data.success) {
272   - uni.$u.route({
273   - type: "redirect",
274   - url: `pages/order/detail/index`,
275   - params: {
276   - orderId: res.data.data
277   - }
278   - })
  403 + if (userType.value === "运输驾驶员") {
  404 + uni.$u.toast("派单成功,请切换成且角色查看订单详情")
  405 + setTimeout(() => {
  406 + uni.navigateBack({
  407 + delta: 1,
  408 + })
  409 + }, 50)
  410 + } else {
  411 + uni.$u.route({
  412 + type: "redirect",
  413 + url: `pages/order/detail/index`,
  414 + params: {
  415 + orderId: res.data.data
  416 + }
  417 + })
  418 + uni.$u.toast(res.data.msg)
  419 + }
  420 +
279 421 }
280   - uni.$u.toast(res.data.msg)
281 422 })
282   -
283 423 }
284 424  
285   -onMounted(() => {
286   - let areaHeight;
287   - // select中的参数就如css选择器一样选择元素
288   - let movableArea = uni.createSelectorQuery().in(proxy).select(".movableArea");
289   - movableArea.boundingClientRect(function (data) {
290   - // data - 包含元素的高度等信息
291   - areaHeight = data.height;
292   - y.value = areaHeight > 20 ? (areaHeight - 20) : areaHeight;
293   - }).exec(function (res) {
294   - // 注意:exec方法必须执行,即便什么也不做,否则不会获取到任何数据
295   - })
296   -})
297 425  
298 426 /**
299 427 * 校验参数
... ... @@ -310,15 +438,21 @@ const validateParams = (params) =&gt; {
310 438 case "garOrderAgreementTime":
311 439 jumpPrompt('请选择预约时间')
312 440 break;
313   - case "garOrderTrashType":
314   - jumpPrompt('请选择垃圾类型')
315   - break;
316   - case "garOrderCarType":
317   - jumpPrompt('请选择车辆类型')
318   - break;
  441 +
319 442 }
320 443 return false;
321 444 }
  445 + if (key === "garCarInfoList") {
  446 + let count = 0;
  447 + params[key].forEach(item => {
  448 + count += item.garOrderCarNumber;
  449 + })
  450 + if (count === 0) {
  451 + jumpPrompt('请添加车辆数量')
  452 + return false;
  453 + }
  454 + }
  455 +
322 456 if (key == "imageUrls") {
323 457 if (params[key].length == 0) {
324 458 jumpPrompt('请上传现场图片')
... ... @@ -355,6 +489,31 @@ const validateImage = (fileList) =&gt; {
355 489 return true;
356 490 }
357 491  
  492 +
  493 +// 开始执行一次
  494 +watch(carPopupShowFlag, (val) => {
  495 + // console.log(val);
  496 + // carPopupShowFlag.value = val
  497 + if (!val) {
  498 + setTimeout(() => {
  499 + nextTick(() => {
  500 + let areaHeight;
  501 + // select中的参数就如css选择器一样选择元素
  502 + let movableArea = uni.createSelectorQuery().in(proxy).select(".movableArea");
  503 + movableArea.boundingClientRect(function (data) {
  504 + // data - 包含元素的高度等信息
  505 + areaHeight = data.height;
  506 + y.value = areaHeight > 40 ? (areaHeight - 40) : areaHeight;
  507 + }).exec(function (res) {
  508 + // 注意:exec方法必须执行,即便什么也不做,否则不会获取到任何数据
  509 + })
  510 + })
  511 + }, 0);
  512 + }
  513 +}, {
  514 + immediate: true
  515 +})
  516 +
358 517 </script>
359 518  
360 519 <style lang="scss" scoped>
... ... @@ -363,6 +522,7 @@ $custom-page-padding: 20rpx;
363 522 $custom-border-radio: 20rpx;
364 523 $custom-bottom-height: 200rpx;
365 524  
  525 +
366 526 .company-clean-container {
367 527 height: 100%;
368 528 width: 100%;
... ... @@ -546,6 +706,8 @@ $custom-bottom-height: 200rpx;
546 706 // height: 100%;
547 707 bottom: 0;
548 708 left: 0;
  709 + // 阴影
  710 + box-shadow: 0 0 10rpx 0 rgba(0, 0, 0, 0.1);
549 711  
550 712 .movableArea {
551 713 pointer-events: none;
... ... @@ -583,7 +745,12 @@ $custom-bottom-height: 200rpx;
583 745 align-items: center;
584 746  
585 747 .company-clean-bottom-left {
586   - transform: rotateY(180deg);
  748 + display: flex;
  749 +
  750 + .company-clean-bottom-left-icon {
  751 + transform: rotateY(180deg);
  752 + }
  753 +
587 754 }
588 755  
589 756 .company-clean-bottom-right {
... ... @@ -594,5 +761,53 @@ $custom-bottom-height: 200rpx;
594 761 }
595 762  
596 763  
  764 +
  765 +}
  766 +
  767 +.hoverClickStyle {
  768 + @include handleClick;
  769 +}
  770 +
  771 +// 弹出框
  772 +.company-clean-container-car-popup {
  773 + min-height: 450rpx;
  774 + padding: $custom-page-padding;
  775 + box-sizing: border-box;
  776 +
  777 + .company-clean-container-car-popup-content {
  778 + font-size: 28rpx;
  779 +
  780 + .company-clean-container-car-popup-content-box {
  781 + box-sizing: border-box;
  782 + padding: $custom-page-padding;
  783 + border: 2rpx solid #a9e08f;
  784 + border-radius: 10rpx;
  785 +
  786 + .company-clean-container-car-popup-content-box-item {
  787 + display: flex;
  788 + align-items: center;
  789 + justify-content: space-between;
  790 + margin: 20rpx 0;
  791 + box-sizing: border-box;
  792 +
  793 + .company-clean-container-car-popup-content-box-item-text {}
  794 +
  795 + .company-clean-container-car-popup-content-box-item-number {}
  796 + }
  797 + }
  798 +
  799 + .company-clean-container-car-popup-content-title {
  800 + color: $u-main-color;
  801 + box-sizing: border-box;
  802 + margin-bottom: 20rpx;
  803 + font-size: 30rpx;
  804 + font-weight: bold;
  805 + }
  806 + }
  807 +
  808 + .company-clean-container-car-popup-button-safe {
  809 + width: 100%;
  810 + height: $custom-bottom-height;
  811 + }
597 812 }
598 813 </style>
... ...
garbage-removal/src/pages/home/index.vue
... ... @@ -47,24 +47,25 @@
47 47 :src="item.carParkPanorama ? item.carParkPanorama : 'https://ijry.github.io/uview-plus/h5/assets/logo-8d54bbeb.png'" />
48 48 </view>
49 49 <view class="company-list-item-main-right"
50   - @click="handleDetailClick(item, item.legalRepresentativePhone, userAddress)">
  50 + @click="handleDetailClick(item, item.service_phone, userAddress)">
51 51 <view class="company-list-item-main-right-name">
52 52 {{ item.name }}
53 53 </view>
54 54 <view class="company-list-item-main-right-score">
55 55 <text class="company-list-item-main-right-text">评分:</text>
56 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"
58   - color="#f9ae3d" size="28"></u-icon>
  57 + <!-- <u-icon v-for="todo in maxStar" :name="item.score > todo ? 'star-fill' : 'star'" :key="todo"
  58 + color="#f9ae3d" size="28"></u-icon> -->
  59 + <u-rate activeColor="#f9ae3d" inactive-color="#f9ae3d" size="28" :modelValue="item.score"
  60 + allowHalf readonly></u-rate>
59 61 </view>
60 62 <text v-if="item.score > 0" class="company-list-item-main-right-text" style="color: #fd5d00;">{{
61 63 item.score }}分</text>
62 64 <text v-else class="company-list-item-main-right-text" style="color: #fd5d00;">最近一月暂无评分</text>
63 65 </view>
64 66 <view class="company-list-item-main-right-price-number">
65   - <view class="company-list-item-main-right-price">公司类型:{{ item.companyType == 0 ? "经营单位" :
66   - "运输公司"
67   - }}&nbsp;&nbsp;</view>
  67 + <view class="company-list-item-main-right-price">报价:<text
  68 + style="color: #fd5d00;">¥400起&nbsp;&nbsp;</text></view>
68 69 <view class="company-list-item-main-right-number">
69 70 清运数:<text class="company-list-item-main-right-number-text">{{ item.cleanNumber }}</text>
70 71 </view>
... ... @@ -76,12 +77,12 @@
76 77 </view>
77 78 <view class="company-list-item-bottom">
78 79 <view class="company-list-item-bottom-contact-company">
79   - <u-button @click="handleContactClick(item.legalRepresentativePhone)" color="#a9e08f" size="normal"
  80 + <u-button @click="handleContactClick(item.service_phone)" color="#a9e08f" size="normal"
80 81 type="success" :hairline="true" shape="circle" text="联系公司"></u-button>
81 82 </view>
82 83 <view class="company-list-item-bottom-button-clean">
83   - <u-button @click="handleCleanGarbage(item, item.legalRepresentativePhone, userAddress)"
84   - type="success" :hairline="true" size="normal" shape="circle" text="垃圾清运"></u-button>
  84 + <u-button @click="handleCleanGarbage(item, item.service_phone, userAddress)" type="success"
  85 + :hairline="true" size="normal" shape="circle" text="垃圾清运"></u-button>
85 86 </view>
86 87 </view>
87 88 </view>
... ... @@ -281,7 +282,7 @@ const initData = () =&gt; {
281 282 }
282 283 const queryList = (pageNo, pageSize) => {
283 284 // 查询公司信息
284   - queryEnterpriseList({ companyType: 0, pageNum: pageNo, pageSize }).then(res => {
  285 + queryEnterpriseList({ companyType: 1, pageNum: pageNo, pageSize }).then(res => {
285 286 paging.value.complete(res.data.data.list);
286 287 })
287 288 }
... ... @@ -510,6 +511,7 @@ const queryList = (pageNo, pageSize) =&gt; {
510 511 }
511 512  
512 513 .company-list-item-main-right {
  514 + flex: auto;
513 515 display: flex;
514 516 flex-direction: column;
515 517 flex-wrap: wrap;
... ... @@ -543,14 +545,16 @@ const queryList = (pageNo, pageSize) =&gt; {
543 545  
544 546 .company-list-item-main-right-price-number {
545 547 display: flex;
546   - justify-content: space-around;
  548 + justify-content: space-between;
547 549 align-items: center;
548 550  
549 551 .company-list-item-main-right-price {}
550 552  
551 553 .company-list-item-main-right-number {
  554 + flex: auto;
552 555 font-size: small;
553 556  
  557 +
554 558 .company-list-item-main-right-number-text {
555 559 color: $u-main-color;
556 560 }
... ...
garbage-removal/src/pages/login/index.vue
... ... @@ -104,7 +104,6 @@ export default {
104 104 console.log(res);
105 105 })
106 106 }
107   -
108 107 });
109 108 }
110 109 }
... ...
garbage-removal/src/pages/order/detail/index.vue
1 1 <template>
  2 + <clashDispatch ref="clashDispatchRef" :valueKey="'licensePlateNumber'" :onconfirm="handleDispatchConfirm"
  3 + :dataList="personnelList">
  4 + </clashDispatch>
2 5 <view class="order-detail-container" v-if="dataGram != null || dataGram != undefined">
3 6 <view class="order-detail-container-box">
4 7 <view class="order-detail-top">
... ... @@ -46,12 +49,6 @@
46 49 </view>
47 50 </view>
48 51 <view class="order-detail-container-header-item">
49   - <text class="order-detail-container-header-title">车辆类型:</text>
50   - <view class="order-detail-container-header-content">
51   - {{ dataGram.garOrderCarType }}({{ dataGram.garOrderCarNumber }}辆)
52   - </view>
53   - </view>
54   - <view class="order-detail-container-header-item">
55 52 <text class="order-detail-container-header-title">垃圾类型:</text>
56 53 <view class="order-detail-container-header-content">
57 54 {{ dataGram.garOrderTrashType }}
... ... @@ -67,7 +64,23 @@
67 64 <view @click="handleQrCodeClick(orderId)" class="iconfont icon-erweima-xian"></view>
68 65 </view>
69 66 </view>
70   -
  67 + </view>
  68 + <!-- 车辆信息 -->
  69 + <view class="order-detail-container-box-card">
  70 + <view class="order-detail-container-header-card-title">
  71 + <view class="order-detail-container-header-card-uicon"></view>
  72 + 车辆信息
  73 + </view>
  74 + <view class="order-detail-container-header-item" style="justify-content: space-between;"
  75 + v-for="(item) in dataGram.garCarInfoList" :key="item.garId">
  76 + <text class="order-detail-container-header-title" style="color: #303133;">{{ item.garOrderCarType }}
  77 + </text>
  78 + <view class="order-detail-container-header-content">
  79 + <text class="order-detail-container-header-title">
  80 + {{ cleanStatus(dataGram.garOrderHandlerStatus) }}
  81 + </text>
  82 + </view>
  83 + </view>
71 84 </view>
72 85 <!-- 派单记录 -->
73 86 <view class="order-detail-container-box-card">
... ... @@ -82,7 +95,7 @@
82 95 </view>
83 96 </view> -->
84 97 <view class="order-detail-container-header-item">
85   - <text class="order-detail-container-header-title">约定时间:</text>
  98 + <text class="order-detail-container-header-title">预约时间:</text>
86 99 <view class="order-detail-container-header-content">
87 100 {{ dataGram.garOrderAgreementTime }}
88 101 </view>
... ... @@ -117,27 +130,27 @@
117 130 处理信息
118 131 </view>
119 132 <view v-if="dataGram.garOrderHandlerId" style="width: 100%;">
120   - <view class="order-detail-container-header-item">
  133 + <!-- <view class="order-detail-container-header-item">
121 134 <text class="order-detail-container-header-title">负责人:</text>
122 135 <view class="order-detail-container-header-content">
123 136 {{ dataGram.garOrderHandleName }}
124 137 </view>
125   - </view>
  138 + </view> -->
126 139 <view class="order-detail-container-header-item">
127   - <text class="order-detail-container-header-title">联系方式:</text>
  140 + <text class="order-detail-container-header-title">服务电话:</text>
128 141 <view class="order-detail-container-header-content">
129   - {{ dataGram.garOrderHandleTel }}
  142 + {{ dataGram.garOrderCompanyTel }}
130 143 </view>
131 144 </view>
132 145 <view class="order-detail-container-header-item">
133   - <text class="order-detail-container-header-title">装车照片:</text>
  146 + <text class=" order-detail-container-header-title">装车照片:</text>
134 147 <view class="order-detail-container-header-content">
135 148 <u-upload width="180" height="130" :fileList="putOnImages" name="3" multiple :maxCount="20"
136 149 :previewFullImage="true" :isReadOnly="true"></u-upload>
137 150 </view>
138 151 </view>
139 152 <view class="order-detail-container-header-item">
140   - <text class="order-detail-container-header-title">卸车照片:</text>
  153 + <text class=" order-detail-container-header-title">卸车照片:</text>
141 154 <view class="order-detail-container-header-content">
142 155 <u-upload width="180" height="130" :fileList="putDownImages" name="3" multiple :maxCount="20"
143 156 :previewFullImage="true" :isReadOnly="true"></u-upload>
... ... @@ -150,38 +163,55 @@
150 163 </view>
151 164 </view>
152 165 <view class="space-box">{{ spaceStr }}</view>
153   -
154 166 </view>
155 167 <!-- 占位符 -->
156 168 <view class="order-detail-bottom">
157 169 <view class="order-detail-bottom-box">
158 170 <view class=" order-detail-bottom-left">
159   - <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '司机'" @click="handleOderCancelClick()"
160   - shape="circle" color="#a9e08f" text="取消派单"></u-button>
  171 + <u-button v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
  172 + @click="handleSubmitSuccess(orderId)" shape="circle" color="#a9e08f" text="完成派单"></u-button>
  173 + <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '企业负责人' && dataGram.garCancelFlag === 0"
  174 + @click="handleOderCancelClick()" shape="circle" color="#a9e08f" text="取消派单"></u-button>
  175 + <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '运输驾驶员' && dataGram.garCancelFlag === 0"
  176 + @click="handleOderCancelClick()" shape="circle" color="#a9e08f" text="取消派单"></u-button>
  177 + <u-button v-if="dataGram.garOrderHandlerStatus === 1 && userType == '企业负责人'"
  178 + @click="handleOrderDispatchClick(orderId)" shape="circle" color="#a9e08f"
  179 + :text="dataGram.garOrderMatchFlag === 0 ? '派单下发' : '继续下发'"></u-button>
161 180 </view>
162 181 <view class="order-detail-bottom-right">
163 182 <u-button v-if="dataGram.garOrderHandlerStatus === 0 && userType == '居民用户' && dataGram.garCancelFlag === 0"
164 183 @click="handleOderCancelClick()" shape="circle" color="#a9e08f" text="取消派单"></u-button>
  184 + <u-button @click="driverHandleOrder(orderId)"
  185 + v-if="dataGram.garOrderHandlerStatus === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
  186 + shape="circle" color="#a9e08f" text="处理派单"></u-button>
165 187 <u-button @click="handleOrder(orderId)"
166   - v-if="dataGram.garOrderHandlerStatus === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0"
  188 + v-if="dataGram.garOrderHandlerStatus === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '企业负责人'"
167 189 shape="circle" color="#a9e08f" text="处理派单"></u-button>
168 190 <u-button @click="handleUploadImage(orderId, 'putOnImages')"
169   - v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putOnImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0"
  191 + v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
  192 + shape="circle" color="#a9e08f" text="上传图片"></u-button>
  193 + <!-- <u-button @click="handleUploadImage(orderId, 'putOnImages')"
  194 + v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putOnImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
170 195 shape="circle" color="#a9e08f" text="装车照片"></u-button>
171 196 <u-button @click="handleUploadImage(orderId, 'putDownImages')"
172   - v-else-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putDownImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0"
173   - shape="circle" color="#a9e08f" text="卸车照片"></u-button>
  197 + v-else-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putDownImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '运输驾驶员'"
  198 + shape="circle" color="#a9e08f" text="卸车照片"></u-button> -->
  199 + <!-- <u-button @click="handleUploadImage(orderId, 'putDownImages')"
  200 + v-else-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putDownImages.length === 0 && dataGram.handleFlag && dataGram.garCancelFlag === 0 && userType === '企业负责人'"
  201 + shape="circle" color="#a9e08f" text="上传照片"></u-button> -->
174 202 <u-button @click="handleEvaluate(orderId, userType)"
175 203 v-if="dataGram.garEvaluateFlag === 0 && userType === '居民用户'" shape="circle" color="#a9e08f"
176 204 text="去评价"></u-button>
177 205 <u-button @click="handleEvaluate(orderId, userType)"
178   - v-if="dataGram.garHandlerEvaluateFlag === 0 && userType === '司机'" shape="circle" color="#a9e08f"
  206 + v-if="dataGram.garHandlerEvaluateFlag === 0 && userType === '企业负责人'" shape="circle" color="#a9e08f"
179 207 text="去评价"></u-button>
180 208 <u-button @click="handleEvaluateDetail(orderId, userType)"
181   - v-if="dataGram.garHandlerEvaluateFlag === 1 && userType === '司机'" shape="circle" color="#a9e08f"
  209 + v-if="dataGram.garHandlerEvaluateFlag === 1 && userType === '企业负责人'" shape="circle" color="#a9e08f"
182 210 text="查看评价"></u-button>
183   - <u-button
184   - v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.putOnImages.length != 0 && dataGram.putDownImages.length != 0 && dataGram.garCancelFlag === 0"
  211 + <u-button @click="handleEvaluateDetail(orderId, userType)"
  212 + v-if="dataGram.garEvaluateFlag === 1 && userType === '居民用户'" shape="circle" color="#a9e08f"
  213 + text="查看评价"></u-button>
  214 + <u-button v-if="dataGram.garOrderHandlerStatus === 1 && dataGram.garCancelFlag === 0 && userType != '运输驾驶员'"
185 215 @click="handleSubmitSuccess(orderId)" shape="circle" color="#a9e08f" text="完成派单"></u-button>
186 216 </view>
187 217 </view>
... ... @@ -197,13 +227,16 @@
197 227 </template>
198 228  
199 229 <script setup>
200   -import { queryOrderDetail, updateOrder } from "@/apis/order.js";
  230 +import { dispatchOrders, queryOrderDetail, queryOrderDispatch, updateOrder } from "@/apis/order.js";
201 231 import { createQrCode } from '@/apis/qrcode.js';
202 232 import uqrcode from '@/components/Sansnn-uQRCode_4.0.6/components/uqrcode/uqrcode.vue';
  233 +import clashDispatch from '@/components/clash-dispatch/index.vue';
203 234 import zStatic from '@/components/z-paging/js/z-paging-static';
204 235 import { useMainStore } from '@/stores/index.js';
205   -import { onLoad, onReady } from '@dcloudio/uni-app';
206   -import { computed, nextTick, ref } from 'vue';
  236 +import { onLoad } from '@dcloudio/uni-app';
  237 +import { computed, ref } from 'vue';
  238 +const clashDispatchRef = ref()
  239 +const personnelList = ref([])
207 240 const store = useMainStore();
208 241 const userType = computed(() => store.userType)
209 242 const dataGram = ref();
... ... @@ -248,16 +281,8 @@ const createQrCodeLocal = (orderId) =&gt; {
248 281 const protocol = window.location.protocol;
249 282 const localAddress = `${protocol}//${hostname}:${port}`;
250 283 // const localAddress = `http://localhost:5173`;
251   - qrCodeText.value = localAddress + "/pages/order/detail/index?orderId=" + orderId;
252   - console.log(qrCodeText.value);
253   - qrCodeRef.value.remake({
254   - success: () => {
255   - console.log('生成成功');
256   - },
257   - fail: err => {
258   - console.log(err)
259   - }
260   - });
  284 + qrCodeText.value = localAddress + "/pages/order/guest/index?orderId=" + orderId;
  285 + console.log(qrCodeRef.value);
261 286 }
262 287 // 获取二维码
263 288 const handleQrCodeClick = (orderId) => {
... ... @@ -286,6 +311,21 @@ const handleQrCodeClick = (orderId) =&gt; {
286 311 // #endif
287 312 }
288 313  
  314 +const handleOrderDispatchClick = (orderId) => {
  315 + // 获取派单人员
  316 + queryOrderDispatch(orderId).then(res => {
  317 + if (res.data.success) {
  318 + personnelList.value = res.data.data
  319 + clashDispatchRef.value.open(res.data.data)
  320 +
  321 + handleOrderDetail(orderId)
  322 + } else {
  323 + uni.$u.toast(res.data.message)
  324 + }
  325 + })
  326 +}
  327 +
  328 +
289 329 const handleClose = (e) => {
290 330 cancelShow.value = false
291 331 }
... ... @@ -371,6 +411,8 @@ const handleSubmitSuccess = (orderId) =&gt; {
371 411 }
372 412 }
373 413 });
  414 + // uni.$u.route(`pages/order/success/index?orderId=${orderId}`)
  415 +
374 416 }
375 417 const handleEvaluate = (orderId, userType) => {
376 418 uni.$u.route(`pages/order/evaluate/index?orderId=${orderId}&userType=${userType}`)
... ... @@ -394,6 +436,24 @@ const handleOrder = (orderId) =&gt; {
394 436 })
395 437 }
396 438  
  439 +// 接收派单
  440 +const driverHandleOrder = (orderId) => {
  441 + updateOrder({ garOrderId: orderId, handleType: 0 }).then(res => {
  442 + if (res.data.success) {
  443 + if (res.data.data === "派单已经被别人接受啦") {
  444 + uni.$u.toast(res.data.data)
  445 + uni.$u.route({
  446 + type: "reLaunch",
  447 + url: `pages/order/index`,
  448 + })
  449 + } else {
  450 + uni.$u.toast(res.data.data)
  451 + handleOrderDetail(orderId)
  452 + }
  453 + }
  454 + })
  455 +}
  456 +
397 457  
398 458 const currentStep = (step) => {
399 459 if (step > 2) {
... ... @@ -403,12 +463,65 @@ const currentStep = (step) =&gt; {
403 463 }
404 464  
405 465 /**
  466 + * 清运状态
  467 + * @param {*} status
  468 + */
  469 +const cleanStatus = (status) => {
  470 + if (dataGram.garCancelFlag === 1) {
  471 + return '取消清运';
  472 + }
  473 + switch (status) {
  474 + case 0:
  475 + return '准备清运';
  476 + case 1:
  477 + return '正在清运';
  478 + case 3:
  479 + return '清运完成';
  480 + }
  481 +}
  482 +
  483 +// /**
  484 +// * 上传图片
  485 +// * @param {string} orderId
  486 +// * @param {string} putType
  487 +// */
  488 +// const handleUploadImage = (orderId, putType) => {
  489 +// uni.$u.route(`pages/order/upload/index?orderId=${orderId}&putType=${putType}`)
  490 +// }
  491 +
  492 +/**
406 493 * 上传图片
407 494 * @param {string} orderId
408 495 * @param {string} putType
409 496 */
410 497 const handleUploadImage = (orderId, putType) => {
411   - uni.$u.route(`pages/order/upload/index?orderId=${orderId}&putType=${putType}`)
  498 + uni.$u.route(`pages/order/upload/index?orderId=${orderId}`)
  499 +}
  500 +
  501 +
  502 +const handleDispatchConfirm = (val) => {
  503 + console.log(val);
  504 + if (!val) {
  505 + return
  506 + }
  507 + let data = {
  508 + garOrderId: orderId.value,
  509 + dispatchList: []
  510 + }
  511 + for (const key in val) {
  512 + data.dispatchList.push({
  513 + ...val[key]
  514 + });
  515 + }
  516 + console.log(data);
  517 + dispatchOrders(data).then(res => {
  518 + if (res.data.success) {
  519 + uni.$u.toast(res.data.msg)
  520 + } else {
  521 + uni.$u.toast("派单下发失败,请重试")
  522 + }
  523 + clashDispatchRef.value.close()
  524 + })
412 525 }
413 526  
414 527 /**
... ... @@ -418,14 +531,21 @@ onLoad((options) =&gt; {
418 531 orderId.value = options.orderId
419 532 handleOrderDetail(orderId.value)
420 533 })
421   -onReady(() => {
422   - // 生成二维码
423   - nextTick(() => {
424   -
425   - })
426   -})
427   -
428 534  
  535 +// onShow(() => {
  536 +// try {
  537 +// let pages = getCurrentPages();
  538 +// let currPage = pages[pages.length - 1];
  539 +// if (currPage.__data__.isRefresh) {
  540 +// // 重新获取数据
  541 +// this.getData(true)//获取列表数据
  542 +// // 每一次需要清除,否则会参数会缓存
  543 +// currPage.__data__.isRefresh = false
  544 +// }
  545 +// } catch (error) {
  546 +// console.log(error);
  547 +// }
  548 +// })
429 549 </script>
430 550  
431 551 <style lang="scss" scoped>
... ...
garbage-removal/src/pages/order/evaluate-info/index.vue
... ... @@ -24,7 +24,7 @@
24 24 <view class="user-info-title">
25 25 <u-avatar :src="pic" size="70"></u-avatar>
26 26 <view class="user-name">
27   - 司机
  27 + 企业负责人
28 28 </view>
29 29 </view>
30 30 <view v-if="evaluateManager" class="evaluate-content">
... ... @@ -55,7 +55,7 @@ const maxStar = ref([])
55 55  
56 56 // 用户评价对象
57 57 const evaluateUser = ref()
58   -// 司机评价
  58 +// 企业负责人评价
59 59 const evaluateManager = ref()
60 60 onLoad((options) => {
61 61 for (let index = 0; index < maxScore; index++) {
... ...
garbage-removal/src/pages/order/success/index.vue 0 → 100644
  1 +<template>
  2 + <view>
  3 + 完成界面{{ orderId }}
  4 + </view>
  5 +</template>
  6 +
  7 +<script setup>
  8 +import {
  9 + onLoad
  10 +} from '@dcloudio/uni-app';
  11 +import { ref } from 'vue';
  12 +const orderId = ref()
  13 +
  14 +
  15 +
  16 +onLoad((options) => {
  17 + orderId.value = options.orderId
  18 +})
  19 +</script>
  20 +
  21 +<style lang="scss" scoped>
  22 +</style>
... ...
garbage-removal/src/pages/order/swiper-list-item/index.vue
... ... @@ -10,16 +10,21 @@
10 10 <view class="store">{{ item.garOrderCompanyName }}</view>
11 11 <u-icon name="arrow-right" color="rgb(203,203,203)" :size="26"></u-icon>
12 12 </view>
13   - <view v-if="item.garOrderHandlerStatus === 0 && item.garCancelFlag === 0" class="right">待清运 </view>
14   - <view v-if="item.garCancelFlag === 1" class="right">已取消 </view>
15   - <view v-if="item.garOrderHandlerStatus === 1 && item.garCancelFlag === 0" class="right">清运中 </view>
  13 + <view style="display: flex;align-items: center;">
  14 + <text v-if="item.garOrderHandlerStatus != 3 && item.garOrderStatus === 3 && userType === '运输驾驶员'"
  15 + style="font-size: small;color: #f56c6c;">派单已经完成了。</text>
  16 + <view v-if="item.garOrderHandlerStatus === 0 && item.garCancelFlag === 0" class="right">待清运 </view>
  17 + <view v-if="item.garCancelFlag === 1" class="right">已取消 </view>
  18 + <view v-if="item.garOrderHandlerStatus === 1 && item.garCancelFlag === 0" class="right">清运中 </view>
  19 + <view v-if="item.garOrderHandlerStatus === 3 && userType === '运输驾驶员'" class="right">已完成 </view>
  20 + </view>
16 21 <view v-if="item.garEvaluateFlag === 0 && userType === '居民用户'" class="right">待评价
17 22 </view>
18   - <view v-if="item.garHandlerEvaluateFlag === 0 && userType === '司机'" class="right">待评价
  23 + <view v-if="item.garHandlerEvaluateFlag === 0 && userType === '企业负责人'" class="right">待评价
19 24 </view>
20 25 <view v-if="item.garEvaluateFlag === 1 && userType === '居民用户'" class="right">已评价
21 26 </view>
22   - <view v-if="item.garHandlerEvaluateFlag === 1 && userType === '司机'" class="right">已评价
  27 + <view v-if="item.garHandlerEvaluateFlag === 1 && userType === '企业负责人'" class="right">已评价
23 28 </view>
24 29 </view>
25 30 <view class="item" @click="handleClick(item.garOrderId)">
... ... @@ -49,7 +54,7 @@
49 54 </view>
50 55 <!-- 公司对用户评价 -->
51 56 <view class="bottom"
52   - v-if="item.garHandlerEvaluateFlag === 0 && item.garOrderHandlerStatus === 3 && userType === '司机'">
  57 + v-if="item.garHandlerEvaluateFlag === 0 && item.garOrderHandlerStatus === 3 && userType === '企业负责人'">
53 58 <view class="more">
54 59 <!-- <u-icon name="more-dot-fill" color="rgb(203,203,203)"></u-icon> -->
55 60 </view>
... ...
garbage-removal/src/pages/order/upload/index.vue
1 1 <template>
2 2 <view class="upload-image-box">
3 3 <view class="upload-image-box-choose">
4   - <text class="upload-image-box-choose-txt">请上传{{ putType }}图片类型:</text>
  4 + <text class="upload-image-box-choose-txt">请选着上传图片类型:</text>
5 5 <view class="upload-image-box-choose-type">
6   -
  6 + <u-radio-group v-model="putType" @change="groupChange" placement="row">
  7 + <u-radio activeColor="#19be6b" :customStyle="{ marginBottom: '8px' }" size="28" labelSize="28"
  8 + v-for="(item, index) in chooseList" :key="index" :label="item.name" :name="item.name" @change="radioChange">
  9 + </u-radio>
  10 + </u-radio-group>
7 11 </view>
8 12 </view>
9 13 <view class="upload-image-box-bottom">
... ... @@ -27,10 +31,11 @@
27 31 import { uploadFilePromise } from '@/apis/common.js';
28 32 import { uploadImageUrlByType } from '@/apis/order.js';
29 33 import { onLoad } from '@dcloudio/uni-app';
30   -import { ref } from 'vue';
31   -const putType = ref("")
  34 +import { reactive, ref } from 'vue';
  35 +const putType = ref("装车图片")
32 36 const orderId = ref();
33 37 const fileList = ref([])
  38 +const chooseList = reactive([{ name: "装车图片" }, { name: "卸车图片" }])
34 39 // 删除图片
35 40 const deletePic = (event) => {
36 41 fileList.value.splice(event.index, 1);
... ... @@ -71,15 +76,20 @@ const handleSubmit = (id, type) =&gt; {
71 76 }
72 77 let params = {
73 78 garOrderId: id,
74   - type: type == "装车片" ? 1 : 2,
  79 + type: type == "装车片" ? 1 : 2,
75 80 imageUrls: fileList.value.map(item => item.url)
76 81 }
77 82 uploadImageUrlByType(params).then(res => {
78 83 if (res.data.success) {
79 84 uni.$u.toast("图片上传完毕!");
80   - uni.$u.route({
81   - type: "navigateBack",
82   - url: "pages/order/detail/index"
  85 + let pages = getCurrentPages();
  86 + console.log(pages);
  87 + uni.navigateBack({
  88 + delta: 1,
  89 + success() {
  90 + //pages.length-1 即最后一个为当前页,所以取当前页面的上一级
  91 + pages[pages.length - 2].$vm.handleOrderDetail(id); // init 是上一个页面的方法名称
  92 + }
83 93 })
84 94 }
85 95 })
... ... @@ -97,7 +107,8 @@ const validateImage = () =&gt; {
97 107  
98 108 onLoad((options) => {
99 109 orderId.value = options.orderId;
100   - putType.value = options.putType === "putOnImages" ? "装车照片" : "卸车照片";
  110 + // putType.value = options.putType === "putOnImages" ? "装车图片" : "卸车图片";
  111 +
101 112 })
102 113 </script>
103 114  
... ...
garbage-removal/src/pages/wode/choose/index.vue
... ... @@ -2,21 +2,34 @@
2 2 <view class="wrap">
3 3 <u-radio-group v-model="userType" placement="row" @change="groupChange">
4 4 <view class="choose-type" v-for="(item, index) in typeList">
5   - <u-radio :customStyle="{ marginBottom: '8px' }" size="28" labelSize="28" :key="index" :label="item.name"
6   - :name="item.name" @change="radioChange">
  5 + <u-radio size="28" labelSize="28" :key="index" :label="item.name" :name="item.name" @change="radioChange">
7 6 </u-radio>
8   - <view class="manager-info" v-if="item.name === '司机' && unitInfo.companyFlag">
9   - <view class="manager-info-parent-company-name">
10   - <text style="margin-right: 20rpx;">经营公司:</text>
11   - <text>{{ unitInfo.parentCompanyName }}</text>
12   - </view>
13   - <view class="manager-info-transport-company-name">
14   - <text style="margin-right: 20rpx;">运输公司:</text>
15   - <text>{{ unitInfo.transportCompanyName }}</text>
16   - </view>
17   - </view>
18 7 </view>
19 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 class="manager-info-parent-company-name">
  18 + 长沙有限运输运输公司-运输驾驶员-李伟
  19 + </view>
  20 + <view class="manager-info-parent-company-name">
  21 + 未匹配到该手机号绑定的运输公司!
  22 + </view>
  23 + </view>
  24 + <view class="manager-info" v-if="userType === '企业负责人'">
  25 + <view class="manager-info-parent-company-name">
  26 + 长沙有限运输运输公司公司服务账号!
  27 + </view>
  28 + <view class="manager-info-parent-company-name">
  29 + 未匹配到该手机号绑定运输公司公司服务账号!
  30 + </view>
  31 + </view>
  32 + </view>
20 33 <view class="choose-button">
21 34 <u-button shape="circle" color="#a9e08f" @click="submit(userType)">确定</u-button>
22 35 </view>
... ... @@ -31,12 +44,13 @@ import { onLoad } from &quot;@dcloudio/uni-app&quot;;
31 44 import { ref } from 'vue';
32 45 const store = useMainStore();
33 46 const userType = ref("居民用户")
34   -const typeList = ref([{ name: "居民用户" }, { name: "司机" }])
  47 +const typeList = ref([{ name: "居民用户" }, { name: "运输驾驶员" }, { name: "企业负责人" }])
35 48 const unitInfo = ref({})
36 49 const radioChange = (e) => {
37 50 }
38 51 const groupChange = (e) => {
39 52 }
  53 +
40 54 const submit = (userType) => {
41 55 setRequestToken(store.tempToken)
42 56 updateUserInfo({ garUserType: userType }).then(res => {
... ... @@ -56,10 +70,8 @@ const submit = (userType) =&gt; {
56 70 }
57 71 onLoad((options) => {
58 72 unitInfo.value = options
59   - unitInfo.value.companyFlag = JSON.parse(options.companyFlag)
60   - if (unitInfo.value.companyFlag) {
61   - userType.value = "司机"
62   - }
  73 + userType.value = options.userType
  74 + // submit(options.userType)
63 75 })
64 76 </script>
65 77  
... ... @@ -72,36 +84,39 @@ onLoad((options) =&gt; {
72 84 background-color: $u-info-light;
73 85  
74 86 .choose-type {
75   - width: 100%;
  87 + // width: 100%;
76 88 box-sizing: border-box;
77   - padding: 30rpx;
  89 + padding: 20rpx;
78 90 background-color: #ffffff;
79 91 border-radius: 20rpx;
  92 + margin-right: 20rpx;
  93 + display: flex;
  94 + align-items: center;
  95 + justify-content: center;
80 96  
81   - &:first-child {
  97 + &:last-child {
82 98 margin-right: 20rpx;
83 99 }
84 100  
  101 +
  102 + }
  103 +
  104 + .rule-label-info-box {
  105 + box-sizing: border-box;
  106 + margin-top: 20rpx;
  107 +
85 108 .manager-info {
86 109 font-size: 25rpx;
87 110 color: $u-main-color;
88 111 box-sizing: border-box;
89 112  
90 113 .manager-info-parent-company-name {
91   -
92   - text {
93   - color: $u-info;
94   - }
95   - }
96   -
97   - .manager-info-transport-company-name {
98   - text {
99   - color: $u-info;
100   - }
  114 + color: $u-info;
101 115 }
102 116 }
103 117 }
104 118  
  119 +
105 120 .choose-button {
106 121 position: relative;
107 122 width: 100%;
... ...
garbage-removal/src/pages/wode/index.vue
... ... @@ -6,13 +6,15 @@
6 6 </view>
7 7 <view class="u-flex-1">
8 8 <view class="u-font-18 u-p-b-20">{{ userInfo.userType }}</view>
9   - <view class="manager-info" v-if="userInfo.companyFlag">
10   - <view class="manager-info-parent-company-name">
11   - <text style="margin-right: 20rpx;">经营公司:</text>
12   - <text>{{ userInfo.parentCompanyName }}</text>
  9 + <view class="manager-info" v-if="userInfo.userType === '运输驾驶员'">
  10 + <view class="manager-info-transport-company-name">
  11 + <text style="margin-right: 20rpx;">所属运输公司:</text>
  12 + <text>{{ userInfo.transportCompanyName }}</text>
13 13 </view>
  14 + </view>
  15 + <view class="manager-info" v-if="userInfo.userType === '企业负责人'">
14 16 <view class="manager-info-transport-company-name">
15   - <text style="margin-right: 20rpx;">运输公司:</text>
  17 + <text style="margin-right: 20rpx;">所属运输公司:</text>
16 18 <text>{{ userInfo.transportCompanyName }}</text>
17 19 </view>
18 20 </view>
... ...
garbage-removal/src/utils/request/request.js
... ... @@ -148,4 +148,7 @@ const handleGet = (config) =&gt; {
148 148 }
149 149 config.url += strUrl;
150 150 config.params = "";
  151 + if (config.url.startsWith("/order/webDetail/")) {
  152 + config.headers["Authorization"] = "";
  153 + }
151 154 }
... ...
garbage-removal/src/uview-plus/components/u-action-sheet/u-action-sheet.vue
... ... @@ -39,7 +39,7 @@
39 39 <!-- #endif -->
40 40 <view v-if="item.name == '其他'" class="u-action-sheet__item-wrap__item" :hover-stay-time="150">
41 41 <view class="parent-box">
42   - <u-collapse>
  42 + <u-collapse @open="handleOpenMethod" @close="handleCloseMethod">
43 43 <u-collapse-item @selectHandler="selectHandler" :index="index" :name="item.name" ref="childRef"
44 44 title="其他" name="其他">
45 45 <view class="u-collapse-content" style="width: 97vw;text-align: left;">
... ... @@ -151,6 +151,14 @@ export default {
151 151 },
152 152 },
153 153 methods: {
  154 + handleOpenMethod(e) {
  155 + // console.log("开启", e);
  156 + this.accordion = true;
  157 + },
  158 + handleCloseMethod(e) {
  159 + // console.log("关闭", e);
  160 + this.accordion = false;
  161 + },
154 162 closeHandler() {
155 163 // 允许点击遮罩关闭时,才发出close事件
156 164 if (this.closeOnClickOverlay) {
... ... @@ -162,6 +170,7 @@ export default {
162 170 this.$emit('actionSheetClose')
163 171 },
164 172 selectHandler(index, name) {
  173 + console.log(index, name);
165 174 if (name != "其他") {
166 175 if (this.accordion) {
167 176 this.$refs.childRef[0].clickHandler("抽屉");
... ... @@ -169,9 +178,6 @@ export default {
169 178 }
170 179 this.otherReason = ''
171 180 }
172   - if (name == "其他") {
173   - this.accordion = true;
174   - }
175 181 this.currentSelect = index;
176 182 const item = this.actions[index]
177 183 if (item && !item.disabled && !item.loading) {
... ...
garbage-removal/src/uview-plus/components/u-checkbox-group/u-checkbox-group.vue
... ... @@ -97,6 +97,7 @@ export default {
97 97 values.push(child.name)
98 98 }
99 99 })
  100 + console.log(values);
100 101 // 发出事件
101 102 this.$emit('change', values)
102 103 // 修改通过v-model绑定的值
... ...
garbage-removal/src/uview-plus/components/u-number-box/u-number-box.vue
1 1 <template>
2 2 <view class="u-number-box">
3   - <view
4   - class="u-number-box__slot"
5   - @tap.stop="clickHandler('minus')"
6   - @touchstart="onTouchStart('minus')"
7   - @touchend.stop="clearTimeout"
8   - v-if="showMinus && $slots.minus"
9   - >
  3 + <view class="u-number-box__slot" @tap.stop="clickHandler('minus')" @touchstart="onTouchStart('minus')"
  4 + @touchend.stop="clearTimeout" v-if="showMinus && $slots.minus">
10 5 <slot name="minus" />
11 6 </view>
12   - <view
13   - v-else-if="showMinus"
14   - class="u-number-box__minus"
15   - @tap.stop="clickHandler('minus')"
16   - @touchstart="onTouchStart('minus')"
17   - @touchend.stop="clearTimeout"
18   - hover-class="u-number-box__minus--hover"
19   - hover-stay-time="150"
20   - :class="{ 'u-number-box__minus--disabled': isDisabled('minus') }"
21   - :style="[buttonStyle('minus')]"
22   - >
23   - <u-icon
24   - name="minus"
25   - :color="isDisabled('minus') ? '#c8c9cc' : '#323233'"
26   - size="15"
27   - bold
28   - :customStyle="iconStyle"
29   - ></u-icon>
  7 + <view v-else-if="showMinus" class="u-number-box__minus" @tap.stop="clickHandler('minus')"
  8 + @touchstart="onTouchStart('minus')" @touchend.stop="clearTimeout" hover-class="u-number-box__minus--hover"
  9 + hover-stay-time="150" :class="{ 'u-number-box__minus--disabled': isDisabled('minus') }"
  10 + :style="[buttonStyle('minus')]">
  11 + <u-icon name="minus" :color="isDisabled('minus') ? '#c8c9cc' : '#323233'" size="15" bold
  12 + :customStyle="iconStyle"></u-icon>
30 13 </view>
31 14  
32 15 <slot name="input">
33   - <input
34   - :disabled="disabledInput || disabled"
35   - :cursor-spacing="getCursorSpacing"
36   - :class="{ 'u-number-box__input--disabled': disabled || disabledInput }"
37   - v-model="currentValue"
38   - class="u-number-box__input"
39   - @blur="onBlur"
40   - @focus="onFocus"
41   - @input="onInput"
42   - type="number"
43   - :style="[inputStyle]"
44   - />
  16 + <input :disabled="disabledInput || disabled" :cursor-spacing="getCursorSpacing"
  17 + :class="{ 'u-number-box__input--disabled': disabled || disabledInput }" v-model="currentValue"
  18 + class="u-number-box__input" @blur="onBlur" @focus="onFocus" @input="onInput" type="number"
  19 + :style="[inputStyle]" />
45 20 </slot>
46   - <view
47   - class="u-number-box__slot"
48   - @tap.stop="clickHandler('plus')"
49   - @touchstart="onTouchStart('plus')"
50   - @touchend.stop="clearTimeout"
51   - v-if="showPlus && $slots.plus"
52   - >
  21 + <view class="u-number-box__slot" @tap.stop="clickHandler('plus')" @touchstart="onTouchStart('plus')"
  22 + @touchend.stop="clearTimeout" v-if="showPlus && $slots.plus">
53 23 <slot name="plus" />
54 24 </view>
55   - <view
56   - v-else-if="showPlus"
57   - class="u-number-box__plus"
58   - @tap.stop="clickHandler('plus')"
59   - @touchstart="onTouchStart('plus')"
60   - @touchend.stop="clearTimeout"
61   - hover-class="u-number-box__plus--hover"
62   - hover-stay-time="150"
63   - :class="{ 'u-number-box__minus--disabled': isDisabled('plus') }"
64   - :style="[buttonStyle('plus')]"
65   - >
66   - <u-icon
67   - name="plus"
68   - :color="isDisabled('plus') ? '#c8c9cc' : '#323233'"
69   - size="15"
70   - bold
71   - :customStyle="iconStyle"
72   - ></u-icon>
  25 + <view v-else-if="showPlus" class="u-number-box__plus" @tap.stop="clickHandler('plus')"
  26 + @touchstart="onTouchStart('plus')" @touchend.stop="clearTimeout" hover-class="u-number-box__plus--hover"
  27 + hover-stay-time="150" :class="{ 'u-number-box__minus--disabled': isDisabled('plus') }"
  28 + :style="[buttonStyle('plus')]">
  29 + <u-icon name="plus" :color="isDisabled('plus') ? '#c8c9cc' : '#323233'" size="15" bold
  30 + :customStyle="iconStyle"></u-icon>
73 31 </view>
74 32 </view>
75 33 </template>
76 34  
77 35 <script>
78   - import props from './props.js';
79   - import mpMixin from '../../libs/mixin/mpMixin.js';
80   - import mixin from '../../libs/mixin/mixin.js';
81   - /**
82   - * numberBox 步进器
83   - * @description 该组件一般用于商城购物选择物品数量的场景。
84   - * @tutorial https://uviewui.com/components/numberBox.html
85   - * @property {String | Number} name 步进器标识符,在change回调返回
86   - * @property {String | Number} value 用于双向绑定的值,初始化时设置设为默认min值(最小值) (默认 0 )
87   - * @property {String | Number} min 最小值 (默认 1 )
88   - * @property {String | Number} max 最大值 (默认 Number.MAX_SAFE_INTEGER )
89   - * @property {String | Number} step 加减的步长,可为小数 (默认 1 )
90   - * @property {Boolean} integer 是否只允许输入整数 (默认 false )
91   - * @property {Boolean} disabled 是否禁用,包括输入框,加减按钮 (默认 false )
92   - * @property {Boolean} disabledInput 是否禁用输入框 (默认 false )
93   - * @property {Boolean} asyncChange 是否开启异步变更,开启后需要手动控制输入值 (默认 false )
94   - * @property {String | Number} inputWidth 输入框宽度,单位为px (默认 35 )
95   - * @property {Boolean} showMinus 是否显示减少按钮 (默认 true )
96   - * @property {Boolean} showPlus 是否显示增加按钮 (默认 true )
97   - * @property {String | Number} decimalLength 显示的小数位数
98   - * @property {Boolean} longPress 是否开启长按加减手势 (默认 true )
99   - * @property {String} color 输入框文字和加减按钮图标的颜色 (默认 '#323233' )
100   - * @property {String | Number} buttonSize 按钮大小,宽高等于此值,单位px,输入框高度和此值保持一致 (默认 30 )
101   - * @property {String} bgColor 输入框和按钮的背景颜色 (默认 '#EBECEE' )
102   - * @property {String | Number} cursorSpacing 指定光标于键盘的距离,避免键盘遮挡输入框,单位px (默认 100 )
103   - * @property {Boolean} disablePlus 是否禁用增加按钮 (默认 false )
104   - * @property {Boolean} disableMinus 是否禁用减少按钮 (默认 false )
105   - * @property {Object | String} iconStyle 加减按钮图标的样式
106   - *
107   - * @event {Function} onFocus 输入框活动焦点
108   - * @event {Function} onBlur 输入框失去焦点
109   - * @event {Function} onInput 输入框值发生变化
110   - * @event {Function} onChange
111   - * @example <u-number-box v-model="value" @change="valChange"></u-number-box>
112   - */
113   - export default {
114   - name: 'u-number-box',
115   - mixins: [mpMixin, mixin, props],
116   - data() {
117   - return {
118   - // 输入框实际操作的值
119   - currentValue: '',
120   - // 定时器
121   - longPressTimer: null
122   - }
  36 +import mixin from '../../libs/mixin/mixin.js';
  37 +import mpMixin from '../../libs/mixin/mpMixin.js';
  38 +import props from './props.js';
  39 +/**
  40 + * numberBox 步进器
  41 + * @description 该组件一般用于商城购物选择物品数量的场景。
  42 + * @tutorial https://uviewui.com/components/numberBox.html
  43 + * @property {String | Number} name 步进器标识符,在change回调返回
  44 + * @property {String | Number} value 用于双向绑定的值,初始化时设置设为默认min值(最小值) (默认 0 )
  45 + * @property {String | Number} min 最小值 (默认 1 )
  46 + * @property {String | Number} max 最大值 (默认 Number.MAX_SAFE_INTEGER )
  47 + * @property {String | Number} step 加减的步长,可为小数 (默认 1 )
  48 + * @property {Boolean} integer 是否只允许输入整数 (默认 false )
  49 + * @property {Boolean} disabled 是否禁用,包括输入框,加减按钮 (默认 false )
  50 + * @property {Boolean} disabledInput 是否禁用输入框 (默认 false )
  51 + * @property {Boolean} asyncChange 是否开启异步变更,开启后需要手动控制输入值 (默认 false )
  52 + * @property {String | Number} inputWidth 输入框宽度,单位为px (默认 35 )
  53 + * @property {Boolean} showMinus 是否显示减少按钮 (默认 true )
  54 + * @property {Boolean} showPlus 是否显示增加按钮 (默认 true )
  55 + * @property {String | Number} decimalLength 显示的小数位数
  56 + * @property {Boolean} longPress 是否开启长按加减手势 (默认 true )
  57 + * @property {String} color 输入框文字和加减按钮图标的颜色 (默认 '#323233' )
  58 + * @property {String | Number} buttonSize 按钮大小,宽高等于此值,单位px,输入框高度和此值保持一致 (默认 30 )
  59 + * @property {String} bgColor 输入框和按钮的背景颜色 (默认 '#EBECEE' )
  60 + * @property {String | Number} cursorSpacing 指定光标于键盘的距离,避免键盘遮挡输入框,单位px (默认 100 )
  61 + * @property {Boolean} disablePlus 是否禁用增加按钮 (默认 false )
  62 + * @property {Boolean} disableMinus 是否禁用减少按钮 (默认 false )
  63 + * @property {Object | String} iconStyle 加减按钮图标的样式
  64 + *
  65 + * @event {Function} onFocus 输入框活动焦点
  66 + * @event {Function} onBlur 输入框失去焦点
  67 + * @event {Function} onInput 输入框值发生变化
  68 + * @event {Function} onChange
  69 + * @example <u-number-box v-model="value" @change="valChange"></u-number-box>
  70 + */
  71 +export default {
  72 + name: 'u-number-box',
  73 + mixins: [mpMixin, mixin, props],
  74 + data() {
  75 + return {
  76 + // 输入框实际操作的值
  77 + currentValue: '',
  78 + // 定时器
  79 + longPressTimer: null
  80 + }
  81 + },
  82 + watch: {
  83 + // 多个值之间,只要一个值发生变化,都要重新检查check()函数
  84 + watchChange(n) {
  85 + this.check()
123 86 },
124   - watch: {
125   - // 多个值之间,只要一个值发生变化,都要重新检查check()函数
126   - watchChange(n) {
127   - this.check()
128   - },
129   - // #ifdef VUE2
130   - // 监听v-mode的变化,重新初始化内部的值
131   - value(n) {
132   - if (n !== this.currentValue) {
133   - this.currentValue = this.format(this.value)
134   - }
135   - },
136   - // #endif
137   - // #ifdef VUE3
138   - // 监听v-mode的变化,重新初始化内部的值
139   - modelValue(n) {
140   - if (n !== this.currentValue) {
141   - this.currentValue = this.format(this.modelValue)
142   - }
  87 + // #ifdef VUE2
  88 + // 监听v-mode的变化,重新初始化内部的值
  89 + value(n) {
  90 + if (n !== this.currentValue) {
  91 + this.currentValue = this.format(this.value)
143 92 }
144   - // #endif
145 93 },
146   - computed: {
147   - getCursorSpacing() {
148   - // 判断传入的单位,如果为px单位,需要转成px
149   - return uni.$u.getPx(this.cursorSpacing)
150   - },
151   - // 按钮的样式
152   - buttonStyle() {
153   - return (type) => {
154   - const style = {
155   - backgroundColor: this.bgColor,
156   - height: uni.$u.addUnit(this.buttonSize),
157   - color: this.color
158   - }
159   - if (this.isDisabled(type)) {
160   - style.backgroundColor = '#f7f8fa'
161   - }
162   - return style
  94 + // #endif
  95 + // 监听v-mode的变化,重新初始化内部的值
  96 +
  97 + // #ifdef VUE3
  98 + // modelValue(n) {
  99 + // console.log("n", n);
  100 + // console.log("this.currentValue", this.currentValue);
  101 + // if (n !== this.currentValue) {
  102 + // this.currentValue = this.format(this.modelValue)
  103 + // }
  104 + // },
  105 + modelValue: {
  106 + handler: function (newV, oldV) {
  107 + if (newV !== this.currentValue) {
  108 + this.currentValue = this.format(this.modelValue)
163 109 }
164 110 },
165   - // 输入框的样式
166   - inputStyle() {
167   - const disabled = this.disabled || this.disabledInput
  111 + immediate: true
  112 + }
  113 + // #endif
  114 + },
  115 + computed: {
  116 + getCursorSpacing() {
  117 + // 判断传入的单位,如果为px单位,需要转成px
  118 + return uni.$u.getPx(this.cursorSpacing)
  119 + },
  120 + // 按钮的样式
  121 + buttonStyle() {
  122 + return (type) => {
168 123 const style = {
169   - color: this.color,
170 124 backgroundColor: this.bgColor,
171 125 height: uni.$u.addUnit(this.buttonSize),
172   - width: uni.$u.addUnit(this.inputWidth)
  126 + color: this.color
  127 + }
  128 + if (this.isDisabled(type)) {
  129 + style.backgroundColor = '#f7f8fa'
173 130 }
174 131 return style
175   - },
176   - // 用于监听多个值发生变化
177   - watchChange() {
178   - return [this.integer, this.decimalLength, this.min, this.max]
179   - },
180   - isDisabled() {
181   - return (type) => {
182   - if (type === 'plus') {
183   - // 在点击增加按钮情况下,判断整体的disabled,是否单独禁用增加按钮,以及当前值是否大于最大的允许值
184   - return (
185   - this.disabled ||
186   - this.disablePlus ||
187   - this.currentValue >= this.max
188   - )
189   - }
190   - // 点击减少按钮同理
  132 + }
  133 + },
  134 + // 输入框的样式
  135 + inputStyle() {
  136 + const disabled = this.disabled || this.disabledInput
  137 + const style = {
  138 + color: this.color,
  139 + backgroundColor: this.bgColor,
  140 + height: uni.$u.addUnit(this.buttonSize),
  141 + width: uni.$u.addUnit(this.inputWidth)
  142 + }
  143 + return style
  144 + },
  145 + // 用于监听多个值发生变化
  146 + watchChange() {
  147 + return [this.integer, this.decimalLength, this.min, this.max]
  148 + },
  149 + isDisabled() {
  150 + return (type) => {
  151 + if (type === 'plus') {
  152 + // 在点击增加按钮情况下,判断整体的disabled,是否单独禁用增加按钮,以及当前值是否大于最大的允许值
191 153 return (
192 154 this.disabled ||
193   - this.disableMinus ||
194   - this.currentValue <= this.min
  155 + this.disablePlus ||
  156 + this.currentValue >= this.max
195 157 )
196 158 }
197   - },
  159 + // 点击减少按钮同理
  160 + return (
  161 + this.disabled ||
  162 + this.disableMinus ||
  163 + this.currentValue <= this.min
  164 + )
  165 + }
198 166 },
199   - mounted() {
200   - this.init()
  167 + },
  168 + mounted() {
  169 + this.init()
  170 + },
  171 + // #ifdef VUE3
  172 + emits: ['update:modelValue', 'focus', 'blur', 'overlimit', 'change', 'plus', 'minus'],
  173 + // #endif
  174 + methods: {
  175 + init() {
  176 + // #ifdef VUE3
  177 + this.currentValue = this.format(this.modelValue)
  178 + // #endif
  179 + // #ifdef VUE2
  180 + this.currentValue = this.format(this.value)
  181 + // #endif
201 182 },
202   - // #ifdef VUE3
203   - emits: ['update:modelValue', 'focus', 'blur', 'overlimit', 'change', 'plus', 'minus'],
204   - // #endif
205   - methods: {
206   - init() {
207   - // #ifdef VUE3
208   - this.currentValue = this.format(this.modelValue)
209   - // #endif
210   - // #ifdef VUE2
211   - this.currentValue = this.format(this.value)
212   - // #endif
213   - },
214   - // 格式化整理数据,限制范围
215   - format(value) {
216   - value = this.filter(value)
217   - // 如果为空字符串,那么设置为0,同时将值转为Number类型
218   - value = value === '' ? 0 : +value
219   - // 对比最大最小值,取在min和max之间的值
220   - value = Math.max(Math.min(this.max, value), this.min)
221   - // 如果设定了最大的小数位数,使用toFixed去进行格式化
222   - if (this.decimalLength !== null) {
223   - value = value.toFixed(this.decimalLength)
224   - }
225   - return value
226   - },
227   - // 过滤非法的字符
228   - filter(value) {
229   - // 只允许0-9之间的数字,"."为小数点,"-"为负数时候使用
230   - value = String(value).replace(/[^0-9.-]/g, '')
231   - // 如果只允许输入整数,则过滤掉小数点后的部分
232   - if (this.integer && value.indexOf('.') !== -1) {
233   - value = value.split('.')[0]
234   - }
235   - return value;
236   - },
237   - check() {
238   - // 格式化了之后,如果前后的值不相等,那么设置为格式化后的值
239   - const val = this.format(this.currentValue);
240   - if (val !== this.currentValue) {
241   - this.currentValue = val
242   - }
243   - },
244   - // 判断是否出于禁止操作状态
245   - // isDisabled(type) {
246   - // if (type === 'plus') {
247   - // // 在点击增加按钮情况下,判断整体的disabled,是否单独禁用增加按钮,以及当前值是否大于最大的允许值
248   - // return (
249   - // this.disabled ||
250   - // this.disablePlus ||
251   - // this.currentValue >= this.max
252   - // )
253   - // }
254   - // // 点击减少按钮同理
255   - // return (
256   - // this.disabled ||
257   - // this.disableMinus ||
258   - // this.currentValue <= this.min
259   - // )
260   - // },
261   - // 输入框活动焦点
262   - onFocus(event) {
263   - this.$emit('focus', {
264   - ...event.detail,
265   - name: this.name,
  183 + // 格式化整理数据,限制范围
  184 + format(value) {
  185 + value = this.filter(value)
  186 + // 如果为空字符串,那么设置为0,同时将值转为Number类型
  187 + value = value === '' ? 0 : +value
  188 + // 对比最大最小值,取在min和max之间的值
  189 + value = Math.max(Math.min(this.max, value), this.min)
  190 + // 如果设定了最大的小数位数,使用toFixed去进行格式化
  191 + if (this.decimalLength !== null) {
  192 + value = value.toFixed(this.decimalLength)
  193 + }
  194 + return value
  195 + },
  196 + // 过滤非法的字符
  197 + filter(value) {
  198 + // 只允许0-9之间的数字,"."为小数点,"-"为负数时候使用
  199 + value = String(value).replace(/[^0-9.-]/g, '')
  200 + // 如果只允许输入整数,则过滤掉小数点后的部分
  201 + if (this.integer && value.indexOf('.') !== -1) {
  202 + value = value.split('.')[0]
  203 + }
  204 + return value;
  205 + },
  206 + check() {
  207 + // 格式化了之后,如果前后的值不相等,那么设置为格式化后的值
  208 + const val = this.format(this.currentValue);
  209 + if (val !== this.currentValue) {
  210 + this.currentValue = val
  211 + }
  212 + },
  213 + // 判断是否出于禁止操作状态
  214 + // isDisabled(type) {
  215 + // if (type === 'plus') {
  216 + // // 在点击增加按钮情况下,判断整体的disabled,是否单独禁用增加按钮,以及当前值是否大于最大的允许值
  217 + // return (
  218 + // this.disabled ||
  219 + // this.disablePlus ||
  220 + // this.currentValue >= this.max
  221 + // )
  222 + // }
  223 + // // 点击减少按钮同理
  224 + // return (
  225 + // this.disabled ||
  226 + // this.disableMinus ||
  227 + // this.currentValue <= this.min
  228 + // )
  229 + // },
  230 + // 输入框活动焦点
  231 + onFocus(event) {
  232 + this.$emit('focus', {
  233 + ...event.detail,
  234 + name: this.name,
  235 + })
  236 + },
  237 + // 输入框失去焦点
  238 + onBlur(event) {
  239 + // 对输入值进行格式化
  240 + const value = this.format(event.detail.value)
  241 + // 发出blur事件
  242 + this.$emit(
  243 + 'blur', {
  244 + ...event.detail,
  245 + name: this.name,
  246 + }
  247 + )
  248 + },
  249 + // 输入框值发生变化
  250 + onInput(e) {
  251 + const {
  252 + value = ''
  253 + } = e.detail || {}
  254 + // 为空返回
  255 + if (value === '') return
  256 + let formatted = this.filter(value)
  257 + // 最大允许的小数长度
  258 + if (this.decimalLength !== null && formatted.indexOf('.') !== -1) {
  259 + const pair = formatted.split('.');
  260 + formatted = `${pair[0]}.${pair[1].slice(0, this.decimalLength)}`
  261 + }
  262 + formatted = this.format(formatted)
  263 + this.emitChange(formatted);
  264 + },
  265 + // 发出change事件
  266 + emitChange(value) {
  267 + // 如果开启了异步变更值,则不修改内部的值,需要用户手动在外部通过v-model变更
  268 + if (!this.asyncChange) {
  269 + this.$nextTick(() => {
  270 + // #ifdef VUE3
  271 + this.$emit('update:modelValue', value)
  272 + // #endif
  273 + // #ifdef VUE2
  274 + this.$emit('input', value)
  275 + // #endif
  276 + this.currentValue = value
  277 + this.$forceUpdate()
266 278 })
267   - },
268   - // 输入框失去焦点
269   - onBlur(event) {
270   - // 对输入值进行格式化
271   - const value = this.format(event.detail.value)
272   - // 发出blur事件
273   - this.$emit(
274   - 'blur',{
275   - ...event.detail,
276   - name: this.name,
277   - }
278   - )
279   - },
280   - // 输入框值发生变化
281   - onInput(e) {
282   - const {
283   - value = ''
284   - } = e.detail || {}
285   - // 为空返回
286   - if (value === '') return
287   - let formatted = this.filter(value)
288   - // 最大允许的小数长度
289   - if (this.decimalLength !== null && formatted.indexOf('.') !== -1) {
290   - const pair = formatted.split('.');
291   - formatted = `${pair[0]}.${pair[1].slice(0, this.decimalLength)}`
292   - }
293   - formatted = this.format(formatted)
294   - this.emitChange(formatted);
295   - },
296   - // 发出change事件
297   - emitChange(value) {
298   - // 如果开启了异步变更值,则不修改内部的值,需要用户手动在外部通过v-model变更
299   - if (!this.asyncChange) {
300   - this.$nextTick(() => {
301   - // #ifdef VUE3
302   - this.$emit('update:modelValue', value)
303   - // #endif
304   - // #ifdef VUE2
305   - this.$emit('input', value)
306   - // #endif
307   - this.currentValue = value
308   - this.$forceUpdate()
309   - })
310   - }
311   - this.$emit('change', {
312   - value,
313   - name: this.name,
314   - });
315   - },
316   - onChange() {
317   - const {
318   - type
319   - } = this
320   - if (this.isDisabled(type)) {
321   - return this.$emit('overlimit', type)
322   - }
323   - const diff = type === 'minus' ? -this.step : +this.step
324   - const value = this.format(this.add(+this.currentValue, diff))
325   - this.emitChange(value)
326   - this.$emit(type)
327   - },
328   - // 对值扩大后进行四舍五入,再除以扩大因子,避免出现浮点数操作的精度问题
329   - add(num1, num2) {
330   - const cardinal = Math.pow(10, 10);
331   - return Math.round((num1 + num2) * cardinal) / cardinal
332   - },
333   - // 点击加减按钮
334   - clickHandler(type) {
335   - this.type = type
336   - this.onChange()
337   - },
338   - longPressStep() {
339   - // 每隔一段时间,重新调用longPressStep方法,实现长按加减
340   - this.clearTimeout()
341   - this.longPressTimer = setTimeout(() => {
342   - this.onChange()
343   - this.longPressStep()
344   - }, 250);
345   - },
346   - onTouchStart(type) {
347   - if (!this.longPress) return
348   - this.clearTimeout()
349   - this.type = type
350   - // 一定时间后,默认达到长按状态
351   - this.longPressTimer = setTimeout(() => {
352   - this.onChange()
353   - this.longPressStep()
354   - }, 600)
355   - },
356   - // 触摸结束,清除定时器,停止长按加减
357   - onTouchEnd() {
358   - if (!this.longPress) return
359   - this.clearTimeout()
360   - },
361   - // 清除定时器
362   - clearTimeout() {
363   - clearTimeout(this.longPressTimer)
364   - this.longPressTimer = null
365 279 }
  280 + this.$emit('change', {
  281 + value,
  282 + name: this.name,
  283 + });
  284 + },
  285 + onChange() {
  286 + const {
  287 + type
  288 + } = this
  289 + if (this.isDisabled(type)) {
  290 + return this.$emit('overlimit', type)
  291 + }
  292 + const diff = type === 'minus' ? -this.step : +this.step
  293 + const value = this.format(this.add(+this.currentValue, diff))
  294 + this.emitChange(value)
  295 + this.$emit(type)
  296 + },
  297 + // 对值扩大后进行四舍五入,再除以扩大因子,避免出现浮点数操作的精度问题
  298 + add(num1, num2) {
  299 + const cardinal = Math.pow(10, 10);
  300 + return Math.round((num1 + num2) * cardinal) / cardinal
  301 + },
  302 + // 点击加减按钮
  303 + clickHandler(type) {
  304 + this.type = type
  305 + this.onChange()
  306 + },
  307 + longPressStep() {
  308 + // 每隔一段时间,重新调用longPressStep方法,实现长按加减
  309 + this.clearTimeout()
  310 + this.longPressTimer = setTimeout(() => {
  311 + this.onChange()
  312 + this.longPressStep()
  313 + }, 250);
  314 + },
  315 + onTouchStart(type) {
  316 + if (!this.longPress) return
  317 + this.clearTimeout()
  318 + this.type = type
  319 + // 一定时间后,默认达到长按状态
  320 + this.longPressTimer = setTimeout(() => {
  321 + this.onChange()
  322 + this.longPressStep()
  323 + }, 600)
  324 + },
  325 + // 触摸结束,清除定时器,停止长按加减
  326 + onTouchEnd() {
  327 + if (!this.longPress) return
  328 + this.clearTimeout()
  329 + },
  330 + // 清除定时器
  331 + clearTimeout() {
  332 + clearTimeout(this.longPressTimer)
  333 + this.longPressTimer = null
366 334 }
367 335 }
  336 +}
368 337 </script>
369 338  
370 339 <style lang="scss" scoped>
371   - @import '../../libs/css/components.scss';
372   -
373   - $u-numberBox-hover-bgColor: #E6E6E6 !default;
374   - $u-numberBox-disabled-color: #c8c9cc !default;
375   - $u-numberBox-disabled-bgColor: #f7f8fa !default;
376   - $u-numberBox-plus-radius: 4px !default;
377   - $u-numberBox-minus-radius: 4px !default;
378   - $u-numberBox-input-text-align: center !default;
379   - $u-numberBox-input-font-size: 15px !default;
380   - $u-numberBox-input-padding: 0 !default;
381   - $u-numberBox-input-margin: 0 2px !default;
382   - $u-numberBox-input-disabled-color: #c8c9cc !default;
383   - $u-numberBox-input-disabled-bgColor: #f2f3f5 !default;
  340 +@import '../../libs/css/components.scss';
384 341  
385   - .u-number-box {
386   - @include flex(row);
387   - align-items: center;
  342 +$u-numberBox-hover-bgColor: #E6E6E6 !default;
  343 +$u-numberBox-disabled-color: #c8c9cc !default;
  344 +$u-numberBox-disabled-bgColor: #f7f8fa !default;
  345 +$u-numberBox-plus-radius: 4px !default;
  346 +$u-numberBox-minus-radius: 4px !default;
  347 +$u-numberBox-input-text-align: center !default;
  348 +$u-numberBox-input-font-size: 15px !default;
  349 +$u-numberBox-input-padding: 0 !default;
  350 +$u-numberBox-input-margin: 0 2px !default;
  351 +$u-numberBox-input-disabled-color: #c8c9cc !default;
  352 +$u-numberBox-input-disabled-bgColor: #f2f3f5 !default;
388 353  
389   - &__slot {
390   - /* #ifndef APP-NVUE */
391   - touch-action: none;
392   - /* #endif */
393   - }
  354 +.u-number-box {
  355 + @include flex(row);
  356 + align-items: center;
394 357  
395   - &__plus,
396   - &__minus {
397   - width: 35px;
398   - @include flex;
399   - justify-content: center;
400   - align-items: center;
401   - /* #ifndef APP-NVUE */
402   - touch-action: none;
403   - /* #endif */
  358 + &__slot {
  359 + /* #ifndef APP-NVUE */
  360 + touch-action: none;
  361 + /* #endif */
  362 + }
404 363  
405   - &--hover {
406   - background-color: $u-numberBox-hover-bgColor !important;
407   - }
  364 + &__plus,
  365 + &__minus {
  366 + width: 35px;
  367 + @include flex;
  368 + justify-content: center;
  369 + align-items: center;
  370 + /* #ifndef APP-NVUE */
  371 + touch-action: none;
  372 + /* #endif */
408 373  
409   - &--disabled {
410   - color: $u-numberBox-disabled-color;
411   - background-color: $u-numberBox-disabled-bgColor;
412   - }
  374 + &--hover {
  375 + background-color: $u-numberBox-hover-bgColor !important;
413 376 }
414 377  
415   - &__plus {
416   - border-top-right-radius: $u-numberBox-plus-radius;
417   - border-bottom-right-radius: $u-numberBox-plus-radius;
  378 + &--disabled {
  379 + color: $u-numberBox-disabled-color;
  380 + background-color: $u-numberBox-disabled-bgColor;
418 381 }
  382 + }
419 383  
420   - &__minus {
421   - border-top-left-radius: $u-numberBox-minus-radius;
422   - border-bottom-left-radius: $u-numberBox-minus-radius;
423   - }
  384 + &__plus {
  385 + border-top-right-radius: $u-numberBox-plus-radius;
  386 + border-bottom-right-radius: $u-numberBox-plus-radius;
  387 + }
  388 +
  389 + &__minus {
  390 + border-top-left-radius: $u-numberBox-minus-radius;
  391 + border-bottom-left-radius: $u-numberBox-minus-radius;
  392 + }
424 393  
425   - &__input {
426   - position: relative;
427   - text-align: $u-numberBox-input-text-align;
428   - font-size: $u-numberBox-input-font-size;
429   - padding: $u-numberBox-input-padding;
430   - margin: $u-numberBox-input-margin;
431   - @include flex;
432   - align-items: center;
433   - justify-content: center;
  394 + &__input {
  395 + position: relative;
  396 + text-align: $u-numberBox-input-text-align;
  397 + font-size: $u-numberBox-input-font-size;
  398 + padding: $u-numberBox-input-padding;
  399 + margin: $u-numberBox-input-margin;
  400 + @include flex;
  401 + align-items: center;
  402 + justify-content: center;
434 403  
435   - &--disabled {
436   - color: $u-numberBox-input-disabled-color;
437   - background-color: $u-numberBox-input-disabled-bgColor;
438   - }
  404 + &--disabled {
  405 + color: $u-numberBox-input-disabled-color;
  406 + background-color: $u-numberBox-input-disabled-bgColor;
439 407 }
440 408 }
  409 +}
441 410 </style>
... ...
garbage-removal/src/uview-plus/components/u-picker/u-picker.vue
... ... @@ -133,7 +133,6 @@ export default {
133 133 // 将当前的各项变化索引,设置为"上一次"的索引变化值
134 134 this.setLastIndex(value)
135 135 this.setIndexs(value)
136   -
137 136 this.$emit('change', {
138 137 // #ifndef MP-WEIXIN || MP-LARK
139 138 // 微信小程序不能传递this,会因为循环引用而报错
... ... @@ -213,13 +212,17 @@ export default {
213 212  
214 213 .u-picker {
215 214 position: relative;
  215 + box-sizing: border-box;
216 216  
217 217 &__view {
218 218  
  219 + box-sizing: border-box;
  220 +
219 221 &__column {
220 222 @include flex;
221 223 flex: 1;
222 224 justify-content: center;
  225 + box-sizing: border-box;
223 226  
224 227 &__item {
225 228 @include flex;
... ... @@ -231,12 +234,14 @@ export default {
231 234 display: block;
232 235 /* #endif */
233 236 color: $u-main-color;
  237 + box-sizing: border-box;
234 238  
235 239 &--disabled {
236 240 /* #ifndef APP-NVUE */
237 241 cursor: not-allowed;
238 242 /* #endif */
239 243 opacity: 0.35;
  244 + box-sizing: border-box;
240 245 }
241 246 }
242 247 }
... ... @@ -253,6 +258,7 @@ export default {
253 258 align-items: center;
254 259 background-color: rgba(255, 255, 255, 0.87);
255 260 z-index: 1000;
  261 + box-sizing: border-box;
256 262 }
257 263 }
258 264 </style>
... ...
garbage-removal/src/uview-plus/components/u-rate/u-rate.vue
1 1 <template>
2   - <view
3   - class="u-rate"
4   - :id="elId"
5   - ref="u-rate"
6   - :style="[$u.addStyle(customStyle)]"
7   - >
8   - <view
9   - class="u-rate__content"
10   - @touchmove.stop="touchMove"
11   - @touchend.stop="touchEnd"
12   - >
13   - <view
14   - class="u-rate__content__item"
15   - v-for="(item, index) in Number(count)"
16   - :key="index"
17   - :class="[elClass]"
18   - >
19   - <view
20   - class="u-rate__content__item__icon-wrap"
21   - ref="u-rate__content__item__icon-wrap"
22   - @tap.stop="clickHandler($event, index + 1)"
23   - >
24   - <u-icon
25   - :name="
26   - Math.floor(activeIndex) > index
27   - ? activeIcon
28   - : inactiveIcon
29   - "
30   - :color="
31   - disabled
32   - ? '#c8c9cc'
33   - : Math.floor(activeIndex) > index
34   - ? activeColor
35   - : inactiveColor
36   - "
37   - :custom-style="{
38   - padding: `0 ${$u.addUnit(gutter / 2)}`,
39   - }"
40   - :size="size"
41   - ></u-icon>
42   - </view>
43   - <view
44   - v-if="allowHalf"
45   - @tap.stop="clickHandler($event, index + 1)"
46   - class="u-rate__content__item__icon-wrap u-rate__content__item__icon-wrap--half"
47   - :style="[{
48   - width: $u.addUnit(rateWidth / 2),
49   - }]"
50   - ref="u-rate__content__item__icon-wrap"
51   - >
52   - <u-icon
53   - :name="
54   - Math.ceil(activeIndex) > index
55   - ? activeIcon
56   - : inactiveIcon
57   - "
58   - :color="
59   - disabled
60   - ? '#c8c9cc'
61   - : Math.ceil(activeIndex) > index
62   - ? activeColor
63   - : inactiveColor
64   - "
65   - :custom-style="{
66   - padding: `0 ${$u.addUnit(gutter / 2)}`
67   - }"
68   - :size="size"
69   - ></u-icon>
70   - </view>
71   - </view>
72   - </view>
73   - </view>
  2 + <view class="u-rate" :id="elId" ref="u-rate" :style="[$u.addStyle(customStyle)]">
  3 + <view class="u-rate__content" @touchmove.stop="touchMove" @touchend.stop="touchEnd">
  4 + <view class="u-rate__content__item" v-for="(item, index) in Number(count)" :key="index" :class="[elClass]">
  5 + <view class="u-rate__content__item__icon-wrap" ref="u-rate__content__item__icon-wrap"
  6 + @tap.stop="clickHandler($event, index + 1)">
  7 + <u-icon :name="Math.floor(activeIndex) > index
  8 + ? activeIcon
  9 + : inactiveIcon
  10 + " :color="disabled
  11 + ? '#c8c9cc'
  12 + : Math.floor(activeIndex) > index
  13 + ? activeColor
  14 + : inactiveColor
  15 + " :custom-style="{
  16 + padding: `0 ${$u.addUnit(gutter / 2)}`,
  17 + }" :size="size"></u-icon>
  18 + </view>
  19 + <view v-if="allowHalf" @tap.stop="clickHandler($event, index + 1)"
  20 + class="u-rate__content__item__icon-wrap u-rate__content__item__icon-wrap--half" :style="[{
  21 + width: $u.addUnit(rateWidth / 2),
  22 + }]" ref="u-rate__content__item__icon-wrap">
  23 + <u-icon :name="Math.ceil(activeIndex) > index
  24 + ? activeIcon
  25 + : inactiveIcon
  26 + " :color="disabled
  27 + ? '#c8c9cc'
  28 + : Math.ceil(activeIndex) > index
  29 + ? activeColor
  30 + : inactiveColor
  31 + " :custom-style="{
  32 + padding: `0 ${$u.addUnit(gutter / 2)}`
  33 + }" :size="size"></u-icon>
  34 + </view>
  35 + </view>
  36 + </view>
  37 + </view>
74 38 </template>
75 39  
76 40 <script>
77   - import props from './props.js';
78   - import mpMixin from '../../libs/mixin/mpMixin.js';
79   - import mixin from '../../libs/mixin/mixin.js';
  41 +import mixin from '../../libs/mixin/mixin.js';
  42 +import mpMixin from '../../libs/mixin/mpMixin.js';
  43 +import props from './props.js';
80 44  
81   - // #ifdef APP-NVUE
82   - const dom = weex.requireModule("dom");
  45 +// #ifdef APP-NVUE
  46 +const dom = weex.requireModule("dom");
  47 +// #endif
  48 +/**
  49 + * rate 评分
  50 + * @description 该组件一般用于满意度调查,星型评分的场景
  51 + * @tutorial https://ijry.github.io/uview-plus/components/rate.html
  52 + * @property {String | Number} value 用于v-model双向绑定选中的星星数量 (默认 1 )
  53 + * @property {String | Number} count 最多可选的星星数量 (默认 5 )
  54 + * @property {Boolean} disabled 是否禁止用户操作 (默认 false )
  55 + * @property {Boolean} readonly 是否只读 (默认 false )
  56 + * @property {String | Number} size 星星的大小,单位px (默认 18 )
  57 + * @property {String} inactiveColor 未选中星星的颜色 (默认 '#b2b2b2' )
  58 + * @property {String} activeColor 选中的星星颜色 (默认 '#FA3534' )
  59 + * @property {String | Number} gutter 星星之间的距离 (默认 4 )
  60 + * @property {String | Number} minCount 最少选中星星的个数 (默认 1 )
  61 + * @property {Boolean} allowHalf 是否允许半星选择 (默认 false )
  62 + * @property {String} activeIcon 选中时的图标名,只能为uView的内置图标 (默认 'star-fill' )
  63 + * @property {String} inactiveIcon 未选中时的图标名,只能为uView的内置图标 (默认 'star' )
  64 + * @property {Boolean} touchable 是否可以通过滑动手势选择评分 (默认 'true' )
  65 + * @property {Object} customStyle 组件的样式,对象形式
  66 + * @event {Function} change 选中的星星发生变化时触发
  67 + * @example <u-rate :count="count" :value="2"></u-rate>
  68 + */
  69 +export default {
  70 + name: "u-rate",
  71 + mixins: [mpMixin, mixin, props],
  72 + data() {
  73 + return {
  74 + // 生成一个唯一id,否则一个页面多个评分组件,会造成冲突
  75 + elId: uni.$u.guid(),
  76 + elClass: uni.$u.guid(),
  77 + rateBoxLeft: 0, // 评分盒子左边到屏幕左边的距离,用于滑动选择时计算距离
  78 + // #ifdef VUE3
  79 + activeIndex: this.modelValue,
  80 + // #endif
  81 + // #ifdef VUE2
  82 + activeIndex: this.value,
  83 + // #endif
  84 + rateWidth: 0, // 每个星星的宽度
  85 + // 标识是否正在滑动,由于iOS事件上touch比click先触发,导致快速滑动结束后,接着触发click,导致事件混乱而出错
  86 + moving: false,
  87 + };
  88 + },
  89 + watch: {
  90 + // #ifdef VUE3
  91 + modelValue(val) {
  92 + this.activeIndex = val;
  93 + },
  94 + // #endif
  95 + // #ifdef VUE2
  96 + value(val) {
  97 + this.activeIndex = val;
  98 + },
  99 + // #endif
  100 + activeIndex: 'emitEvent'
  101 + },
  102 + // #ifdef VUE3
  103 + emits: ['update:modelValue', 'change'],
83 104 // #endif
84   - /**
85   - * rate 评分
86   - * @description 该组件一般用于满意度调查,星型评分的场景
87   - * @tutorial https://ijry.github.io/uview-plus/components/rate.html
88   - * @property {String | Number} value 用于v-model双向绑定选中的星星数量 (默认 1 )
89   - * @property {String | Number} count 最多可选的星星数量 (默认 5 )
90   - * @property {Boolean} disabled 是否禁止用户操作 (默认 false )
91   - * @property {Boolean} readonly 是否只读 (默认 false )
92   - * @property {String | Number} size 星星的大小,单位px (默认 18 )
93   - * @property {String} inactiveColor 未选中星星的颜色 (默认 '#b2b2b2' )
94   - * @property {String} activeColor 选中的星星颜色 (默认 '#FA3534' )
95   - * @property {String | Number} gutter 星星之间的距离 (默认 4 )
96   - * @property {String | Number} minCount 最少选中星星的个数 (默认 1 )
97   - * @property {Boolean} allowHalf 是否允许半星选择 (默认 false )
98   - * @property {String} activeIcon 选中时的图标名,只能为uView的内置图标 (默认 'star-fill' )
99   - * @property {String} inactiveIcon 未选中时的图标名,只能为uView的内置图标 (默认 'star' )
100   - * @property {Boolean} touchable 是否可以通过滑动手势选择评分 (默认 'true' )
101   - * @property {Object} customStyle 组件的样式,对象形式
102   - * @event {Function} change 选中的星星发生变化时触发
103   - * @example <u-rate :count="count" :value="2"></u-rate>
104   - */
105   - export default {
106   - name: "u-rate",
107   - mixins: [mpMixin, mixin, props],
108   - data() {
109   - return {
110   - // 生成一个唯一id,否则一个页面多个评分组件,会造成冲突
111   - elId: uni.$u.guid(),
112   - elClass: uni.$u.guid(),
113   - rateBoxLeft: 0, // 评分盒子左边到屏幕左边的距离,用于滑动选择时计算距离
114   - // #ifdef VUE3
115   - activeIndex: this.modelValue,
116   - // #endif
117   - // #ifdef VUE2
118   - activeIndex: this.value,
119   - // #endif
120   - rateWidth: 0, // 每个星星的宽度
121   - // 标识是否正在滑动,由于iOS事件上touch比click先触发,导致快速滑动结束后,接着触发click,导致事件混乱而出错
122   - moving: false,
123   - };
  105 + methods: {
  106 + init() {
  107 + uni.$u.sleep().then(() => {
  108 + this.getRateItemRect();
  109 + this.getRateIconWrapRect();
  110 + })
124 111 },
125   - watch: {
126   - // #ifdef VUE3
127   - modelValue(val) {
128   - this.activeIndex = val;
129   - },
  112 + // 获取评分组件盒子的布局信息
  113 + async getRateItemRect() {
  114 + await uni.$u.sleep();
  115 + // uView封装的获取节点的方法,详见文档
  116 + // #ifndef APP-NVUE
  117 + this.$uGetRect("#" + this.elId).then((res) => {
  118 + this.rateBoxLeft = res.left;
  119 + });
130 120 // #endif
131   - // #ifdef VUE2
132   - value(val) {
133   - this.activeIndex = val;
134   - },
  121 + // #ifdef APP-NVUE
  122 + dom.getComponentRect(this.$refs["u-rate"], (res) => {
  123 + this.rateBoxLeft = res.size.left;
  124 + });
135 125 // #endif
136   - activeIndex: 'emitEvent'
137 126 },
138   - // #ifdef VUE3
139   - emits: ['update:modelValue', 'change'],
140   - // #endif
141   - methods: {
142   - init() {
143   - uni.$u.sleep().then(() => {
144   - this.getRateItemRect();
145   - this.getRateIconWrapRect();
146   - })
147   - },
148   - // 获取评分组件盒子的布局信息
149   - async getRateItemRect() {
150   - await uni.$u.sleep();
151   - // uView封装的获取节点的方法,详见文档
152   - // #ifndef APP-NVUE
153   - this.$uGetRect("#" + this.elId).then((res) => {
154   - this.rateBoxLeft = res.left;
155   - });
156   - // #endif
157   - // #ifdef APP-NVUE
158   - dom.getComponentRect(this.$refs["u-rate"], (res) => {
159   - this.rateBoxLeft = res.size.left;
160   - });
161   - // #endif
162   - },
163   - // 获取单个星星的尺寸
164   - getRateIconWrapRect() {
165   - // uView封装的获取节点的方法,详见文档
166   - // #ifndef APP-NVUE
167   - this.$uGetRect("." + this.elClass).then((res) => {
168   - this.rateWidth = res.width;
169   - });
170   - // #endif
171   - // #ifdef APP-NVUE
172   - dom.getComponentRect(
173   - this.$refs["u-rate__content__item__icon-wrap"][0],
174   - (res) => {
175   - this.rateWidth = res.size.width;
176   - }
177   - );
178   - // #endif
179   - },
180   - // 手指滑动
181   - touchMove(e) {
182   - // 如果禁止通过手动滑动选择,返回
183   - if (!this.touchable) {
184   - return;
185   - }
186   - this.preventEvent(e);
187   - const x = e.changedTouches[0].pageX;
188   - this.getActiveIndex(x);
189   - },
190   - // 停止滑动
191   - touchEnd(e) {
192   - // 如果禁止通过手动滑动选择,返回
193   - if (!this.touchable) {
194   - return;
195   - }
196   - this.preventEvent(e);
197   - const x = e.changedTouches[0].pageX;
198   - this.getActiveIndex(x);
199   - },
200   - // 通过点击,直接选中
201   - clickHandler(e, index) {
202   - // ios上,moving状态取消事件触发
203   - if (uni.$u.os() === "ios" && this.moving) {
204   - return;
  127 + // 获取单个星星的尺寸
  128 + getRateIconWrapRect() {
  129 + // uView封装的获取节点的方法,详见文档
  130 + // #ifndef APP-NVUE
  131 + this.$uGetRect("." + this.elClass).then((res) => {
  132 + this.rateWidth = res.width;
  133 + });
  134 + // #endif
  135 + // #ifdef APP-NVUE
  136 + dom.getComponentRect(
  137 + this.$refs["u-rate__content__item__icon-wrap"][0],
  138 + (res) => {
  139 + this.rateWidth = res.size.width;
205 140 }
206   - this.preventEvent(e);
207   - let x = 0;
208   - // 点击时,在nvue上,无法获得点击的坐标,所以无法实现点击半星选择
209   - // #ifndef APP-NVUE
210   - x = e.changedTouches[0].pageX;
211   - // #endif
212   - // #ifdef APP-NVUE
213   - // nvue下,无法通过点击获得坐标信息,这里通过元素的位置尺寸值模拟坐标
214   - x = index * this.rateWidth + this.rateBoxLeft;
215   - // #endif
216   - this.getActiveIndex(x,true);
217   - },
218   - // 发出事件
219   - emitEvent() {
220   - // 发出change事件
221   - this.$emit("change", this.activeIndex);
222   - // 同时修改双向绑定的值
223   - // #ifdef VUE3
224   - this.$emit("update:modelValue", this.activeIndex);
225   - // #endif
226   - // #ifdef VUE2
227   - this.$emit("input", this.activeIndex);
228   - // #endif
229   - },
230   - // 获取当前激活的评分图标
231   - getActiveIndex(x,isClick = false) {
232   - if (this.disabled || this.readonly) {
233   - return;
  141 + );
  142 + // #endif
  143 + },
  144 + // 手指滑动
  145 + touchMove(e) {
  146 + // 如果禁止通过手动滑动选择,返回
  147 + if (!this.touchable) {
  148 + return;
  149 + }
  150 + this.preventEvent(e);
  151 + const x = e.changedTouches[0].pageX;
  152 + this.getActiveIndex(x);
  153 + },
  154 + // 停止滑动
  155 + touchEnd(e) {
  156 + // 如果禁止通过手动滑动选择,返回
  157 + if (!this.touchable) {
  158 + return;
  159 + }
  160 + this.preventEvent(e);
  161 + const x = e.changedTouches[0].pageX;
  162 + this.getActiveIndex(x);
  163 + },
  164 + // 通过点击,直接选中
  165 + clickHandler(e, index) {
  166 + // ios上,moving状态取消事件触发
  167 + if (uni.$u.os() === "ios" && this.moving) {
  168 + return;
  169 + }
  170 + this.preventEvent(e);
  171 + let x = 0;
  172 + // 点击时,在nvue上,无法获得点击的坐标,所以无法实现点击半星选择
  173 + // #ifndef APP-NVUE
  174 + x = e.changedTouches[0].pageX;
  175 + // #endif
  176 + // #ifdef APP-NVUE
  177 + // nvue下,无法通过点击获得坐标信息,这里通过元素的位置尺寸值模拟坐标
  178 + x = index * this.rateWidth + this.rateBoxLeft;
  179 + // #endif
  180 + this.getActiveIndex(x, true);
  181 + },
  182 + // 发出事件
  183 + emitEvent() {
  184 + // 发出change事件
  185 + this.$emit("change", this.activeIndex);
  186 + // 同时修改双向绑定的值
  187 + // #ifdef VUE3
  188 + this.$emit("update:modelValue", this.activeIndex);
  189 + // #endif
  190 + // #ifdef VUE2
  191 + this.$emit("input", this.activeIndex);
  192 + // #endif
  193 + },
  194 + // 获取当前激活的评分图标
  195 + getActiveIndex(x, isClick = false) {
  196 + if (this.disabled || this.readonly) {
  197 + return;
  198 + }
  199 + // 判断当前操作的点的x坐标值,是否在允许的边界范围内
  200 + const allRateWidth = this.rateWidth * this.count + this.rateBoxLeft;
  201 + // 如果小于第一个图标的左边界,设置为最小值,如果大于所有图标的宽度,则设置为最大值
  202 + x = uni.$u.range(this.rateBoxLeft, allRateWidth, x) - this.rateBoxLeft
  203 + // 滑动点相对于评分盒子左边的距离
  204 + const distance = x;
  205 + // 滑动的距离,相当于多少颗星星
  206 + let index;
  207 + // 判断是否允许半星
  208 + if (this.allowHalf) {
  209 + index = Math.floor(distance / this.rateWidth);
  210 + // 取余,判断小数的区间范围
  211 + const decimal = distance % this.rateWidth;
  212 + if (decimal <= this.rateWidth / 2 && decimal > 0) {
  213 + index += 0.5;
  214 + } else if (decimal > this.rateWidth / 2) {
  215 + index++;
234 216 }
235   - // 判断当前操作的点的x坐标值,是否在允许的边界范围内
236   - const allRateWidth = this.rateWidth * this.count + this.rateBoxLeft;
237   - // 如果小于第一个图标的左边界,设置为最小值,如果大于所有图标的宽度,则设置为最大值
238   - x = uni.$u.range(this.rateBoxLeft, allRateWidth, x) - this.rateBoxLeft
239   - // 滑动点相对于评分盒子左边的距离
240   - const distance = x;
241   - // 滑动的距离,相当于多少颗星星
242   - let index;
243   - // 判断是否允许半星
244   - if (this.allowHalf) {
245   - index = Math.floor(distance / this.rateWidth);
246   - // 取余,判断小数的区间范围
247   - const decimal = distance % this.rateWidth;
248   - if (decimal <= this.rateWidth / 2 && decimal > 0) {
249   - index += 0.5;
250   - } else if (decimal > this.rateWidth / 2) {
251   - index++;
252   - }
  217 + } else {
  218 + index = Math.floor(distance / this.rateWidth);
  219 + // 取余,判断小数的区间范围
  220 + const decimal = distance % this.rateWidth;
  221 + // 非半星时,只有超过了图标的一半距离,才认为是选择了这颗星
  222 + if (isClick) {
  223 + if (decimal > 0) index++;
253 224 } else {
254   - index = Math.floor(distance / this.rateWidth);
255   - // 取余,判断小数的区间范围
256   - const decimal = distance % this.rateWidth;
257   - // 非半星时,只有超过了图标的一半距离,才认为是选择了这颗星
258   - if (isClick){
259   - if (decimal > 0) index++;
260   - } else {
261   - if (decimal > this.rateWidth / 2) index++;
262   - }
263   -
264   - }
265   - this.activeIndex = Math.min(index, this.count);
266   - // 对最少颗星星的限制
267   - if (this.activeIndex < this.minCount) {
268   - this.activeIndex = this.minCount;
  225 + if (decimal > this.rateWidth / 2) index++;
269 226 }
270 227  
271   - // 设置延时为了让click事件在touchmove之前触发
272   - setTimeout(() => {
273   - this.moving = true;
274   - }, 10);
275   - // 一定时间后,取消标识为移动中状态,是为了让click事件无效
276   - setTimeout(() => {
277   - this.moving = false;
278   - }, 10);
279   - },
280   - },
281   - mounted() {
282   - this.init();
  228 + }
  229 + this.activeIndex = Math.min(index, this.count);
  230 + // 对最少颗星星的限制
  231 + if (this.activeIndex < this.minCount) {
  232 + this.activeIndex = this.minCount;
  233 + }
  234 +
  235 + // 设置延时为了让click事件在touchmove之前触发
  236 + setTimeout(() => {
  237 + this.moving = true;
  238 + }, 10);
  239 + // 一定时间后,取消标识为移动中状态,是为了让click事件无效
  240 + setTimeout(() => {
  241 + this.moving = false;
  242 + }, 10);
283 243 },
284   - };
  244 + },
  245 + mounted() {
  246 + this.init();
  247 + },
  248 +};
285 249 </script>
286 250  
287 251 <style lang="scss" scoped>
... ... @@ -292,35 +256,35 @@ $u-rate-item-icon-wrap-half-top: 0 !default;
292 256 $u-rate-item-icon-wrap-half-left: 0 !default;
293 257  
294 258 .u-rate {
295   - @include flex;
296   - align-items: center;
297   - margin: $u-rate-margin;
298   - padding: $u-rate-padding;
299   - /* #ifndef APP-NVUE */
300   - touch-action: none;
301   - /* #endif */
  259 + @include flex;
  260 + align-items: center;
  261 + margin: $u-rate-margin;
  262 + padding: $u-rate-padding;
  263 + /* #ifndef APP-NVUE */
  264 + touch-action: none;
  265 + /* #endif */
302 266  
303   - &__content {
304   - @include flex;
  267 + &__content {
  268 + @include flex;
305 269  
306 270 &__item {
307   - position: relative;
  271 + position: relative;
308 272  
309   - &__icon-wrap {
310   - &--half {
311   - position: absolute;
312   - overflow: hidden;
313   - top: $u-rate-item-icon-wrap-half-top;
314   - left: $u-rate-item-icon-wrap-half-left;
315   - }
316   - }
  273 + &__icon-wrap {
  274 + &--half {
  275 + position: absolute;
  276 + overflow: hidden;
  277 + top: $u-rate-item-icon-wrap-half-top;
  278 + left: $u-rate-item-icon-wrap-half-left;
  279 + }
  280 + }
317 281 }
318   - }
  282 + }
319 283 }
320 284  
321 285 .u-icon {
322   - /* #ifndef APP-NVUE */
323   - box-sizing: border-box;
324   - /* #endif */
  286 + /* #ifndef APP-NVUE */
  287 + box-sizing: border-box;
  288 + /* #endif */
325 289 }
326 290 </style>
... ...
garbage-removal/src/uview-plus/components/u-transition/u-transition.vue
1 1 <template>
2   - <view
3   - v-if="inited"
4   - class="u-transition"
5   - ref="u-transition"
6   - @tap="clickHandler"
7   - :class="classes"
8   - :style="[mergeStyle]"
9   - @touchmove="noop"
10   - >
  2 + <view v-if="inited" class="u-transition" ref="u-transition" @tap="clickHandler" :class="classes" :style="[mergeStyle]"
  3 + @touchmove="noop">
11 4 <slot />
12 5 </view>
13 6 </template>
14 7  
15 8 <script>
16   -import props from './props.js';
17   -import mpMixin from '../../libs/mixin/mpMixin.js';
18 9 import mixin from '../../libs/mixin/mixin.js';
  10 +import mpMixin from '../../libs/mixin/mpMixin.js';
  11 +import props from './props.js';
19 12 // 组件的methods方法,由于内容较长,写在外部文件中通过mixin引入
20 13 import transition from "./transition.js";
21 14 /**
... ... @@ -49,19 +42,19 @@ export default {
49 42 },
50 43 emits: ['click', 'beforeEnter', 'enter', 'afterEnter', 'beforeLeave', 'leave', 'afterLeave'],
51 44 computed: {
52   - mergeStyle() {
53   - const { viewStyle, customStyle } = this
54   - return {
55   - // #ifndef APP-NVUE
56   - transitionDuration: `${this.duration}ms`,
57   - // display: `${this.display ? '' : 'none'}`,
  45 + mergeStyle() {
  46 + const { viewStyle, customStyle } = this
  47 + return {
  48 + // #ifndef APP-NVUE
  49 + transitionDuration: `${this.duration}ms`,
  50 + // display: `${this.display ? '' : 'none'}`,
58 51 transitionTimingFunction: this.timingFunction,
59   - // #endif
  52 + // #endif
60 53 // 避免自定义样式影响到动画属性,所以写在viewStyle前面
61   - ...uni.$u.addStyle(customStyle),
62   - ...viewStyle
63   - }
64   - }
  54 + ...uni.$u.addStyle(customStyle),
  55 + ...viewStyle
  56 + }
  57 + }
65 58 },
66 59 // 将mixin挂在到组件中,uni.$u.mixin实际上为一个vue格式对象
67 60 mixins: [mpMixin, mixin, transition, props],
... ...