Browse Source

任务详情

master
parent
commit
c222cfd49a
  1. 21
      App.vue
  2. 22
      components/cs-page/index.vue
  3. 12
      pages.json
  4. 36
      pages/enterprise.vue
  5. 186
      pages/task.vue
  6. 3
      static/scss/global.scss
  7. 2
      store/modules/user.js
  8. 2
      sub/chat/index.vue
  9. 2
      sub/enterprise/detail.vue
  10. 487
      sub/task/detail.vue
  11. 1
      uni.scss
  12. 15
      uni_modules/s-components/s-tabber/index.vue
  13. 418
      wxcomponents/vant/circle/index.js
  14. 2
      wxcomponents/vant/circle/index.wxml
  15. 17
      wxcomponents/vant/circle/index.wxss
  16. 285
      wxcomponents/vant/dropdown-item/index.js
  17. 252
      wxcomponents/vant/dropdown-menu/index.js
  18. 3
      wxcomponents/vant/dropdown-menu/index.wxml
  19. 25
      wxcomponents/vant/dropdown-menu/index.wxs
  20. 43
      wxcomponents/vant/dropdown-menu/index.wxss

21
App.vue

@ -23,12 +23,29 @@ export default {
animation: false animation: false
}) })
// //
this.initConfig() await this.initConfig()
// //
this.checkLogin() this.checkLogin()
}, },
initConfig() { async initConfig() {
this.globalData.config = config this.globalData.config = config
uni.requestSubscribeMessage({
//ID
tmplIds: ['E8RK91cPLMios6ZHoKx6FJOV4H2kodx6yPWYp7jpLJY'],
success(res) {
console.log('requestSubscribeMessage', res)
}
})
uni.getSystemInfoAsync({
success: res => {
uni.setStorageSync('MOBILE', res.model)
uni.setStorageSync('SYSTEM', res.system)
uni.setStorageSync('PIXELRATIO', res.pixelRatio)
},
fail: err => {
console.error('获取设备信息失败:', err)
}
})
}, },
checkLogin() { checkLogin() {
if (!getAccessToken()) { if (!getAccessToken()) {

22
components/cs-page/index.vue

@ -1,6 +1,6 @@
<template> <template>
<view class=""> <view class="">
<view class="container" v-if="isTab"> <view class="container" v-if="isTab" :style="{ height: viewHeight }">
<s-header :title="title" :isTab="isTab" :isCustom="isCustom" @goback="$emit('goback')"> <s-header :title="title" :isTab="isTab" :isCustom="isCustom" @goback="$emit('goback')">
<slot name="header"></slot> <slot name="header"></slot>
</s-header> </s-header>
@ -33,7 +33,21 @@ export default {
} }
}, },
data() { data() {
return {} return {
viewHeight: '0px'
}
},
created() {
this.getViewHeight()
},
methods: {
getViewHeight() {
uni.getSystemInfoAsync({
success: res => {
this.viewHeight = `${res.screenHeight}px`
}
})
}
} }
} }
</script> </script>
@ -43,9 +57,6 @@ export default {
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto; grid-template-rows: auto 1fr auto;
height: 100vh;
width: 100vw;
overflow: hidden;
.view { .view {
position: relative; position: relative;
width: 100%; width: 100%;
@ -54,6 +65,7 @@ export default {
position: absolute; position: absolute;
overflow: hidden; overflow: hidden;
inset: 0; inset: 0;
background-color: #f9f9f9;
} }
} }
} }

12
pages.json

@ -93,7 +93,17 @@
}, { }, {
"path": "task/detail", "path": "task/detail",
"style": { "style": {
"navigationBarTitleText": "任务详情" "navigationBarTitleText": "任务详情",
"onReachBottonDistance": 50,
"enablePullDownRefresh": true,
"usingComponents": {
"van-dropdown-menu": "/wxcomponents/vant/dropdown-menu/index",
"van-dropdown-item": "/wxcomponents/vant/dropdown-item/index"
},
"componentPlaceholder": {
"u-modal": "view",
"u-sticky": "view"
}
} }
}] }]
}], }],

36
pages/enterprise.vue

