移动端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

916 lines
17 KiB

4 months ago
<template>
<cs-page>
<view
class="detail-container"
:style="{
paddingBottom:
isSelect.length > 0 ? '140rpx' : '40rpx',
}"
>
<view class="box detail">
<text
class="wd-font-800 wd-text-16"
style="color: #071437; padding-right: 40rpx"
>
{{ detail.title }}
</text>
<view class="tagList">
<view
class="tag"
v-if="detail.deptName"
>
{{ detail.deptName }}
</view>
<view class="tag">
{{
$dict.echoDicValue(
dictMap.task_priority,
detail.priority
)
}}
</view>
<view
v-for="(tag, index) in detail.tagList"
:key="index"
class="tag"
>
{{ tag }}
</view>
</view>
<view
class="wd-flex wd-text-13"
style="justify-content: space-between"
>
<view
class="wd-flex"
style="align-items: center; gap: 8rpx"
>
<u-icon
name="calendar"
color="#17C653"
size="16"
/>
<text
class="wd-text-13"
style="font-weight: bold; margin-right: 8rpx"
>
{{
`${$util.formatDate(
detail.startDate,
'YYYY年M月D日'
)} ${$util.formatDate(
detail.endDate,
'YYYY年M月D日'
)}`
}}
</text>
</view>
</view>
<cs-text-more :value="detail.description" />
<view
class="file-list"
v-if="files && files.length > 0"
>
<view
class="file"
v-for="(file, index) in files"
:key="index"
@click="openFile(file)"
>
<u-icon
name="attach"
color="#17C653"
size="16"
/>
<text
class="name"
style="
color: var(
--LightMode-Grey-Grey-900,
#071437
);
"
>
{{ file.name }}
</text>
</view>
</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
active-color="#17C653"
style="flex: 1"
>
<van-dropdown-item
v-if="showItem(['director'])"
:value="queryParams.departmentId"
:options="dropOption.dept"
@change="
v => {
querySelect(v, 'departmentId')
}
"
/>
<van-dropdown-item
v-if="showItem(['queue', 'director'])"
:value="queryParams.userId"
use-before-toggle
@before-toggle="getUserOption"
:options="userList"
@change="
v => {
querySelect(v, 'userId')
}
"
/>
<van-dropdown-item
:value="queryParams.Inspections_status"
:options="dropOption.status"
@change="
v => {
querySelect(v, 'inspectionsStatus')
}
"
/>
</van-dropdown-menu>
<view style="flex: 0 0 120rpx">
<text style="color: #17c653">{{
list.length
}}</text>
条记录
</view>
</view>
</u-sticky>
<view
class="record"
v-for="record in list"
:key="record.id"
@tap="goRecord(record)"
>
<view
:class="{
select: true,
isSelect: isSelect.includes(record.id),
}"
@tap.native.stop="select(record.id)"
v-if="
['3', null].includes(record.inspectionStatus)
"
>
<u-icon
name="checkbox-mark"
size="16"
color="#fff"
></u-icon>
</view>
<view
class="disable"
v-else
></view>
<view class="info">
<view class="name">
{{ record.enterpriseName }}
</view>
<view
style="
font-size: 26rpx;
padding-right: 3rem;
margin-bottom: 4rpx;
white-space: nowrap;
text-overflow: ellipsis;
width: 528rpx;
overflow: hidden;
"
>
{{ record.enterpriseAddress }}
</view>
<view
class="tagList"
style="margin-top: 16rpx"
>
<view
v-for="(item, index) in record.tagList"
:key="index"
class="tag"
>
{{ item }}
</view>
</view>
</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"
v-if="load != 'nomore'"
/>
<view
class="btn-box"
v-if="isSelect.length > 0"
>
<view
class="confirm-btn"
@tap="replay"
>
已选择({{ isSelect.length }})
</view>
</view>
<u-modal
:show="model.show"
closeOnClickOverlay
@close="closeModel"
borderRadius="32rpx"
>
<view
class="wd-flex wd-flex-col"
style="gap: 20px"
>
<view class="header">
<view class="row-1">
已选择
<text class="num"
>{{ isSelect.length }}项记录</text
>
转移给
</view>
<view class="row-2">每次只能选择一人</view>
</view>
<view class="staff-list">
<view
class="staff"
v-for="staff in model.list"
:key="staff.userId"
:style="{
'--select-color':
model.isSelect == staff.userId
? '#17c653'
: '#f1f1f4',
}"
@click="selectUser(staff.userId)"
>
<u-avatar
size="40"
shape="circle"
:src="staff.avatar"
></u-avatar>
<view class="info">
<view class="name">{{
staff.realName
}}</view>
<view class="dept">{{
staff.roleName[0]
}}</view>
</view>
<view class="isSelect">
<u-icon
name="checkbox-mark"
size="16px"
color="#fff"
></u-icon>
</view>
</view>
</view>
</view>
<template #confirmButton>
<view class="wd-flex wd-flex-center">
<view
class="confirm-btn"
@tap="submitReplay"
>转移给TA</view
>
</view>
</template>
</u-modal>
</view>
</cs-page>
4 months ago
</template>
<script>
import {
getDeptTree,
getDictBatchByType,
} from '@/api/system/dict.js'
import { TaskApi } from '@/api/task/index.js'
import { InspectionsApi } from '@/api/inspections/index.js'
import { getUserList } from '@/api/system/user.js'
export default {
data() {
return {
// 任务详情
detail: {
id: '',
description: '',
},
// 文件列表
files: [],
list: [],
// 是否展开文本
isShowAllText: false,
// 已选中
isSelect: [],
dictMap: {},
//u-sticky 样式开关
OptionsOffset: {
top: 0,
isTop: false,
},
// 查询条件
queryParams: {
departmentId: '',
inspectionsStatus: '',
pageSize: 8,
pageNo: 1,
userId: '',
},
load: 'loadmore',
model: {
show: false,
list: [],
isSelect: '',
},
userList: [
{
value: '',
text: '按人员',
},
],
// 下拉选项
dropOption: {
dept: [],
userList: [],
status: [],
},
}
},
async onLoad(res) {
this.detail.id = res.id
await this.getDict()
},
onPageScroll(e) {
this.OptionsOffset.isTop =
e.scrollTop + 10 > this.OptionsOffset.top
},
onReady() {
this.getOptionOffset()
},
onReachBottom() {
this.loadMore()
},
onPullDownRefresh() {
this.reset()
},
onShow() {
this.init()
this.reset()
},
methods: {
openFile(file) {
uni.downloadFile({
url: file.url,
success: function (res) {
const filePath = res.tempFilePath
uni.openDocument({
filePath: filePath,
showMenu: true,
fail(err) {
uni.showToast({
title: '文件打开失败',
icon: 'none',
})
},
})
},
fail(err) {
uni.showToast({
title: '文件下载失败',
icon: 'none',
})
},
})
},
getOptionOffset() {
const query = uni.createSelectorQuery().in(this)
query
.select('#options')
.boundingClientRect(data => {
this.OptionsOffset.top = data.top
})
.exec()
},
showItem(query) {
return this.$roles.checkRole(query)
},
/**
* 获取字典
*/
async getDict() {
const dict = await getDictBatchByType({
type: [
'task_state',
'Inspections_status',
'task_priority',
].join(','),
})
const dept = await getDeptTree()
this.dictMap = {
...dict.data,
dept: dept.data,
}
this.dropOption = {
dept: [
{
value: '',
text: '按部门',
},
...dept.data.map(d => {
return {
value: d.id,
text: d.name,
}
}),
],
status: [
{
value: '',
text: '按状态',
},
...dict.data.task_state.map(d => {
return {
...d,
value: d.value,
text: d.label,
}
}),
],
}
},
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) {
if (key == 'departmentId') {
this.queryParams.userId = ''
}
this.queryParams[key] = v.detail
this.queryList()
},
async init() {
const res = await TaskApi.getDetail(this.detail.id)
this.detail = res.data
this.files = res.data.fileList
},
async getUser() {
const res = await getUserList(
this.queryParams.departmentId
)
return res.data
},
async getList() {
if (!this.$roles.checkRole(['director'])) {
this.queryParams.departmentId =
this.$store.getters.deptId
}
uni.showToast({
title: '加载中',
mask: true,
icon: 'loading',
})
this.load = 'loading'
const { data } = await InspectionsApi.getList({
...this.queryParams,
taskId: this.detail.id,
})
this.list.push(...data.list)
this.load = 'loadmore'
if (this.list.length == data.total) {
this.load = 'nomore'
}
uni.stopPullDownRefresh()
uni.hideToast()
},
getUserOption({ detail }) {
this.getUser().then(res => {
this.userList = [
{
value: '',
text: '按人员',
},
...res.map(i => {
return {
...i,
value: i.userId,
text: i.realName,
}
}),
]
detail.callback(true)
})
},
goBack() {
uni.switchTab({
url: '/pages/task',
})
},
loadMore() {
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 = {
departmentId: '',
Inspections_status: '',
pageSize: 8,
pageNo: 1,
userId: '',
}
await this.queryList()
},
queryList() {
this.queryParams.pageNo = 1
this.load = 'loadmore'
this.list = []
this.getList()
},
replay() {
this.getUser().then(res => {
this.model.list = res
this.model.show = true
})
},
closeModel() {
this.model = {
show: false,
list: [],
isSelect: '',
}
},
selectUser(id) {
if (this.model.isSelect == id) {
this.model.isSelect = null
} else {
this.model.isSelect = id
}
},
goRecord(record) {
uni.navigateTo({
url: `/sub/task/record?taskId=${record.taskId}&recordId=${record.id}&enterpriseId=${record.enterpriseId}`,
})
},
submitReplay() {
InspectionsApi.replay({
inspectionsId: this.isSelect,
userId: this.model.isSelect,
}).then(res => {
uni.showToast({
icon: 'none',
title: '任务转移成功',
})
this.closeModel()
this.reset()
})
},
},
}
4 months ago
</script>
<style lang="scss" scoped>
.detail-container {
position: relative;
color: $cs-color-grey;
.box {
margin: 12px;
background-color: #fff;
border-radius: $cs-border-radius;
padding: 16px;
}
.detail {
display: flex;
flex-flow: column nowrap;
gap: 12px;
position: relative;
overflow: hidden;
.audit {
position: absolute;
right: 0;
top: 0;
transform: translateX(58rpx) translateY(24rpx)
rotateZ(45deg);
transform-origin: 50% 50%;
}
.file-list {
border-radius: 4px;
background: var(--LightMode-Grey-Grey-100, #f9f9f9);
padding: 8rpx 16rpx;
display: flex;
flex-wrap: wrap;
gap: 24rpx;
width: 100%;
.file {
display: flex;
flex-flow: row nowarp;
gap: 8rpx;
cursor: pointer;
align-items: center;
.name {
color: var(--LightMode-Grey-Grey-900, #071437);
font-family: 'PingFang SC';
font-size: 26rpx;
font-style: normal;
font-weight: 400;
line-height: 160%;
text-decoration-line: underline;
text-decoration-style: solid;
text-decoration-skip-ink: auto;
text-decoration-thickness: auto;
text-underline-offset: auto;
text-underline-position: from-font;
}
}
}
}
.record {
background-color: #fff;
display: flex;
padding: 24rpx 32rpx;
align-items: center;
border-radius: var(--Number-8px, 8px);
border: 2rpx solid
var(--LightMode-Grey-Grey-100, #f9f9f9);
margin: 24rpx;
margin-top: 0;
position: relative;
overflow: hidden;
.audit {
position: absolute;
right: 0;
top: 0;
transform-origin: 50% 50%;
transform: translateX(64rpx) translateY(18rpx)
rotateZ(45deg);
}
.select {
width: 44rpx;
height: 44rpx;
min-width: 44rpx;
border: 4rpx solid $cs-color-main;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
transition: 0.2s all;
margin-right: 32rpx;
}
.disable {
width: 44rpx;
height: 44rpx;
border: 4rpx solid #dbdfe9;
min-width: 44rpx;
margin-right: 32rpx;
border-radius: 100%;
position: relative;
&::after {
content: '';
position: absolute;
inset: 0;
border-left: 4rpx solid #dbdfe9;
transform-origin: 0 50%;
transform: translateX(calc(50% - 2rpx))
rotateZ(45deg);
}
}
.isSelect {
background-color: $cs-color-main;
}
.info {
font-size: 26rpx;
overflow: hidden;
.name {
font-size: 32rpx;
font-weight: 600;
color: #071437;
margin-bottom: 8rpx;
white-space: nowrap;
text-overflow: ellipsis;
width: 480rpx;
overflow: hidden;
}
}
&: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 {
.name {
font-size: 30rpx;
font-weight: bold;
}
.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;
}
}
}
}
.options-container {
overflow: hidden;
margin: 12px;
border-radius: 8px;
transition: 0.1s all;
display: flex;
padding: 0 12px;
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;
.van-dropdown-menu__item {
flex: 0;
.van-dropdown-menu__title {
width: 80px;
}
}
}
}
.isTop {
margin: 12px 0;
border-radius: 0px;
}
::v-deep .u-popup__content {
border-radius: 32rpx;
}
</style>