2025-07-11 18:05:05 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="create-task-container">
|
|
|
|
|
|
<!-- 表单内容 -->
|
|
|
|
|
|
<view class="form-container">
|
|
|
|
|
|
<form @submit="submitForm">
|
|
|
|
|
|
<!-- 任务主题 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">任务主题</text>
|
|
|
|
|
|
<text class="required">*</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<input
|
|
|
|
|
|
v-model="form.taskTitle"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
placeholder="请输入任务主题"
|
|
|
|
|
|
maxlength="100"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 工作类型 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">工作类型</text>
|
|
|
|
|
|
<text class="required">*</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<picker
|
|
|
|
|
|
@change="onTaskTypeChange"
|
|
|
|
|
|
:value="taskTypeIndex"
|
|
|
|
|
|
:range="taskTypeOptions"
|
|
|
|
|
|
range-key="label"
|
|
|
|
|
|
class="form-picker"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="picker-text">
|
|
|
|
|
|
{{ taskTypeOptions[taskTypeIndex] ? taskTypeOptions[taskTypeIndex].label : '请选择工作类型' }}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 任务模式 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">任务模式</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="radio-group">
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="radio-item"
|
|
|
|
|
|
:class="{ active: form.status === 0 }"
|
|
|
|
|
|
@click="form.status = 0"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="radio-circle"></view>
|
|
|
|
|
|
<text class="radio-text">单任务模式</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="radio-item"
|
|
|
|
|
|
:class="{ active: form.status === 1 }"
|
|
|
|
|
|
@click="form.status = 1"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="radio-circle"></view>
|
|
|
|
|
|
<text class="radio-text">报工模式</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 报工周期 -->
|
|
|
|
|
|
<view class="form-item" v-if="form.status === 1">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">报工周期(天)</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<input
|
|
|
|
|
|
v-model="form.timeGap"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
placeholder="请输入报工周期"
|
|
|
|
|
|
min="1"
|
|
|
|
|
|
max="10"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 任务时间 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">开始时间</text>
|
|
|
|
|
|
<text class="required">*</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<picker
|
|
|
|
|
|
mode="date"
|
|
|
|
|
|
@change="onBeginTimeChange"
|
|
|
|
|
|
class="form-picker"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="picker-text">
|
|
|
|
|
|
{{ form.beginTime || '请选择开始时间' }}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="form-item" v-if="form.status === 0">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">结束时间</text>
|
|
|
|
|
|
<text class="required">*</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<picker
|
|
|
|
|
|
mode="date"
|
|
|
|
|
|
@change="onFinishTimeChange"
|
|
|
|
|
|
class="form-picker"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="picker-text">
|
|
|
|
|
|
{{ form.finishTime || '请选择结束时间' }}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 优先级 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">优先级</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="radio-group">
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="radio-item"
|
|
|
|
|
|
:class="{ active: form.taskGrade === '0' }"
|
|
|
|
|
|
@click="form.taskGrade = '0'"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="radio-circle"></view>
|
|
|
|
|
|
<text class="radio-text">一般</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="radio-item"
|
|
|
|
|
|
:class="{ active: form.taskGrade === '1' }"
|
|
|
|
|
|
@click="form.taskGrade = '1'"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="radio-circle"></view>
|
|
|
|
|
|
<text class="radio-text">中等</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="radio-item"
|
|
|
|
|
|
:class="{ active: form.taskGrade === '2' }"
|
|
|
|
|
|
@click="form.taskGrade = '2'"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="radio-circle"></view>
|
|
|
|
|
|
<text class="radio-text">紧急</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 关联项目 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">关联项目</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<picker
|
|
|
|
|
|
@change="onProjectChange"
|
|
|
|
|
|
:value="projectIndex"
|
|
|
|
|
|
:range="projectList"
|
|
|
|
|
|
range-key="projectName"
|
|
|
|
|
|
class="form-picker"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="picker-text">
|
|
|
|
|
|
{{ projectIndex === -1 ? '请选择项目' : projectList[projectIndex].projectName }}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
<view v-if="projectIndex !== -1" class="selected-project" style="margin-top: 10rpx;">
|
|
|
|
|
|
<text>{{ projectList[projectIndex].projectName }}</text>
|
|
|
|
|
|
<text class="remove-btn" @click="removeProject" style="color:#ff4757;margin-left:20rpx;">移除</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 执行人 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">执行人</text>
|
|
|
|
|
|
<text class="required">*</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<!-- 已选用户标签 -->
|
|
|
|
|
|
<view v-if="selectedUsers.length > 0" class="user-tags">
|
|
|
|
|
|
<view v-for="user in selectedUsers" :key="user.userId" class="user-tag">
|
|
|
|
|
|
<text>{{ user.nickName }}</text>
|
|
|
|
|
|
<text class="remove-btn" @click="removeUser(user)">×</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<button type="primary" size="mini" @click="openUserPopup">点击选择</button>
|
|
|
|
|
|
<!-- 弹窗 -->
|
|
|
|
|
|
<uni-popup ref="userPopup" type="center">
|
|
|
|
|
|
<view class="user-select-popup">
|
|
|
|
|
|
<view class="popup-header">
|
|
|
|
|
|
<text>选择执行人</text>
|
|
|
|
|
|
<text class="close-btn" @click="closeUserPopup">×</text>
|
|
|
|
|
|
</view>
|
2025-07-14 14:37:49 +08:00
|
|
|
|
<!-- 新增:搜索框 -->
|
|
|
|
|
|
<view style="padding: 16rpx;">
|
|
|
|
|
|
<input
|
|
|
|
|
|
v-model="userSearchKeyword"
|
|
|
|
|
|
placeholder="请输入昵称搜索"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
style="width: 100%;"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
2025-07-11 18:05:05 +08:00
|
|
|
|
<scroll-view scroll-y class="user-list" style="height: 400rpx;">
|
|
|
|
|
|
<view
|
2025-07-14 14:37:49 +08:00
|
|
|
|
v-for="user in filteredUserList"
|
2025-07-11 18:05:05 +08:00
|
|
|
|
:key="user.userId"
|
|
|
|
|
|
class="user-row"
|
|
|
|
|
|
@click="toggleUser(user)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<checkbox :checked="isSelected(user)" />
|
|
|
|
|
|
<text>{{ user.nickName }}</text>
|
|
|
|
|
|
<text class="user-dept">{{ user.deptName }}</text>
|
|
|
|
|
|
</view>
|
2025-07-14 14:37:49 +08:00
|
|
|
|
<!-- 新增:无匹配提示 -->
|
|
|
|
|
|
<view v-if="filteredUserList.length === 0" style="text-align:center;color:#999;padding:20rpx;">
|
|
|
|
|
|
暂无匹配用户
|
|
|
|
|
|
</view>
|
2025-07-11 18:05:05 +08:00
|
|
|
|
</scroll-view>
|
|
|
|
|
|
<view class="popup-footer">
|
|
|
|
|
|
<button type="primary" size="mini" @click="confirmUserSelect">确定</button>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</uni-popup>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 详细描述 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">详细描述</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
v-model="form.content"
|
|
|
|
|
|
class="form-textarea"
|
|
|
|
|
|
placeholder="请输入详细描述"
|
|
|
|
|
|
maxlength="1000"
|
|
|
|
|
|
auto-height
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 附件 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
|
<text class="label-text">附件</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="file-upload">
|
|
|
|
|
|
<view class="upload-btn" @click="chooseFile">
|
|
|
|
|
|
<text class="upload-icon">+</text>
|
|
|
|
|
|
<text class="upload-text">选择文件</text>
|
|
|
|
|
|
</view>
|
2025-07-12 10:37:32 +08:00
|
|
|
|
|
2025-07-11 18:05:05 +08:00
|
|
|
|
<view class="file-list" v-if="fileList.length > 0">
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="file-item"
|
|
|
|
|
|
v-for="(file, index) in fileList"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
>
|
|
|
|
|
|
<text class="file-name">{{ file.name }}</text>
|
|
|
|
|
|
<text class="file-size">{{ formatFileSize(file.size) }}</text>
|
|
|
|
|
|
<text class="remove-file" @click="removeFile(index)">×</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 提交按钮 -->
|
|
|
|
|
|
<view class="submit-container">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
class="submit-btn"
|
|
|
|
|
|
:loading="loading"
|
|
|
|
|
|
@click="submitForm"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ loading ? '提交中...' : '提交' }}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import { addTask } from '@/api/oa/task'
|
|
|
|
|
|
import { listProject } from '@/api/oa/project'
|
|
|
|
|
|
import { selectUser, deptTreeSelect } from '@/api/oa/user'
|
2025-07-12 10:37:32 +08:00
|
|
|
|
import { uploadFiles } from '@/api/common/upload'
|
2025-07-11 18:05:05 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'CreateTask',
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
form: {
|
|
|
|
|
|
taskTitle: '',
|
|
|
|
|
|
taskType: '',
|
|
|
|
|
|
status: 0,
|
|
|
|
|
|
timeGap: 3,
|
|
|
|
|
|
beginTime: '',
|
|
|
|
|
|
finishTime: '',
|
|
|
|
|
|
taskGrade: '0',
|
|
|
|
|
|
projectId: '',
|
|
|
|
|
|
workerIds: '',
|
|
|
|
|
|
content: '',
|
|
|
|
|
|
accessory: ''
|
|
|
|
|
|
},
|
|
|
|
|
|
taskTypeOptions: [
|
|
|
|
|
|
{ label: '技术审查', value: 1 },
|
|
|
|
|
|
{ label: '初步设计', value: 2 },
|
|
|
|
|
|
{ label: '图纸详细设计', value: 3 },
|
|
|
|
|
|
{ label: 'PLC程序设计', value: 4 },
|
|
|
|
|
|
{ label: '画面设计', value: 5 },
|
|
|
|
|
|
{ label: '调试(传动、打点、精度)', value: 6 },
|
|
|
|
|
|
{ label: '验收资料', value: 7 },
|
|
|
|
|
|
{ label: '验收报告/差旅记录', value: 8 },
|
|
|
|
|
|
{ label: '项目结项', value: 9 }
|
|
|
|
|
|
],
|
|
|
|
|
|
taskTypeIndex: 0,
|
|
|
|
|
|
projectList: [],
|
|
|
|
|
|
projectIndex: -1,
|
|
|
|
|
|
userList: [],
|
|
|
|
|
|
selectedUsers: [],
|
2025-07-14 14:37:49 +08:00
|
|
|
|
userSearchKeyword: '', // 新增:用户搜索关键字
|
2025-07-11 18:05:05 +08:00
|
|
|
|
// userPopupVisible: false, // 不再需要
|
|
|
|
|
|
fileList: [],
|
|
|
|
|
|
uploadedFiles: []
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-07-14 14:37:49 +08:00
|
|
|
|
computed: {
|
|
|
|
|
|
filteredUserList() {
|
|
|
|
|
|
if (!this.userSearchKeyword.trim()) {
|
|
|
|
|
|
return this.userList;
|
|
|
|
|
|
}
|
|
|
|
|
|
return this.userList.filter(user =>
|
|
|
|
|
|
user.nickName && user.nickName.includes(this.userSearchKeyword.trim())
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-07-11 18:05:05 +08:00
|
|
|
|
onLoad() {
|
|
|
|
|
|
this.initData()
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
// 初始化数据
|
|
|
|
|
|
async initData() {
|
|
|
|
|
|
await Promise.all([
|
|
|
|
|
|
this.getProjectList(),
|
|
|
|
|
|
this.getUserList()
|
|
|
|
|
|
])
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取项目列表
|
|
|
|
|
|
async getProjectList() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await listProject({
|
|
|
|
|
|
pageNum: 1,
|
|
|
|
|
|
pageSize: 999
|
|
|
|
|
|
})
|
|
|
|
|
|
this.projectList = res.rows || []
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取项目列表失败:', error)
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '获取项目列表失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取用户列表
|
|
|
|
|
|
async getUserList() {
|
|
|
|
|
|
try {
|
2025-07-12 10:37:32 +08:00
|
|
|
|
const res = await selectUser({ pageNum: 1, pageSize: 999, deptId: 100 })
|
|
|
|
|
|
// const resr = await deptTreeSelect()
|
|
|
|
|
|
this.userList = res.rows || []
|
2025-07-11 18:05:05 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取用户列表失败:', error)
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '获取用户列表失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 工作类型选择
|
|
|
|
|
|
onTaskTypeChange(e) {
|
|
|
|
|
|
this.taskTypeIndex = e.detail.value
|
|
|
|
|
|
this.form.taskType = this.taskTypeOptions[this.taskTypeIndex].value
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 开始时间选择
|
|
|
|
|
|
onBeginTimeChange(e) {
|
|
|
|
|
|
this.form.beginTime = e.detail.value + ' 00:00:00'
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 结束时间选择
|
|
|
|
|
|
onFinishTimeChange(e) {
|
|
|
|
|
|
this.form.finishTime = e.detail.value + ' 23:59:59'
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 项目选择
|
|
|
|
|
|
onProjectChange(e) {
|
|
|
|
|
|
this.projectIndex = e.detail.value
|
|
|
|
|
|
this.form.projectId = this.projectList[this.projectIndex].projectId
|
|
|
|
|
|
},
|
|
|
|
|
|
// 移除项目
|
|
|
|
|
|
removeProject() {
|
|
|
|
|
|
this.projectIndex = -1
|
|
|
|
|
|
this.form.projectId = ''
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 打开用户选择器
|
|
|
|
|
|
openUserPopup() {
|
|
|
|
|
|
this.$refs.userPopup.open()
|
|
|
|
|
|
},
|
|
|
|
|
|
// 关闭用户选择器
|
|
|
|
|
|
closeUserPopup() {
|
|
|
|
|
|
this.$refs.userPopup.close()
|
|
|
|
|
|
},
|
|
|
|
|
|
// 勾选/取消用户
|
|
|
|
|
|
toggleUser(user) {
|
|
|
|
|
|
const index = this.selectedUsers.findIndex(u => u.userId === user.userId)
|
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
|
this.selectedUsers.splice(index, 1)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.selectedUsers.push(user)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 判断用户是否已选
|
|
|
|
|
|
isSelected(user) {
|
|
|
|
|
|
return this.selectedUsers.some(u => u.userId === user.userId)
|
|
|
|
|
|
},
|
|
|
|
|
|
// 移除已选用户
|
|
|
|
|
|
removeUser(user) {
|
|
|
|
|
|
const index = this.selectedUsers.findIndex(u => u.userId === user.userId)
|
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
|
this.selectedUsers.splice(index, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 确认选择
|
|
|
|
|
|
confirmUserSelect() {
|
|
|
|
|
|
this.form.workerIds = this.selectedUsers.map(u => u.userId).join(',')
|
|
|
|
|
|
this.closeUserPopup()
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-07-12 10:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-11 18:05:05 +08:00
|
|
|
|
// 选择文件
|
|
|
|
|
|
chooseFile() {
|
2025-07-12 10:37:32 +08:00
|
|
|
|
// 安卓平台使用 plus.io.pickFiles
|
|
|
|
|
|
// #ifdef APP-PLUS
|
|
|
|
|
|
if (typeof plus !== 'undefined' && plus.io) {
|
|
|
|
|
|
console.log('使用安卓平台文件选择API')
|
|
|
|
|
|
this.doPickFiles()
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
|
|
|
|
// 微信小程序环境
|
|
|
|
|
|
if (typeof wx !== 'undefined' && wx.chooseMessageFile) {
|
|
|
|
|
|
wx.chooseMessageFile({
|
|
|
|
|
|
count: 5,
|
|
|
|
|
|
type: 'all',
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
const processedFiles = res.tempFiles.map(file => ({
|
|
|
|
|
|
name: file.name,
|
|
|
|
|
|
size: file.size,
|
|
|
|
|
|
path: file.path || file.tempFilePath,
|
|
|
|
|
|
type: file.type
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件
|
|
|
|
|
|
const validFiles = this.validateFiles(processedFiles)
|
|
|
|
|
|
if (validFiles.length > 0) {
|
|
|
|
|
|
this.fileList = [...this.fileList, ...validFiles]
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
console.error('选择文件失败:', err)
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '选择文件失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// H5平台使用 uni.chooseFile
|
|
|
|
|
|
// #ifdef H5
|
2025-07-11 18:05:05 +08:00
|
|
|
|
uni.chooseFile({
|
|
|
|
|
|
count: 5,
|
|
|
|
|
|
type: 'all',
|
|
|
|
|
|
success: (res) => {
|
2025-07-12 10:37:32 +08:00
|
|
|
|
const processedFiles = res.tempFiles.map(file => ({
|
|
|
|
|
|
name: file.name,
|
|
|
|
|
|
size: file.size,
|
|
|
|
|
|
path: file.path || file.tempFilePath || file.url,
|
|
|
|
|
|
type: file.type
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件
|
|
|
|
|
|
const validFiles = this.validateFiles(processedFiles)
|
|
|
|
|
|
if (validFiles.length > 0) {
|
|
|
|
|
|
this.fileList = [...this.fileList, ...validFiles]
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
console.error('选择文件失败:', err)
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '选择文件失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
2025-07-11 18:05:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
2025-07-12 10:37:32 +08:00
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
|
|
|
|
// 其他平台提示不支持
|
|
|
|
|
|
// #ifndef APP-PLUS || H5 || MP-WEIXIN
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '当前平台不支持文件选择',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
// #endif
|
2025-07-11 18:05:05 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 移除文件
|
|
|
|
|
|
removeFile(index) {
|
|
|
|
|
|
this.fileList.splice(index, 1)
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-07-12 10:37:32 +08:00
|
|
|
|
// 根据文件名获取文件类型
|
|
|
|
|
|
getFileType(fileName) {
|
|
|
|
|
|
const ext = fileName.split('.').pop().toLowerCase()
|
|
|
|
|
|
const typeMap = {
|
|
|
|
|
|
'jpg': 'image/jpeg',
|
|
|
|
|
|
'jpeg': 'image/jpeg',
|
|
|
|
|
|
'png': 'image/png',
|
|
|
|
|
|
'gif': 'image/gif',
|
|
|
|
|
|
'bmp': 'image/bmp',
|
|
|
|
|
|
'webp': 'image/webp',
|
|
|
|
|
|
'pdf': 'application/pdf',
|
|
|
|
|
|
'doc': 'application/msword',
|
|
|
|
|
|
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
|
|
|
|
'xls': 'application/vnd.ms-excel',
|
|
|
|
|
|
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
|
|
|
|
'ppt': 'application/vnd.ms-powerpoint',
|
|
|
|
|
|
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
|
|
|
|
'txt': 'text/plain',
|
|
|
|
|
|
'zip': 'application/zip',
|
|
|
|
|
|
'rar': 'application/x-rar-compressed',
|
|
|
|
|
|
'7z': 'application/x-7z-compressed'
|
|
|
|
|
|
}
|
|
|
|
|
|
return typeMap[ext] || 'application/octet-stream'
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 执行文件选择
|
|
|
|
|
|
doPickFiles() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
plus.io.pickFiles({
|
|
|
|
|
|
multiple: true,
|
|
|
|
|
|
maximum: 5,
|
|
|
|
|
|
filter: 'none',
|
|
|
|
|
|
onSuccess: (files) => {
|
|
|
|
|
|
console.log('安卓平台选择文件成功:', files)
|
|
|
|
|
|
const processedFiles = files.map(file => ({
|
|
|
|
|
|
name: file.name,
|
|
|
|
|
|
size: file.size,
|
|
|
|
|
|
path: file.path,
|
|
|
|
|
|
type: file.type || this.getFileType(file.name)
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件
|
|
|
|
|
|
const validFiles = this.validateFiles(processedFiles)
|
|
|
|
|
|
if (validFiles.length > 0) {
|
|
|
|
|
|
this.fileList = [...this.fileList, ...validFiles]
|
|
|
|
|
|
console.log('处理后的文件列表:', this.fileList)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
onFail: (error) => {
|
|
|
|
|
|
console.error('安卓平台选择文件失败:', error)
|
|
|
|
|
|
// 尝试使用备用方法
|
|
|
|
|
|
this.fallbackPickFiles()
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('plus.io.pickFiles 不可用:', error)
|
|
|
|
|
|
// 尝试使用备用方法
|
|
|
|
|
|
this.fallbackPickFiles()
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 备用文件选择方法
|
|
|
|
|
|
fallbackPickFiles() {
|
|
|
|
|
|
// 使用 uni.chooseImage 作为备用方案
|
|
|
|
|
|
uni.chooseImage({
|
|
|
|
|
|
count: 5,
|
|
|
|
|
|
sizeType: ['original'],
|
|
|
|
|
|
sourceType: ['album'],
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
console.log('备用方法选择文件成功:', res)
|
|
|
|
|
|
const processedFiles = res.tempFilePaths.map((path, index) => ({
|
|
|
|
|
|
name: `image_${Date.now()}_${index}.jpg`,
|
|
|
|
|
|
size: 0,
|
|
|
|
|
|
path: path,
|
|
|
|
|
|
type: 'image/jpeg'
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件
|
|
|
|
|
|
const validFiles = this.validateFiles(processedFiles)
|
|
|
|
|
|
if (validFiles.length > 0) {
|
|
|
|
|
|
this.fileList = [...this.fileList, ...validFiles]
|
|
|
|
|
|
console.log('处理后的文件列表:', this.fileList)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (error) => {
|
|
|
|
|
|
console.error('备用方法选择文件失败:', error)
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '选择文件失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件
|
|
|
|
|
|
validateFiles(files) {
|
|
|
|
|
|
const allowedTypes = ['doc', 'xls', 'ppt', 'txt', 'pdf', 'docx', 'xlsx', 'png', 'jpg', 'jpeg', 'zip', 'rar', '7z', 'dwg']
|
|
|
|
|
|
const maxSize = 200 * 1024 * 1024 // 200MB
|
|
|
|
|
|
|
|
|
|
|
|
const validFiles = []
|
|
|
|
|
|
const invalidFiles = []
|
|
|
|
|
|
|
|
|
|
|
|
files.forEach(file => {
|
|
|
|
|
|
// 文件类型验证
|
|
|
|
|
|
const ext = file.name.split('.').pop().toLowerCase()
|
|
|
|
|
|
if (!allowedTypes.includes(ext)) {
|
|
|
|
|
|
invalidFiles.push(`${file.name} (格式不支持)`)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 文件大小验证
|
|
|
|
|
|
if (file.size > maxSize) {
|
|
|
|
|
|
invalidFiles.push(`${file.name} (超过200MB)`)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
validFiles.push(file)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 显示无效文件提示
|
|
|
|
|
|
if (invalidFiles.length > 0) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: `以下文件不符合要求:${invalidFiles.join(', ')}`,
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
duration: 3000
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return validFiles
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-11 18:05:05 +08:00
|
|
|
|
// 格式化文件大小
|
|
|
|
|
|
formatFileSize(size) {
|
|
|
|
|
|
if (size < 1024) {
|
|
|
|
|
|
return size + 'B'
|
|
|
|
|
|
} else if (size < 1024 * 1024) {
|
|
|
|
|
|
return (size / 1024).toFixed(2) + 'KB'
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return (size / (1024 * 1024)).toFixed(2) + 'MB'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 上传文件
|
|
|
|
|
|
async uploadFiles() {
|
2025-07-12 10:37:32 +08:00
|
|
|
|
if (this.fileList.length === 0) {
|
|
|
|
|
|
return []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const results = await uploadFiles(this.fileList, {
|
|
|
|
|
|
allowedTypes: ['doc', 'xls', 'ppt', 'txt', 'pdf', 'docx', 'xlsx', 'png', 'jpg', 'jpeg', 'zip', 'rar', '7z', 'dwg'],
|
|
|
|
|
|
maxSize: 200,
|
|
|
|
|
|
extraData: 1,
|
|
|
|
|
|
onProgress: (progress) => {
|
|
|
|
|
|
console.log(`上传进度: ${progress.progress.toFixed(1)}% - ${progress.file.name}`)
|
2025-07-11 18:05:05 +08:00
|
|
|
|
}
|
2025-07-12 10:37:32 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
2025-07-11 18:05:05 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 表单验证
|
|
|
|
|
|
validateForm() {
|
|
|
|
|
|
if (!this.form.taskTitle.trim()) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '请输入任务主题',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!this.form.taskType) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '请选择工作类型',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!this.form.beginTime) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '请选择开始时间',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (this.form.status === 0 && !this.form.finishTime) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '请选择结束时间',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (this.form.workerIds === '') {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '请选择执行人',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 提交表单
|
|
|
|
|
|
async submitForm() {
|
|
|
|
|
|
if (!this.validateForm()) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.loading = true
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 上传文件
|
|
|
|
|
|
if (this.fileList.length > 0) {
|
2025-07-12 10:37:32 +08:00
|
|
|
|
// 显示上传进度提示
|
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
|
title: '正在上传文件...',
|
|
|
|
|
|
mask: true
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-07-11 18:05:05 +08:00
|
|
|
|
const uploadedFiles = await this.uploadFiles()
|
2025-07-12 10:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
// 隐藏上传进度提示
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
|
|
|
|
|
|
// 提取ossId并拼接成字符串
|
|
|
|
|
|
const ossIds = uploadedFiles.map(file => file.ossId).filter(Boolean)
|
|
|
|
|
|
this.form.accessory = ossIds.join(',')
|
|
|
|
|
|
|
|
|
|
|
|
console.log('上传完成,ossId字符串:', this.form.accessory)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.form.accessory = ''
|
2025-07-11 18:05:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-12 10:37:32 +08:00
|
|
|
|
// 显示提交提示
|
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
|
title: '正在创建任务...',
|
|
|
|
|
|
mask: true
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-07-11 18:05:05 +08:00
|
|
|
|
// 提交任务
|
|
|
|
|
|
await addTask(this.form)
|
2025-07-12 10:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
// 隐藏提交提示
|
|
|
|
|
|
uni.hideLoading()
|
2025-07-11 18:05:05 +08:00
|
|
|
|
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '任务创建成功',
|
|
|
|
|
|
icon: 'success'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 返回上一页
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.navigateBack()
|
|
|
|
|
|
}, 1500)
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('创建任务失败:', error)
|
2025-07-12 10:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
// 隐藏所有loading
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
|
|
|
|
|
|
// 显示错误信息
|
|
|
|
|
|
const errorMessage = error.message || '创建任务失败'
|
2025-07-11 18:05:05 +08:00
|
|
|
|
uni.showToast({
|
2025-07-12 10:37:32 +08:00
|
|
|
|
title: errorMessage,
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
duration: 3000
|
2025-07-11 18:05:05 +08:00
|
|
|
|
})
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
this.loading = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.create-task-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
|
padding-bottom: 120rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-container {
|
|
|
|
|
|
max-width: 90vw;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
padding: 30rpx 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-item {
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
padding: 30rpx;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-label {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.label-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.required {
|
|
|
|
|
|
color: #ff4757;
|
|
|
|
|
|
margin-left: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-input {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
border: 1rpx solid #ddd;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
padding: 0 20rpx;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-picker {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
border: 1rpx solid #ddd;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 0 20rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
|
|
|
|
|
|
.picker-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 20rpx 30rpx;
|
|
|
|
|
|
border: 1rpx solid #ddd;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
|
|
border-color: #007aff;
|
|
|
|
|
|
background-color: #f0f8ff;
|
|
|
|
|
|
|
|
|
|
|
|
.radio-circle {
|
|
|
|
|
|
background-color: #007aff;
|
|
|
|
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 50%;
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
transform: translate(-50%, -50%);
|
|
|
|
|
|
width: 12rpx;
|
|
|
|
|
|
height: 12rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-circle {
|
|
|
|
|
|
width: 32rpx;
|
|
|
|
|
|
height: 32rpx;
|
|
|
|
|
|
border: 2rpx solid #ddd;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.radio-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-selector {
|
|
|
|
|
|
min-height: 80rpx;
|
|
|
|
|
|
border: 1rpx solid #ddd;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
|
|
|
|
|
|
.selected-users {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-tag {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
background-color: #f0f8ff;
|
|
|
|
|
|
border: 1rpx solid #007aff;
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
|
padding: 8rpx 16rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.user-name {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #007aff;
|
|
|
|
|
|
margin-right: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.remove-btn {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #007aff;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.placeholder {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-textarea {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
min-height: 200rpx;
|
|
|
|
|
|
border: 1rpx solid #ddd;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.file-upload {
|
|
|
|
|
|
.upload-btn {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
height: 160rpx;
|
|
|
|
|
|
border: 2rpx dashed #ddd;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
background-color: #fafafa;
|
|
|
|
|
|
|
|
|
|
|
|
.upload-icon {
|
|
|
|
|
|
font-size: 48rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.upload-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.file-list {
|
|
|
|
|
|
margin-top: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.file-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
background-color: #f8f9fa;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.file-name {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.file-size {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.remove-file {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
color: #ff4757;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-container {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
padding: 30rpx;
|
|
|
|
|
|
border-top: 1rpx solid #eee;
|
|
|
|
|
|
|
|
|
|
|
|
.submit-btn {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
|
background-color: #007aff;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-popup {
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
border-radius: 20rpx 20rpx 0 0;
|
|
|
|
|
|
max-height: 80vh;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
|
|
|
|
.popup-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
padding: 30rpx;
|
|
|
|
|
|
border-bottom: 1rpx solid #eee;
|
|
|
|
|
|
|
|
|
|
|
|
.popup-title {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.close-btn {
|
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-list {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
padding: 0 30rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 30rpx 0;
|
|
|
|
|
|
border-bottom: 1rpx solid #f5f5f5;
|
|
|
|
|
|
|
|
|
|
|
|
.user-avatar {
|
|
|
|
|
|
margin-right: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.avatar-img {
|
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-info {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
|
|
|
|
.user-nickname {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-dept {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
margin-top: 8rpx;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-check {
|
|
|
|
|
|
width: 40rpx;
|
|
|
|
|
|
height: 40rpx;
|
|
|
|
|
|
border: 2rpx solid #007aff;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
background-color: #007aff;
|
|
|
|
|
|
|
|
|
|
|
|
.check-icon {
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.popup-footer {
|
|
|
|
|
|
padding: 30rpx;
|
|
|
|
|
|
border-top: 1rpx solid #eee;
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-btn {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
|
background-color: #007aff;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-tags {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
margin-bottom: 10rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-tag {
|
|
|
|
|
|
background: #e6f7ff;
|
|
|
|
|
|
color: #007aff;
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
|
padding: 6rpx 16rpx;
|
|
|
|
|
|
margin-right: 10rpx;
|
|
|
|
|
|
margin-bottom: 10rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.remove-btn {
|
|
|
|
|
|
margin-left: 8rpx;
|
|
|
|
|
|
color: #ff4757;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-select-popup {
|
|
|
|
|
|
width: 90vw;
|
|
|
|
|
|
max-width: 700rpx;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.popup-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 24rpx;
|
|
|
|
|
|
border-bottom: 1rpx solid #eee;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
.close-btn {
|
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
.popup-body {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
height: 400rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.dept-tree {
|
|
|
|
|
|
width: 180rpx;
|
|
|
|
|
|
border-right: 1rpx solid #eee;
|
|
|
|
|
|
background: #f8f8f8;
|
|
|
|
|
|
padding: 10rpx 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.dept-item {
|
|
|
|
|
|
padding: 16rpx 24rpx;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
.dept-item.active {
|
|
|
|
|
|
background: #e6f7ff;
|
|
|
|
|
|
color: #007aff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.dept-children {
|
|
|
|
|
|
margin-left: 10rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-list {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
padding: 10rpx 0 10rpx 10rpx;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 10rpx 0;
|
|
|
|
|
|
border-bottom: 1rpx solid #f5f5f5;
|
|
|
|
|
|
}
|
|
|
|
|
|
.user-row .user-dept {
|
|
|
|
|
|
margin-left: 16rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.popup-footer {
|
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|