@ -1,11 +1,12 @@
<template> <template>
<cs-page :selected="3" title="企业档案" isTab> <cs-page :selected="3" title="企业档案" isTab>
<view class="page-container"> <view class="page-container" id="page">
<van-search <van-search
:value="queryParams.enterprisesName" :value="queryParams.enterprisesName"
placeholder="输入企业名称或类型查询" placeholder="输入企业名称或类型查询"
@sreach="queryEnterprise" @sreach="queryEnterprise"
@clear="resetQuery('enterpriseName')" @clear="resetQuery('enterpriseName')"
id="sreach"
/> />
<van-dropdown-menu safe-area-tab-bar active-color="#17C653"> <van-dropdown-menu safe-area-tab-bar active-color="#17C653">
<van-dropdown-item <van-dropdown-item
@ -53,6 +54,7 @@
@refresherpulling="refresherpulling" @refresherpulling="refresherpulling"
@scrolltolower="loadMore" @scrolltolower="loadMore"
class="list" class="list"
:style="{ maxHeight: `${listHeight - sreachHeight}px` }"
> >
<view <view
v-for="enterprise in list" v-for="enterprise in list"
@ -81,7 +83,7 @@
{{ $dict.echoDicValue(dictMap.user_audit_type, enterprise.audit) }} {{ $dict.echoDicValue(dictMap.user_audit_type, enterprise.audit) }}
</view> </view>
</view> </view>
<u-loadmore :status="load" marginTop="20" /> <u-loadmore :status="load" marginTop="12" marginBottom="12" />
</scroll-view> </scroll-view>
</view> </view>
</cs-page> </cs-page>
@ -103,6 +105,8 @@ export default {
enterprisesName: '', enterprisesName: '',
tagList: '' tagList: ''
}, },
listHeight: 0,
sreachHeight: 0,
refresherTriggered: false, refresherTriggered: false,
list: [], list: [],
load: 'loadmore', load: 'loadmore',
@ -115,7 +119,25 @@ export default {
onShow() { onShow() {
this.queryEnterprise() this.queryEnterprise()
}, },
onReady() {
this.getPageHeight()
},
methods: { methods: {
getPageHeight() {
const query = uni.createSelectorQuery().in(this)
query
.select('#sreach')
.boundingClientRect(data => {
this.sreachHeight = data.height
})
.exec()
query
.select('#page')
.boundingClientRect(data => {
this.listHeight = data.height - 35
})
.exec()
},
async getList() { async getList() {
uni.showToast({ uni.showToast({
title: '加载中', title: '加载中',
@ -227,8 +249,10 @@ export default {
overflow: hidden; overflow: hidden;
} }
.list { .list {
height: 67vh; display: flex;
padding: 12px; flex-flow: column nowrap;
gap: 12px;
padding: 0 12px;
} }
.enterprise { .enterprise {
padding: 12px; padding: 12px;
@ -242,6 +266,9 @@ export default {
.address { .address {
color: $uni-text-color-grey; color: $uni-text-color-grey;
} }
&:active {
background-color: $cs-color-touch;
}
.tagList { .tagList {
margin-top: 8px; margin-top: 8px;
display: flex; display: flex;
@ -273,6 +300,7 @@ export default {
box-shadow: none; box-shadow: none;
height: 35px; height: 35px;
font-size: 13px; font-size: 13px;
border-bottom: 1px solid #f1f1f4;
} }
::v-deep .u-list { ::v-deep .u-list {

186
pages/task.vue

@ -1,40 +1,40 @@
<template> <template>
<cs-page :selected="1" title="执法任务" isTab> <cs-page :selected="1" title="执法任务" isTab>
<view class="page-container"> <view class="page-container page">
<van-dropdown-menu safe-area-tab-bar active-color="#17C653"> <van-dropdown-menu safe-area-tab-bar active-color="#17C653">
<van-dropdown-item <van-dropdown-item
:value="queryParams.dept" :value="queryParams.status"
:options="getDropdownOption('dept')" :options="getDropdownOption('task_state')"
@change=" @change="
v => { v => {
querySelect(v, 'dept') querySelect(v, 'status')
} }
" "
/> />
<van-dropdown-item <van-dropdown-item
:value="queryParams.hy" :value="queryParams.zf_qy"
:options="getDropdownOption('hy')" :options="getDropdownOption('zf_qy')"
@change=" @change="
v => { v => {
querySelect(v, 'hy') querySelect(v, 'zf_qy')
} }
" "
/> />
<van-dropdown-item <van-dropdown-item
:value="queryParams.st" :value="queryParams.zf_lx"
:options="getDropdownOption('st')" :options="getDropdownOption('zf_lx')"
@change=" @change="
v => { v => {
querySelect(v, 'st') querySelect(v, 'zf_lx')
} }
" "
/> />
<van-dropdown-item <van-dropdown-item
:value="queryParams.wr" :value="queryParams.select_week"
:options="getDropdownOption('wr')" :options="getDropdownOption('select_week')"
@change=" @change="
v => { v => {
querySelect(v, 'wr') querySelect(v, 'select_week')
} }
" "
/> />
@ -47,61 +47,69 @@
@refresherpulling="refresherpulling" @refresherpulling="refresherpulling"
@scrolltolower="loadMore" @scrolltolower="loadMore"
class="list" class="list"
:enable-flex="true"
:style="{ maxHeight: `${listHeight}px` }"
> >
<view <view v-for="task in list" :key="task.id" class="wd-flex wd-items-center enterprise" @click="goDetail(task.id)">
v-for="enterprise in list" <view class="rate">
:key="enterprise.id" <van-circle
class="wd-flex wd-items-center enterprise" :value="task.status == '3' ? 0 : task.pace"
@click="goDetail(enterprise.id)" size="56"
> type="2d"
<van-circle :value="Math.random() * 100" size="56" color="#17c653" layer-color="#F1F1F4"> color="#17c653"
<template> :layer-color="task.status == '2' ? '#EAFFF1' : '#F1F1F4'"
<u-count-to :startVal="0" :endVal="Math.random() * 100" fontSize="16" bold duration="1000"></u-count-to> :canvasId="`canvas-${task.id}`"
% >
</template> <template>
</van-circle> <u-count-to :startVal="0" :endVal="task.pace" fontSize="16" bold duration="1000"></u-count-to>
%
</template>
</van-circle>
</view>
<view class="wd-flex wd-flex-col" style="gap: 4px"> <view class="wd-flex wd-flex-col" style="gap: 4px">
<text class="wd-font-800 wd-text-15 wd-pb-2px">{{ enterprise.enterprisesName }}</text> <text class="wd-font-800 wd-text-15 wd-pb-2px">{{ task.title }}</text>
<view class="wd-flex wd-pb-8px"> <view class="wd-flex wd-pb-8px">
<u-icon name="clock" size="14" color="#17C653"></u-icon> <u-icon name="calendar" size="18" :color="task.status == '2' ? '#17C653' : '#78829D'"></u-icon>
<text class="address wd-text-12" style="margin-left: 4px">于2024年12月15日结束</text> <text
class="address wd-text-12"
style="margin-left: 4px"
:style="{ color: task.status == '2' ? '#17C653' : '#78829D' }"
>
{{ $util.formatDate(task.endDate, 'YYYY年MM月DD日') }}结束
</text>
</view> </view>
<view class="tagList"> <view class="tagList">
<view class="tag" v-for="(tag, index) in enterprise.tagList" :key="index"> <view class="tag" v-for="(tag, index) in task.tagList" :key="index">
{{ tag }} {{ tag }}
</view> </view>
</view> </view>
</view> </view>
<view <view class="audit">
class="audit" <cs-dict-tag :dict="dictMap.task_state" :value="task.status"></cs-dict-tag>
v-if="enterprise.audit != 2"
:style="{ color: enterprise.audit == 1 ? '#F6B100' : '#ea000c', backgroundColor: '#FFF8DD' }"
>
{{ $dict.echoDicValue(dictMap.user_audit_type, enterprise.audit) }}
</view> </view>
</view> </view>
<u-loadmore :status="load" marginTop="20" /> <u-loadmore :status="load" marginTop="12" marginBottom="12" />
</scroll-view> </scroll-view>
</view> </view>
</cs-page> </cs-page>
</template> </template>
<script> <script>
import { getEnterPriseList } from '@/api/enterprise/index.js'
import { getDictBatchByType, getDeptTree, getTagData } from '@/api/system/dict.js' import { getDictBatchByType, getDeptTree, getTagData } from '@/api/system/dict.js'
import { TaskApi } from '@/api/task/index.js'
export default { export default {
data() { data() {
return { return {
queryParams: { queryParams: {
pageSize: 10, pageSize: 10,
pageNo: 1, pageNo: 1,
qy: '', zf_lx: '',
hy: '', zf_qy: '',
st: '', status: '',
wr: '', select_week: '',
dept: '',
tagList: '' tagList: ''
}, },
listHeight: 0,
refresherTriggered: false, refresherTriggered: false,
list: [], list: [],
load: 'loadmore', load: 'loadmore',
@ -111,10 +119,20 @@ export default {
async onLoad() { async onLoad() {
await this.getDict() await this.getDict()
}, },
onShow() { onReady() {
this.getPageHeight()
this.queryEnterprise() this.queryEnterprise()
}, },
methods: { methods: {
getPageHeight() {
const query = uni.createSelectorQuery().in(this)
query
.select('.page')
.boundingClientRect(data => {
this.listHeight = data.height - 55
})
.exec()
},
async getList() { async getList() {
uni.showToast({ uni.showToast({
title: '加载中', title: '加载中',
@ -122,8 +140,15 @@ export default {
icon: 'loading' icon: 'loading'
}) })
this.load = 'loading' this.load = 'loading'
const res = await getEnterPriseList(this.queryParams) const res = await TaskApi.getList(this.queryParams)
this.list.push(...res.data.list) this.list.push(
...res.data.list.map((i, index) => {
return {
...i,
pace: (i.taskFinishNum / i.taskExecNum) * 100
}
})
)
this.load = 'loadmore' this.load = 'loadmore'
if (this.list.length == res.data.total) { if (this.list.length == res.data.total) {
this.load = 'nomore' this.load = 'nomore'
@ -131,37 +156,26 @@ export default {
uni.hideToast() uni.hideToast()
}, },
async getDict() { async getDict() {
const tags = await getTagData(['qy', ' hy', 'st', 'wr'].join(',')) const tags = await getTagData(['zf_lx', 'zf_qy'].join(','))
const dict = await getDictBatchByType({ type: ['user_audit_type'].join(',') }) const dict = await getDictBatchByType({ type: ['select_week', 'task_state'].join(',') })
const dept = await getDeptTree()
let tagMap = {} let tagMap = {}
tags.data.forEach(t => { tags.data.forEach(t => {
tagMap[t.tagCode] = t.children tagMap[t.tagCode] = t.children
}) })
this.dictMap = { this.dictMap = {
...tagMap, ...tagMap,
...dict.data, ...dict.data
dept: dept.data.map(i => {
return {
...i,
text: i.name,
value: i.id
}
})
} }
}, },
getDropdownOption(key) { getDropdownOption(key) {
if (!this.dictMap[key]) return [] if (!this.dictMap[key]) return []
const keyMap = { const keyMap = {
qy: '区域', zf_qy: '按区域',
hy: '行业', zf_lx: '按类型',
st: '生态', task_state: '按状态',
wr: '污染', select_week: '按周期'
dept: '全部部门'
} }
if (key == 'dept') { if (['zf_qy', 'zf_lx'].includes(key)) {
return [...this.dictMap[key], { value: '', text: keyMap[key] }]
} else {
return [ return [
...this.dictMap[key].map(d => { ...this.dictMap[key].map(d => {
return { return {
@ -171,6 +185,16 @@ export default {
}), }),
{ value: '', text: keyMap[key] } { value: '', text: keyMap[key] }
] ]
} else {
return [
...this.dictMap[key].map(d => {
return {
value: d.value,
text: d.label
}
}),
{ value: '', text: keyMap[key] }
]
} }
}, },
querySelect(v, key) { querySelect(v, key) {
@ -181,9 +205,7 @@ export default {
this.queryParams.pageNo = 1 this.queryParams.pageNo = 1
this.load = 'loadmore' this.load = 'loadmore'
this.list = [] this.list = []
this.queryParams.tagList = [this.queryParams.qy, this.queryParams.hy, this.queryParams.st, this.queryParams.wr] this.queryParams.tagList = [this.queryParams.zf_qy, this.queryParams.zf_lx].filter(i => i != '').join()
.filter(i => i != '')
.join()
this.getList() this.getList()
}, },
loadMore() { loadMore() {
@ -213,11 +235,10 @@ export default {
this.queryParams = { this.queryParams = {
pageSize: 10, pageSize: 10,
pageNo: 1, pageNo: 1,
qy: '', zf_lx: '',
hy: '', zf_qy: '',
st: '', status: '',
wr: '', select_week: '',
dept: '',
tagList: '' tagList: ''
} }
await this.queryEnterprise() await this.queryEnterprise()
@ -237,8 +258,7 @@ export default {
overflow: hidden; overflow: hidden;
} }
.list { .list {
height: 75vh; padding: 0 12px;
padding: 12px;
} }
.enterprise { .enterprise {
padding: 12px; padding: 12px;
@ -249,6 +269,9 @@ export default {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
font-size: 12px; font-size: 12px;
&:active {
background-color: $cs-color-touch;
}
.address { .address {
color: $uni-text-color-grey; color: $uni-text-color-grey;
} }
@ -270,19 +293,20 @@ export default {
} }
.audit { .audit {
position: absolute; position: absolute;
right: -19px; right: 0;
top: 6px; top: 0;
transform: rotateZ(45deg);
transform-origin: 50% 50%; transform-origin: 50% 50%;
padding: 4px 20px; transform: translateX(28px) translateY(9px) rotateZ(45deg);
font-size: 12px; }
text-align: center; .rate {
position: relative;
} }
} }
::v-deep .van-dropdown-menu { ::v-deep .van-dropdown-menu {
box-shadow: none; box-shadow: none;
height: 35px; height: 35px !important;
font-size: 13px; font-size: 13px;
border-bottom: 1px solid #f1f1f4;
} }
::v-deep .u-list { ::v-deep .u-list {

3
static/scss/global.scss

@ -0,0 +1,3 @@
page {
background-color: #f9f9f9;
}

2
store/modules/user.js

@ -75,7 +75,7 @@ const user = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo().then(res => { getInfo().then(res => {
const user = res.data.user const user = res.data.user
if (res.roles && res.roles.length > 0) { if (res.data.roles && res.data.roles.length > 0) {
commit('SET_ROLES', res.roles) commit('SET_ROLES', res.roles)
commit('SET_PERMISSIONS', res.permissions) commit('SET_PERMISSIONS', res.permissions)
} else { } else {

2
sub/chat/index.vue

@ -1,5 +1,5 @@
<template> <template>
<web-view src="https://mb.jzce.com/chat/313cf9e35628923a"></web-view> <web-view src="https://mb.jzce.com/chat/f07644a8e53c750a"></web-view>
</template> </template>
<script> <script>

2
sub/enterprise/detail.vue

@ -57,7 +57,7 @@
</view> </view>
<view class="box"> <view class="box">
<view class="wd-font-800">检查记录</view> <view class="wd-font-800">执法记录</view>
</view> </view>
<view class="button-box"> <view class="button-box">

487
sub/task/detail.vue

@ -1,85 +1,306 @@
<template> <template>
<cs-page> <cs-page>
<view class="detail-container"> <view class="detail-container" :style="{ paddingBottom: isSelect.length > 0 ? '70px' : '20px' }">
<view class="box detail"> <view class="box detail">
<text class="wd-font-800 wd-text-16" style="margin-bottom: 4px">xxxx</text> <text class="wd-font-800 wd-text-16" style="margin-bottom: 4px">{{ detail.title }}</text>
<view class="tagList"> <view class="tagList">
<view v-for="(item, index) in 3" :key="index" class="tag">标签{{ index }}</view> <view v-for="(tag, index) in detail.tagList" :key="index" class="tag">{{ tag }}</view>
</view> </view>
<view class="wd-flex wd-text-13" style="justify-content: space-between"> <view class="wd-flex wd-text-13" style="justify-content: space-between">
<view class="wd-flex" style="align-items: center; gap: 4px"> <view class="wd-flex" style="align-items: center; gap: 4px">
<u-icon name="calendar" color="#17C653" /> <u-icon name="calendar" color="#17C653" />
<text class="wd-text-13 wd-ml-4px">2024/12/15~2025/12/15</text> <text class="wd-text-13 wd-ml-4px">
{{ $util.formatDate(detail.startDate, 'YYYY/M/D') }} ~ {{ $util.formatDate(detail.endDate, 'YYYY/M/D') }}
</text>
</view> </view>
<view class="wd-flex" style="align-items: center; gap: 4px"> </view>
<u-icon name="account" color="#17C653" /> <view
<text class="wd-text-13 wd-font-800">姓名</text> style="font-size: 13px; line-height: 160%; position: relative; transform: 0.2s all"
<text class="wd-text-13">部门</text> v-if="detail.description.length < 20"
>
{{ detail.description }}
</view>
<view
v-else
style="font-size: 13px; line-height: 160%; position: relative; transform: 0.2s all"
@tap="isShowAllText = !isShowAllText"
>
{{ isShowAllText ? detail.description : `${detail.description.slice(1, 20)}...` }}
<text style="color: #17c653; padding-left: 4px">{{ isShowAllText ? '收起' : '展开' }}</text>
</view>
<view class="audit">
<cs-dict-tag :dict="dictMap.task_state" :value="detail.status"></cs-dict-tag>
</view>
</view>
<u-sticky>
<view :class="['options-container', OptionsOffset.isTop ? 'isTop' : '']" ref="optionRef" id="options">
<van-dropdown-menu safe-area-tab-bar active-color="#17C653" style="flex: 1">
<van-dropdown-item
:value="queryParams.dept"
:options="getDropdownOption('dept')"
@change="
v => {
querySelect(v, 'dept')
}
"
/>
<van-dropdown-item
:value="queryParams.Inspections_status"
:options="getDropdownOption('Inspections_status')"
@change="
v => {
querySelect(v, 'Inspections_status')
}
"
/>
</van-dropdown-menu>
<view class="wd-font-600">
(当前
<text style="color: #17c653">{{ list.length }}</text>
条记录)
</view> </view>
</view> </view>
<view class="" style="font-size: 13px; line-height: 160%"> </u-sticky>
任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求任务要求 <view class="record" v-for="record in list" :key="record.id">
<view
:class="{ select: true, isSelect: isSelect.includes(record.id) }"
@tap.self="select(record.id)"
v-if="[3, null].includes(record.inspectionStatus)"
>
<u-icon name="checkbox-mark" size="16px" color="#fff"></u-icon>
</view>
<view class="disable" v-else></view>
<view class="info">
<view class="name">{{ record.enterpriseAddress }}</view>
<view style="font-size: 1 3px">{{ record.enterpriseAddress }}</view>
<view class="tagList" style="margin-top: 8px">
<view v-for="(item, index) in record.tagList" :key="index" class="tag">{{ item }}</view>
</view>
</view> </view>
<view class="audit">111</view> <view class="audit" v-show="record.inspectionStatus">
<cs-dict-tag :dict="dictMap.Inspections_status" :value="record.inspectionStatus"></cs-dict-tag>
</view>
</view>
<u-loadmore :status="load" marginTop="12" marginBottom="12" />
<view class="btn-box" v-if="isSelect.length > 0">
<view class="confirm-btn" @tap="replay">已选择({{ isSelect.length }})</view>
</view> </view>
<scroll-view scroll-y="true" class="list"> <u-modal :show="model.show" closeOnClickOverlay @close="closeModel">
<view class="record" v-for="record in 10" :key="record.id"> <view class="wd-flex wd-flex-col" style="gap: 20px">
<view :class="{ select: true, isSelect: false }" @tap="select()"> <view class="header">
<u-icon name="checkbox-mark" size="16px" color="#fff"></u-icon> <view class="row-1">
已选择
<text class="num">{{ isSelect.length }}项记录</text>
转移给
</view>
<view class="row-2">每次只能选择一人</view>
</view> </view>
<view class="info"> <view class="staff-list">
<view class="name">义县某某环保企业名称</view> <view
<view style="font-size: 13px">某某区工业产业园5-182</view> class="staff"
<view class="tagList" style="margin-top: 8px"> v-for="(staff, index) in 10"
<view v-for="(item, index) in 3" :key="index" class="tag">标签{{ index }}</view> :key="staff.id"
:style="{ '--select-color': index == 0 ? '#17c653' : '#f1f1f4' }"
>
<u-avatar size="40" shape="circle"></u-avatar>
<view class="info">
<view class="name">姓名</view>
<view class="dept">部门</view>
</view>
<view class="isSelect">
<u-icon name="checkbox-mark" size="16px" color="#fff"></u-icon>
</view>
</view> </view>
</view> </view>
<view class="audit">111</view>
</view> </view>
<u-loadmore :status="load" marginTop="20" /> <template #confirmButton>
</scroll-view> <view class="wd-flex wd-flex-center">
<view class="confirm-btn">转移给TA</view>
</view>
</template>
</u-modal>
</view> </view>
</cs-page> </cs-page>
</template> </template>
<script> <script>
import { getEnterPrise } from '@/api/enterprise/index.js' import { getDeptTree, getDictBatchByType } from '@/api/system/dict.js'
import { getDictBatchByType } from '@/api/system/dict.js' import { TaskApi } from '@/api/task/index.js'
import { InspectionsApi } from '@/api/inspections/index.js'
export default { export default {
data() { data() {
return { return {
//
detail: { detail: {
id: '' id: '',
description: ''
},
list: [],
//
isShowAllText: false,
//
isSelect: [],
dictMap: {},
//u-sticky
OptionsOffset: {
top: 0,
isTop: false
}, },
isSelect: false, //
dictMap: {} queryParams: {
dept: '',
Inspections_status: '',
pageSize: 8,
pageNo: 1,
taskId: ''
},
load: 'loadmore',
model: {
show: false
}
} }
}, },
onLoad(res) { onLoad(res) {
if (res.id) { this.queryParams.taskId = res.id
this.detail.id = res.id this.getDict()
}
// this.getDict()
this.init() this.init()
}, },
onPageScroll(e) {
this.OptionsOffset.isTop = e.scrollTop + 10 > this.OptionsOffset.top
},
onReady() {
this.getOptionOffset()
},
onReachBottom() {
this.loadMore()
},
onPullDownRefresh() {
this.reset()
},
methods: { methods: {
getOptionOffset() {
const query = uni.createSelectorQuery().in(this)
query
.select('#options')
.boundingClientRect(data => {
this.OptionsOffset.top = data.top
})
.exec()
},
/** /**
* 获取字典 * 获取字典
*/ */
async getDict() { async getDict() {
const dict = await getDictBatchByType({ type: ['enterprises_type', 'enterprise_qua'].join(',') }) const dict = await getDictBatchByType({ type: ['task_state', 'Inspections_status'].join(',') })
const dept = await getDeptTree()
this.dictMap = { this.dictMap = {
...dict.data ...dict.data,
dept: dept.data
}
},
getDropdownOption(key) {
const keyMap = {
dept: '按部门',
Inspections_status: '按状态'
}
if (!this.dictMap[key]) return []
if (key == 'dept') {
return [
...this.dictMap[key].map(d => {
return {
...d,
value: d.id,
text: d.name
}
}),
{
value: '',
text: keyMap[key]
}
]
}
return [
...this.dictMap[key].map(d => {
return {
value: d.value,
text: d.label
}
}),
{ value: '', text: keyMap[key] }
]
},
querySelect(v, key) {
this.queryParams[key] = v.detail
// this.queryEnterprise()
},
async init() {
const res = await TaskApi.getDetail(this.queryParams.taskId)
this.detail = res.data
this.getList()
},
async getList() {
uni.showToast({
title: '加载中',
mask: true,
icon: 'loading'
})
this.load = 'loading'
const { data } = await InspectionsApi.getList(this.queryParams)
this.list.push(...data.list)
this.load = 'loadmore'
if (this.list.length == data.total) {
this.load = 'nomore'
} }
uni.hideToast()
}, },
async init() {},
goBack() { goBack() {
uni.switchTab({ uni.switchTab({
url: '/pages/task' url: '/pages/task'
}) })
}, },
select() { loadMore() {
this.isSelect = !this.isSelect if (this.load == 'nomore') {
uni.showToast({
title: '没有更多了',
icon: 'none'
})
return
}
this.queryParams.pageNo++
this.getList()
},
select(id) {
if (this.isSelect.includes(id)) {
this.isSelect = this.isSelect.filter(i => i != id)
} else {
this.isSelect.push(id)
}
},
async reset() {
this.queryParams = {
dept: '',
Inspections_status: '',
pageSize: 8,
pageNo: 1,
taskId: ''
}
await this.queryList()
},
queryList() {
this.queryParams.pageNo = 1
this.load = 'loadmore'
this.list = []
this.getList()
},
replay() {
this.model.show = true
},
closeModel() {
this.model.show = false
} }
} }
} }
@ -87,11 +308,10 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.detail-container { .detail-container {
padding: 12px;
position: relative; position: relative;
color: $cs-color-grey; color: $cs-color-grey;
.box { .box {
margin-bottom: 12px; margin: 12px;
background-color: #fff; background-color: #fff;
border-radius: $cs-border-radius; border-radius: $cs-border-radius;
padding: 16px; padding: 16px;
@ -101,6 +321,14 @@ export default {
flex-flow: column nowrap; flex-flow: column nowrap;
gap: 12px; gap: 12px;
position: relative; position: relative;
overflow: hidden;
.audit {
position: absolute;
right: 0;
top: 0;
transform: translateX(23px) translateY(16px) rotateZ(45deg);
transform-origin: 50% 50%;
}
} }
.tagList { .tagList {
display: flex; display: flex;
@ -122,52 +350,165 @@ export default {
line-height: normal; line-height: normal;
} }
} }
.list { .record {
height: 65vh; background-color: #fff;
padding-bottom: 30px; display: flex;
.record { padding: 12px 16px;
background-color: #fff; align-items: center;
border-radius: var(--Number-8px, 8px);
border: 1px solid var(--LightMode-Grey-Grey-100, #f9f9f9);
margin: 12px;
margin-top: 0;
position: relative;
overflow: hidden;
.audit {
position: absolute;
right: 0;
top: 0;
transform-origin: 50% 50%;
transform: translateX(30px) translateY(10px) rotateZ(45deg);
}
.select {
width: 24px;
height: 24px;
border: 2px solid $cs-color-main;
border-radius: 6px;
display: flex; display: flex;
padding: var(--Number-12px, 12px);
align-items: center; align-items: center;
border-radius: var(--Number-8px, 8px); justify-content: center;
border: 1px solid var(--LightMode-Grey-Grey-100, #f9f9f9); transition: 0.2s all;
margin-bottom: 12px; margin-right: 16px;
}
.disable {
width: 24px;
height: 24px;
border: 2px solid #dbdfe9;
margin-right: 16px;
border-radius: 100%;
position: relative; position: relative;
.select { &::after {
width: 24px; content: '';
height: 24px; position: absolute;
border: 2px solid $cs-color-main; inset: 0;
border-radius: 6px; border-left: 2px solid #dbdfe9;
display: flex; transform-origin: 0 50%;
align-items: center; transform: translateX(calc(50% - 1px)) rotateZ(45deg);
justify-content: center;
transition: 0.2s all;
margin-right: 16px;
} }
.isSelect { }
background-color: $cs-color-main; .isSelect {
background-color: $cs-color-main;
}
.info {
font-size: 13px;
.name {
font-size: 16px;
font-weight: 600;
color: #071437;
margin-bottom: 4px;
}
}
&:active {
background-color: $cs-color-touch;
}
}
.btn-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 30px;
position: fixed;
bottom: 0;
left: 0;
}
.confirm-btn {
background-color: $cs-color-main;
padding: 12px 40px;
color: #fff;
font-size: 16px;
font-weight: 600;
border-radius: 120px;
}
.header {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
gap: 4px;
.row-1 {
font-size: 16px;
font-weight: 600;
color: #071437;
.num {
color: $cs-color-main;
padding: 0 4px;
} }
}
.row-2 {
color: $cs-color-grey;
}
}
.staff-list {
width: 70vw;
display: flex;
flex-flow: row wrap;
gap: 12px;
max-height: 30vh;
overflow-y: scroll;
.staff {
width: calc(50% - 6px);
padding: 12px;
border-radius: 6px;
border: 1px solid var(--select-color, #dbdfe9);
position: relative;
gap: 8px;
display: flex;
.info { .info {
font-size: 13px;
.name { .name {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: bold;
color: #071437; }
margin-bottom: 4px; .dept {
color: $cs-color-grey;
} }
} }
.isSelect {
position: absolute;
right: 0;
top: 0;
width: 30px;
height: 30px;
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0) 50%, var(--select-color, #f1f1f4) 50%);
display: flex;
justify-content: flex-end;
align-items: flex-start;
}
} }
} }
.audit { }
position: absolute; .options-container {
right: -10px; overflow: hidden;
top: 6px; margin: 12px;
transform: rotateZ(45deg); border-radius: 8px;
transform-origin: 50% 50%; transition: 0.1s all;
padding: 4px 20px; display: flex;
font-size: 12px; padding: 0 12px;
text-align: center; flex-flow: row nowrap;
justify-content: center;
align-items: center;
background-color: #fff;
border-bottom: 1px solid #f1f1f4;
color: #071437;
::v-deep .van-dropdown-menu {
background-color: transparent;
box-shadow: none;
--dropdown-menu-title-font-size: 13px;
--dropdown-menu-title-text-color: #071437;
} }
} }
.isTop {
margin: 12px 0;
border-radius: 0px;
}
</style> </style>

1
uni.scss

@ -68,3 +68,4 @@ $cs-border-radius: 8px;
$cs-gap: 10px; $cs-gap: 10px;
$cs-color-main: #17c653; $cs-color-main: #17c653;
$cs-color-grey: #4b5675; $cs-color-grey: #4b5675;
$cs-color-touch: #f9f9f9;

15
uni_modules/s-components/s-tabber/index.vue

@ -19,7 +19,7 @@
</view> </view>
</view> </view>
</view> </view>
<view class="fit-content"></view> <view :style="{ height: isFit ? '25px' : '12px' }"></view>
</view> </view>
</template> </template>
@ -43,7 +43,7 @@ export default {
code: 0 code: 0
}, },
{ {
name: '任务', name: '执法',
path: '/pages/task', path: '/pages/task',
icon: '/static/images/tabbers/task.png', icon: '/static/images/tabbers/task.png',
selectIcon: '/static/images/tabbers/task-select.png', selectIcon: '/static/images/tabbers/task-select.png',
@ -77,6 +77,9 @@ export default {
computed: { computed: {
setClass() { setClass() {
return this.$props.isTab ? 'container' : 'noTab' return this.$props.isTab ? 'container' : 'noTab'
},
isFit() {
return uni.getStorageSync('SYSTEM').includes('iOS')
} }
}, },
methods: { methods: {
@ -95,20 +98,16 @@ export default {
<style lang="scss"> <style lang="scss">
.container { .container {
background-color: #fff; background-color: #fff;
// box-shadow: 0 -1px 2px 1px $cs-shadow-color;
} }
.noTab { .noTab {
// background-color: #fff;
}
.fit-content {
height: 20px;
} }
.tabber { .tabber {
height: 60px;
display: flex; display: flex;
flex-flow: row nowrap; flex-flow: row nowrap;
justify-content: space-around; justify-content: space-around;
align-items: center; align-items: center;
border-top: 1px solid #f1f1f4;
padding: 12px 32px 0px 32px;
.tab { .tab {
transition: 0.2s all; transition: 0.2s all;
} }

418
wxcomponents/vant/circle/index.js

@ -1,197 +1,233 @@
import { BLUE, WHITE } from '../common/color'; import {
import { VantComponent } from '../common/component'; BLUE,
import { getSystemInfoSync } from '../common/utils'; WHITE
import { isObj } from '../common/validator'; } from '../common/color';
import { canIUseCanvas2d } from '../common/version'; import {
import { adaptor } from './canvas'; VantComponent
} from '../common/component';
import {
getSystemInfoSync
} from '../common/utils';
import {
isObj
} from '../common/validator';
import {
canIUseCanvas2d
} from '../common/version';
import {
adaptor
} from './canvas';
function format(rate) { function format(rate) {
return Math.min(Math.max(rate, 0), 100); return Math.min(Math.max(rate, 0), 100);
} }
const PERIMETER = 2 * Math.PI; const PERIMETER = 2 * Math.PI;
const BEGIN_ANGLE = -Math.PI / 2; const BEGIN_ANGLE = -Math.PI / 2;
const STEP = 1; const STEP = 1;
VantComponent({ VantComponent({
props: { props: {
text: String, text: String,
lineCap: { lineCap: {
type: String, type: String,
value: 'round', value: 'round',
}, },
value: { value: {
type: Number, type: Number,
value: 0, value: 0,
observer: 'reRender', observer: 'reRender',
}, },
speed: { speed: {
type: Number, type: Number,
value: 50, value: 50,
}, },
size: { size: {
type: Number, type: Number,
value: 100, value: 100,
observer() { observer() {
this.drawCircle(this.currentValue); this.drawCircle(this.currentValue);
}, },
}, },
fill: String, fill: String,
layerColor: { layerColor: {
type: String, type: String,
value: WHITE, value: WHITE,
}, },
color: { color: {
type: null, type: null,
value: BLUE, value: BLUE,
observer() { observer() {
this.setHoverColor().then(() => { this.setHoverColor().then(() => {
this.drawCircle(this.currentValue); this.drawCircle(this.currentValue);
}); });
}, },
}, },
type: { type: {
type: String, type: String,
value: '', value: '',
}, },
strokeWidth: { strokeWidth: {
type: Number, type: Number,
value: 4, value: 4,
}, },
clockwise: { clockwise: {
type: Boolean, type: Boolean,
value: true, value: true,
}, },
}, canvasId: {
data: { type: String,
hoverColor: BLUE, value: ''
}, }
methods: { },
getContext() { data: {
const { type, size } = this.data; hoverColor: BLUE,
if (type === '' || !canIUseCanvas2d()) { },
const ctx = wx.createCanvasContext('van-circle', this); methods: {
return Promise.resolve(ctx); getContext() {
} const {
const dpr = getSystemInfoSync().pixelRatio; type,
return new Promise((resolve) => { size
wx.createSelectorQuery() } = this.data;
.in(this) if (type === '' || !canIUseCanvas2d()) {
.select('#van-circle') const ctx = wx.createCanvasContext('van-circle', this);
.node() return Promise.resolve(ctx);
.exec((res) => { }
const canvas = res[0].node; const dpr = getSystemInfoSync().pixelRatio;
const ctx = canvas.getContext(type); return new Promise((resolve) => {
if (!this.inited) { wx.createSelectorQuery()
this.inited = true; .in(this)
canvas.width = size * dpr; .select('#van-circle')
canvas.height = size * dpr; .node()
ctx.scale(dpr, dpr); .exec((res) => {
} const canvas = res[0].node;
resolve(adaptor(ctx)); const ctx = canvas.getContext(type);
}); if (!this.inited) {
}); this.inited = true;
}, canvas.width = size * dpr;
setHoverColor() { canvas.height = size * dpr;
const { color, size } = this.data; ctx.scale(dpr, dpr);
if (isObj(color)) { }
return this.getContext().then((context) => { resolve(adaptor(ctx));
if (!context) });
return; });
const LinearColor = context.createLinearGradient(size, 0, 0, 0); },
Object.keys(color) setHoverColor() {
.sort((a, b) => parseFloat(a) - parseFloat(b)) const {
.map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key])); color,
this.hoverColor = LinearColor; size
}); } = this.data;
} if (isObj(color)) {
this.hoverColor = color; return this.getContext().then((context) => {
return Promise.resolve(); if (!context)
}, return;
presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) { const LinearColor = context.createLinearGradient(size, 0, 0, 0);
const { strokeWidth, lineCap, clockwise, size } = this.data; Object.keys(color)
const position = size / 2; .sort((a, b) => parseFloat(a) - parseFloat(b))
const radius = position - strokeWidth / 2; .map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key]));
context.setStrokeStyle(strokeStyle); this.hoverColor = LinearColor;
context.setLineWidth(strokeWidth); });
context.setLineCap(lineCap); }
context.beginPath(); this.hoverColor = color;
context.arc(position, position, radius, beginAngle, endAngle, !clockwise); return Promise.resolve();
context.stroke(); },
if (fill) { presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) {
context.setFillStyle(fill); const {
context.fill(); strokeWidth,
} lineCap,
}, clockwise,
renderLayerCircle(context) { size
const { layerColor, fill } = this.data; } = this.data;
this.presetCanvas(context, layerColor, 0, PERIMETER, fill); const position = size / 2;
}, const radius = position - strokeWidth / 2;
renderHoverCircle(context, formatValue) { context.setStrokeStyle(strokeStyle);
const { clockwise } = this.data; context.setLineWidth(strokeWidth);
// 结束角度 context.setLineCap(lineCap);
const progress = PERIMETER * (formatValue / 100); context.beginPath();
const endAngle = clockwise context.arc(position, position, radius, beginAngle, endAngle, !clockwise);
? BEGIN_ANGLE + progress context.stroke();
: 3 * Math.PI - (BEGIN_ANGLE + progress); if (fill) {
this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle); context.setFillStyle(fill);
}, context.fill();
drawCircle(currentValue) { }
const { size } = this.data; },
this.getContext().then((context) => { renderLayerCircle(context) {
if (!context) const {
return; layerColor,
context.clearRect(0, 0, size, size); fill
this.renderLayerCircle(context); } = this.data;
const formatValue = format(currentValue); this.presetCanvas(context, layerColor, 0, PERIMETER, fill);
if (formatValue !== 0) { },
this.renderHoverCircle(context, formatValue); renderHoverCircle(context, formatValue) {
} const {
context.draw(); clockwise
}); } = this.data;
}, // 结束角度
reRender() { const progress = PERIMETER * (formatValue / 100);
// tofector 动画暂时没有想到好的解决方案 const endAngle = clockwise ?
const { value, speed } = this.data; BEGIN_ANGLE + progress :
if (speed <= 0 || speed > 1000) { 3 * Math.PI - (BEGIN_ANGLE + progress);
this.drawCircle(value); this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle);
return; },
} drawCircle(currentValue) {
this.clearMockInterval(); const {
this.currentValue = this.currentValue || 0; size
const run = () => { } = this.data;
this.interval = setTimeout(() => { this.getContext().then((context) => {
if (this.currentValue !== value) { if (!context)
if (Math.abs(this.currentValue - value) < STEP) { return;
this.currentValue = value; context.clearRect(0, 0, size, size);
} this.renderLayerCircle(context);
else if (this.currentValue < value) { const formatValue = format(currentValue);
this.currentValue += STEP; if (formatValue !== 0) {
} this.renderHoverCircle(context, formatValue);
else { }
this.currentValue -= STEP; context.draw();
} });
this.drawCircle(this.currentValue); },
run(); reRender() {
} // tofector 动画暂时没有想到好的解决方案
else { const {
this.clearMockInterval(); value,
} speed
}, 1000 / speed); } = this.data;
}; if (speed <= 0 || speed > 1000) {
run(); this.drawCircle(value);
}, return;
clearMockInterval() { }
if (this.interval) { this.clearMockInterval();
clearTimeout(this.interval); this.currentValue = this.currentValue || 0;
this.interval = null; const run = () => {
} this.interval = setTimeout(() => {
}, if (this.currentValue !== value) {
}, if (Math.abs(this.currentValue - value) < STEP) {
mounted() { this.currentValue = value;
this.currentValue = this.data.value; } else if (this.currentValue < value) {
this.setHoverColor().then(() => { this.currentValue += STEP;
this.drawCircle(this.currentValue); } else {
}); this.currentValue -= STEP;
}, }
destroyed() { this.drawCircle(this.currentValue);
this.clearMockInterval(); run();
}, } else {
}); this.clearMockInterval();
}
}, 1000 / speed);
};
run();
},
clearMockInterval() {
if (this.interval) {
clearTimeout(this.interval);
this.interval = null;
}
},
},
mounted() {
this.currentValue = this.data.value;
this.setHoverColor().then(() => {
this.drawCircle(this.currentValue);
});
},
destroyed() {
this.clearMockInterval();
},
});

2
wxcomponents/vant/circle/index.wxml

@ -1,7 +1,7 @@
<wxs src="../wxs/utils.wxs" module="utils" /> <wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-circle"> <view class="van-circle">
<canvas class="van-circle__canvas" type="{{ type }}" style="width: {{ utils.addUnit(size) }};height:{{ utils.addUnit(size) }}" id="van-circle" canvas-id="van-circle"></canvas> <canvas class="van-circle__canvas" type="{{ type }}" style="width: {{ utils.addUnit(size) }};height:{{ utils.addUnit(size) }}" id="van-circle" canvas-id="{{canvasId}}"></canvas>
<view wx:if="{{ !text }}" class="van-circle__text"> <view wx:if="{{ !text }}" class="van-circle__text">
<slot></slot> <slot></slot>
</view> </view>

17
wxcomponents/vant/circle/index.wxss

@ -1 +1,16 @@
@import '../common/index.wxss';.van-circle{display:inline-block;position:relative;text-align:center}.van-circle__text{color:var(--circle-text-color,#323233);left:0;position:absolute;top:50%;transform:translateY(-50%);width:100%} @import '../common/index.wxss';
.van-circle {
display: inline-block;
position: relative;
text-align: center
}
.van-circle__text {
color: var(--circle-text-color, #323233);
left: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%
}

285
wxcomponents/vant/dropdown-item/index.js

@ -1,130 +1,157 @@
import { useParent } from '../common/relation'; import {
import { VantComponent } from '../common/component'; useParent
} from '../common/relation';
import {
VantComponent
} from '../common/component';
VantComponent({ VantComponent({
classes: ['item-title-class'], classes: ['item-title-class'],
field: true, field: true,
relation: useParent('dropdown-menu', function () { relation: useParent('dropdown-menu', function() {
this.updateDataFromParent(); this.updateDataFromParent();
}), }),
props: { props: {
value: { value: {
type: null, type: null,
observer: 'rerender', observer: 'rerender',
}, },
title: { title: {
type: String, type: String,
observer: 'rerender', observer: 'rerender',
}, },
disabled: Boolean, disabled: Boolean,
titleClass: { titleClass: {
type: String, type: String,
observer: 'rerender', observer: 'rerender',
}, },
options: { options: {
type: Array, type: Array,
value: [], value: [],
observer: 'rerender', observer: 'rerender',
}, },
popupStyle: String, popupStyle: String,
useBeforeToggle: { useBeforeToggle: {
type: Boolean, type: Boolean,
value: false, value: false,
}, },
rootPortal: { rootPortal: {
type: Boolean, type: Boolean,
value: false, value: false,
}, },
}, },
data: { data: {
transition: true, transition: true,
showPopup: false, showPopup: false,
showWrapper: false, showWrapper: false,
displayTitle: '', displayTitle: '',
safeAreaTabBar: false, safeAreaTabBar: false,
}, },
methods: { methods: {
rerender() { rerender() {
wx.nextTick(() => { wx.nextTick(() => {
var _a; var _a;
(_a = this.parent) === null || _a === void 0 ? void 0 : _a.updateItemListData(); (_a = this.parent) === null || _a === void 0 ? void 0 : _a.updateItemListData();
}); });
}, },
updateDataFromParent() { updateDataFromParent() {
if (this.parent) { if (this.parent) {
const { overlay, duration, activeColor, closeOnClickOverlay, direction, safeAreaTabBar, } = this.parent.data; const {
this.setData({ overlay,
overlay, duration,
duration, activeColor,
activeColor, closeOnClickOverlay,
closeOnClickOverlay, direction,
direction, safeAreaTabBar,
safeAreaTabBar, } = this.parent.data;
}); this.setData({
} overlay,
}, duration,
onOpen() { activeColor,
this.$emit('open'); closeOnClickOverlay,
}, direction,
onOpened() { safeAreaTabBar,
this.$emit('opened'); });
}, }
onClose() { },
this.$emit('close'); onOpen() {
}, this.$emit('open');
onClosed() { },
this.$emit('closed'); onOpened() {
this.setData({ showWrapper: false }); this.$emit('opened');
}, },
onOptionTap(event) { onClose() {
const { option } = event.currentTarget.dataset; this.$emit('close');
const { value } = option; },
const shouldEmitChange = this.data.value !== value; onClosed() {
this.setData({ showPopup: false, value }); this.$emit('closed');
this.$emit('close'); this.setData({
this.rerender(); showWrapper: false
if (shouldEmitChange) { });
this.$emit('change', value); },
} onOptionTap(event) {
}, const {
toggle(show, options = {}) { option
const { showPopup } = this.data; } = event.currentTarget.dataset;
if (typeof show !== 'boolean') { const {
show = !showPopup; value
} } = option;
if (show === showPopup) { const shouldEmitChange = this.data.value !== value;
return; this.setData({
} showPopup: false,
this.onBeforeToggle(show).then((status) => { value
var _a; });
if (!status) { this.$emit('close');
return; this.rerender();
} if (shouldEmitChange) {
this.setData({ this.$emit('change', value);
transition: !options.immediate, }
showPopup: show, },
}); toggle(show, options = {}) {
if (show) { const {
(_a = this.parent) === null || _a === void 0 ? void 0 : _a.getChildWrapperStyle().then((wrapperStyle) => { showPopup
this.setData({ wrapperStyle, showWrapper: true }); } = this.data;
this.rerender(); if (typeof show !== 'boolean') {
}); show = !showPopup;
} }
else { if (show === showPopup) {
this.rerender(); return;
} }
}); this.onBeforeToggle(show).then((status) => {
}, var _a;
onBeforeToggle(status) { if (!status) {
const { useBeforeToggle } = this.data; return;
if (!useBeforeToggle) { }
return Promise.resolve(true); this.setData({
} transition: !options.immediate,
return new Promise((resolve) => { showPopup: show,
this.$emit('before-toggle', { });
status, if (show) {
callback: (value) => resolve(value), (_a = this.parent) === null || _a === void 0 ? void 0 : _a.getChildWrapperStyle().then((
}); wrapperStyle) => {
}); this.setData({
}, wrapperStyle,
}, showWrapper: true
}); });
this.rerender();
});
} else {
this.rerender();
}
});
},
onBeforeToggle(status) {
const {
useBeforeToggle
} = this.data;
if (!useBeforeToggle) {
return Promise.resolve(true);
}
return new Promise((resolve) => {
this.$emit('before-toggle', {
status,
callback: (value) => resolve(value),
});
});
},
},
});

252
wxcomponents/vant/dropdown-menu/index.js

@ -1,117 +1,139 @@
import { VantComponent } from '../common/component'; import {
import { useChildren } from '../common/relation'; VantComponent
import { addUnit, getRect, getSystemInfoSync } from '../common/utils'; } from '../common/component';
import {
useChildren
} from '../common/relation';
import {
addUnit,
getRect,
getSystemInfoSync
} from '../common/utils';
let ARRAY = []; let ARRAY = [];
VantComponent({ VantComponent({
field: true, field: true,
classes: ['title-class'], classes: ['title-class'],
relation: useChildren('dropdown-item', function () { relation: useChildren('dropdown-item', function() {
this.updateItemListData(); this.updateItemListData();
}), }),
props: { props: {
activeColor: { activeColor: {
type: String, type: String,
observer: 'updateChildrenData', observer: 'updateChildrenData',
}, },
overlay: { overlay: {
type: Boolean, type: Boolean,
value: true, value: true,
observer: 'updateChildrenData', observer: 'updateChildrenData',
}, },
zIndex: { zIndex: {
type: Number, type: Number,
value: 10, value: 10,
}, },
duration: { duration: {
type: Number, type: Number,
value: 200, value: 200,
observer: 'updateChildrenData', observer: 'updateChildrenData',
}, },
direction: { direction: {
type: String, type: String,
value: 'down', value: 'down',
observer: 'updateChildrenData', observer: 'updateChildrenData',
}, },
safeAreaTabBar: { safeAreaTabBar: {
type: Boolean, type: Boolean,
value: false, value: false,
}, },
closeOnClickOverlay: { closeOnClickOverlay: {
type: Boolean, type: Boolean,
value: true, value: true,
observer: 'updateChildrenData', observer: 'updateChildrenData',
}, },
closeOnClickOutside: { closeOnClickOutside: {
type: Boolean, type: Boolean,
value: true, value: true,
}, },
}, },
data: { data: {
itemListData: [], itemListData: [],
}, currentValue: ''
beforeCreate() { },
const { windowHeight } = getSystemInfoSync(); beforeCreate() {
this.windowHeight = windowHeight; const {
ARRAY.push(this); windowHeight
}, } = getSystemInfoSync();
destroyed() { this.windowHeight = windowHeight;
ARRAY = ARRAY.filter((item) => item !== this); ARRAY.push(this);
}, },
methods: { destroyed() {
updateItemListData() { ARRAY = ARRAY.filter((item) => item !== this);
this.setData({ },
itemListData: this.children.map((child) => child.data), methods: {
}); updateItemListData() {
}, this.setData({
updateChildrenData() { itemListData: this.children.map((child) => child.data),
this.children.forEach((child) => { });
child.updateDataFromParent(); },
}); updateChildrenData() {
}, this.children.forEach((child) => {
toggleItem(active) { child.updateDataFromParent();
this.children.forEach((item, index) => { });
const { showPopup } = item.data; },
if (index === active) { toggleItem(active) {
item.toggle(); this.children.forEach((item, index) => {
} const {
else if (showPopup) { showPopup
item.toggle(false, { immediate: true }); } = item.data;
} if (index === active) {
}); item.toggle();
}, } else if (showPopup) {
close() { item.toggle(false, {
this.children.forEach((child) => { immediate: true
child.toggle(false, { immediate: true }); });
}); }
}, });
getChildWrapperStyle() { },
const { zIndex, direction } = this.data; close() {
return getRect(this, '.van-dropdown-menu').then((rect) => { this.children.forEach((child) => {
const { top = 0, bottom = 0 } = rect; child.toggle(false, {
const offset = direction === 'down' ? bottom : this.windowHeight - top; immediate: true
let wrapperStyle = `z-index: ${zIndex};`; });
if (direction === 'down') { });
wrapperStyle += `top: ${addUnit(offset)};`; },
} getChildWrapperStyle() {
else { const {
wrapperStyle += `bottom: ${addUnit(offset)};`; zIndex,
} direction
return wrapperStyle; } = this.data;
}); return getRect(this, '.van-dropdown-menu').then((rect) => {
}, const {
onTitleTap(event) { top = 0, bottom = 0
const { index } = event.currentTarget.dataset; } = rect;
const child = this.children[index]; const offset = direction === 'down' ? bottom : this.windowHeight - top;
if (!child.data.disabled) { let wrapperStyle = `z-index: ${zIndex};`;
ARRAY.forEach((menuItem) => { if (direction === 'down') {
if (menuItem && wrapperStyle += `top: ${addUnit(offset)};`;
menuItem.data.closeOnClickOutside && } else {
menuItem !== this) { wrapperStyle += `bottom: ${addUnit(offset)};`;
menuItem.close(); }
} return wrapperStyle;
}); });
this.toggleItem(index); },
} onTitleTap(event) {
}, const {
}, index
}); } = event.currentTarget.dataset;
const child = this.children[index];
if (!child.data.disabled) {
ARRAY.forEach((menuItem) => {
if (menuItem &&
menuItem.data.closeOnClickOutside &&
menuItem !== this) {
menuItem.close();
}
});
this.toggleItem(index);
}
},
},
});

3
wxcomponents/vant/dropdown-menu/index.wxml

@ -14,7 +14,8 @@
style="{{ item.showPopup ? 'color:' + activeColor : '' }}" style="{{ item.showPopup ? 'color:' + activeColor : '' }}"
> >
<view class="van-ellipsis"> <view class="van-ellipsis">
{{ computed.displayTitle(item) }} <text class="select-title" style="color:{{computed.setTitleColor(item)}}"> {{ computed.displayTitle(item) }}</text>
<text class='arrow' style="border-color:#17c653"></text>
</view> </view>
</view> </view>
</view> </view>

25
wxcomponents/vant/dropdown-menu/index.wxs

@ -1,16 +1,21 @@
/* eslint-disable */ /* eslint-disable */
function displayTitle(item) { function displayTitle(item) {
if (item.title) { if (item.title) {
return item.title; return item.title;
} }
var match = item.options.filter(function(option) { var match = item.options.filter(function(option) {
return option.value === item.value; return option.value === item.value;
}); });
var displayTitle = match.length ? match[0].text : ''; var displayTitle = match.length ? match[0].text : '';
return displayTitle; return displayTitle;
}
function setTitleColor(item) {
return item.value != '' ? '#17c653' : ''
} }
module.exports = { module.exports = {
displayTitle: displayTitle displayTitle: displayTitle,
}; setTitleColor: setTitleColor
};

43
wxcomponents/vant/dropdown-menu/index.wxss

@ -33,13 +33,13 @@
box-sizing: border-box; box-sizing: border-box;
color: var(--dropdown-menu-title-text-color, #323233); color: var(--dropdown-menu-title-text-color, #323233);
font-size: var(--dropdown-menu-title-font-size, 15px); font-size: var(--dropdown-menu-title-font-size, 15px);
line-height: var(--dropdown-menu-title-line-height, 18px); /* line-height: var(--dropdown-menu-title-line-height, 18px); */
max-width: 100%; width: 100%;
padding: var(--dropdown-menu-title-padding, 0 24px 0 8px); /* padding: var(--dropdown-menu-title-padding, 0 24px 0 8px); */
position: relative; position: relative;
} }
.van-dropdown-menu__title:after { /* .van-dropdown-menu__title:after {
border-color: transparent transparent currentcolor currentcolor; border-color: transparent transparent currentcolor currentcolor;
border-style: solid; border-style: solid;
border-width: 3px; border-width: 3px;
@ -50,13 +50,42 @@
right: 11px; right: 11px;
top: 50%; top: 50%;
transform: rotate(-45deg) transform: rotate(-45deg)
} } */
.van-dropdown-menu__title--active { .van-dropdown-menu__title--active {
color: var(--dropdown-menu-title-active-text-color, #ee0a24) color: var(--dropdown-menu-title-active-text-color, #ee0a24)
} }
.van-dropdown-menu__title--down:after { .van-ellipsis {
display: flex;
flex: row nowrap;
justify-content: center;
align-items: center;
gap: 4px;
}
.select-title {
font-weight: 600;
transition: .2s all;
}
.van-dropdown-menu__title .arrow {
border-style: solid;
border-color: #000;
border-width: 0 1px 1px 0;
display: inline-block;
padding: 3px;
transform: rotate(45deg) translateY(-30%);
transform-origin: 50% 50%;
transition: .2s all;
}
.van-dropdown-menu__title--down .arrow {
transform: rotate(45deg) rotateZ(180deg) translateY(30%) translate(-4px);
}
/* .van-dropdown-menu__title--down:after {
margin-top: -1px; margin-top: -1px;
transform: rotate(135deg) transform: rotate(135deg)
} } */
Loading…
Cancel
Save