1645 lines
43 KiB
Vue
1645 lines
43 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="dynamicModel-form-v jnpf-wrap jnpf-wrap-form" v-if="showPage">
|
|||
|
|
<JnpfParser :formConf="formConf" ref="dynamicForm" @submit="sumbitForm" :key="key" v-if="!loading" />
|
|||
|
|
|
|||
|
|
<!-- 审批记录区域 -->
|
|||
|
|
<view v-if="false&&(dataForm.approveStatus == 1 || dataForm.approveStatus == 2)">
|
|||
|
|
<view class="approval-title">审批记录</view>
|
|||
|
|
<view class="approval-list">
|
|||
|
|
<view
|
|||
|
|
class="approval-item"
|
|||
|
|
v-for="(item, index) in approvalData"
|
|||
|
|
:key="item.id"
|
|||
|
|
>
|
|||
|
|
<!-- 审批内容 -->
|
|||
|
|
<view class="approval-content">
|
|||
|
|
<view class="task-header">
|
|||
|
|
<text class="task-name">任务:{{ item.name }}</text>
|
|||
|
|
<view class="status-tag" :class="getStatusTagClass(item.result)">
|
|||
|
|
{{ item.result === 1 ? '处理中' : (item.result === 2 ? '通过' : '不通过') }}
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="info-row">
|
|||
|
|
<text class="info-label">审批人:</text>
|
|||
|
|
<text class="info-value">{{ item.assigneeUser.nickname }}</text>
|
|||
|
|
<view class="dept-tag">{{ item.assigneeUser.deptName }}</view>
|
|||
|
|
|
|||
|
|
<text class="info-label ml-20">创建时间:</text>
|
|||
|
|
<text class="info-value">{{ formatTime(item.createTime) }}</text>
|
|||
|
|
|
|||
|
|
<text class="info-label ml-20" v-if="item.endTime">审批时间:</text>
|
|||
|
|
<text class="info-value" v-if="item.endTime">{{ formatTime(item.endTime) }}</text>
|
|||
|
|
|
|||
|
|
<text class="info-label ml-20" v-if="item.durationInMillis">耗时:</text>
|
|||
|
|
<text class="info-value" v-if="item.durationInMillis">{{ formatDuration(item.durationInMillis) }}</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="reason-box" v-if="item.reason">
|
|||
|
|
{{ item.reason }}
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 底部操作按钮区域 -->
|
|||
|
|
<view class="buttom-actions" v-if="btnType === 'btn_edit' || btnType === 'btn_add'">
|
|||
|
|
<CustomButton
|
|||
|
|
class="u-flex buttom-btn-left-inner"
|
|||
|
|
:btnText="getCancelText"
|
|||
|
|
btnIcon="icon-ym icon-ym-add-cancel"
|
|||
|
|
customIcon
|
|||
|
|
:btnLoading="btnLoading"
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
<u-button class="buttom-btn" type="primary" @click.stop="submit" :disabled="idDsabled" :loading="btnLoading">
|
|||
|
|
{{getOkText}}
|
|||
|
|
</u-button>
|
|||
|
|
|
|||
|
|
<view class="more-btn" @click.stop="toggleMoreMenu" v-if="dataForm.id && moreMenuList.length && !idDsabled">
|
|||
|
|
<u-icon name="more-dot-fill" size="34"></u-icon>
|
|||
|
|
<text class="more-text">{{$t('common.moreText')}}</text>
|
|||
|
|
|
|||
|
|
<view class="more-menu" v-show="showMoreMenu" @click.stop>
|
|||
|
|
<view
|
|||
|
|
class="menu-item"
|
|||
|
|
v-for="(item, index) in moreMenuList"
|
|||
|
|
:key="index"
|
|||
|
|
:style="{color: item.color || '#333'}"
|
|||
|
|
>
|
|||
|
|
<view @click.stop="handleMoreMenuClick(item)">
|
|||
|
|
<text class="menu-icon" :class="item.icon"></text>
|
|||
|
|
<text class="menu-label">{{item.label}}</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 流程选择弹框 -->
|
|||
|
|
<u-popup v-model="showProcessDialog" mode="center" :round="10" >
|
|||
|
|
<view class="process-dialog">
|
|||
|
|
<view class="dialog-header">
|
|||
|
|
<text class="dialog-title">选择流程表单</text>
|
|||
|
|
<u-icon name="close" size="24" color="#999" @click="closeProcessDialog" class="close-icon"></u-icon>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="process-list" v-if="!loadingProcess">
|
|||
|
|
<u-radio-group @change="selectProcess">
|
|||
|
|
<view
|
|||
|
|
class="process-item"
|
|||
|
|
v-for="(item, index) in processList"
|
|||
|
|
:key="item.id"
|
|||
|
|
:class="{'selected-item': selectedProcess && selectedProcess.id === item.id}"
|
|||
|
|
>
|
|||
|
|
<view class="process-item-left">
|
|||
|
|
<u-radio :name="item.id">{{ item.name }}</u-radio>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</u-radio-group>
|
|||
|
|
|
|||
|
|
<view class="empty-process" v-if="processList.length === 0">
|
|||
|
|
<u-icon name="list" size="60" color="#c0c4cc"></u-icon>
|
|||
|
|
<text class="empty-text">暂无可用流程</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="loading-process" v-else>
|
|||
|
|
<u-loading mode="circle" size="40"></u-loading>
|
|||
|
|
<text class="loading-text">加载中...</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="dialog-footer" v-if="processList.length > 0">
|
|||
|
|
<u-button class="footer-btn cancel-btn" @click="closeProcessDialog">取消</u-button>
|
|||
|
|
<u-button class="footer-btn submit-btn" type="primary" :disabled="!selectedProcess" @click="launchSelectedProcess">提交</u-button>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</u-popup>
|
|||
|
|
|
|||
|
|
<!-- 审批人弹框 -->
|
|||
|
|
<u-popup v-model="showApproverDialog" mode="center" :round="10" @close="closeApproverDialog">
|
|||
|
|
<view class="approver-dialog">
|
|||
|
|
<view class="dialog-header">
|
|||
|
|
<text class="dialog-title">发起人选择审批人</text>
|
|||
|
|
<u-icon name="close" size="24" color="#999" @click="closeApproverDialog" class="close-icon"></u-icon>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="approver-content" v-if="!loadingApprover && approverList.length > 0">
|
|||
|
|
<view class="approver-node" v-for="(node, index) in approverList" :key="node.id">
|
|||
|
|
<view class="node-title">
|
|||
|
|
<text class="node-label">审批节点:</text>
|
|||
|
|
<text class="node-name">{{ node.taskDefinitionName || '未命名节点' }}</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="candidate-section">
|
|||
|
|
<view class="section-title">
|
|||
|
|
<text class="section-label">候选人<text style="color:red">*</text></text>
|
|||
|
|
<view>
|
|||
|
|
<user-select
|
|||
|
|
v-model="selectedCandidates"
|
|||
|
|
:placeholder="'请选择审批人'"
|
|||
|
|
:multiple="false"
|
|||
|
|
:selectType="type"
|
|||
|
|
@change="(value, data) => handleUserChange(node, value, data,index)"
|
|||
|
|
style="margin-top: 10rpx;"
|
|||
|
|
/>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="loading-approver" v-else-if="loadingApprover">
|
|||
|
|
<u-loading mode="circle" size="40"></u-loading>
|
|||
|
|
<text class="loading-text">加载中...</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="empty-approver" v-else>
|
|||
|
|
<u-icon name="user" size="60" color="#c0c4cc"></u-icon>
|
|||
|
|
<text class="empty-text">暂无审批人</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="dialog-footer" v-if="approverList.length > 0">
|
|||
|
|
<u-button class="footer-btn confirm-btn" type="primary" :disabled="!isAllCandidatesSelected" @click="confirmLaunchFlow">确定</u-button>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</u-popup>
|
|||
|
|
|
|||
|
|
<!-- 审批意见输入弹窗 -->
|
|||
|
|
<u-popup
|
|||
|
|
v-model="showApprovalReasonDialog"
|
|||
|
|
mode="center"
|
|||
|
|
:round="10"
|
|||
|
|
:closeOnClickOverlay="false"
|
|||
|
|
>
|
|||
|
|
<view class="approval-reason-dialog">
|
|||
|
|
<!-- 弹窗标题 -->
|
|||
|
|
<view class="dialog-header">
|
|||
|
|
<text class="dialog-title">{{ approvalType === 'through' ? '审批通过' : '审批不通过' }}</text>
|
|||
|
|
<u-icon name="close" size="24" color="#999" @click="showApprovalReasonDialog = false" class="close-icon"></u-icon>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 输入框区域 -->
|
|||
|
|
<view class="dialog-content">
|
|||
|
|
<view class="input-label">审批意见</view>
|
|||
|
|
<u-input
|
|||
|
|
v-model="approvalReason"
|
|||
|
|
type="textarea"
|
|||
|
|
placeholder="请输入审批意见(选填)"
|
|||
|
|
:rows="4"
|
|||
|
|
border="surround"
|
|||
|
|
class="reason-input"
|
|||
|
|
/>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 按钮区域 -->
|
|||
|
|
<view class="dialog-footer">
|
|||
|
|
<u-button class="footer-btn cancel-btn" @click="showApprovalReasonDialog = false">取消</u-button>
|
|||
|
|
<u-button
|
|||
|
|
class="footer-btn submit-btn"
|
|||
|
|
type="primary"
|
|||
|
|
@click="submitApprovalResult"
|
|||
|
|
:loading="approvalSubmitting"
|
|||
|
|
>
|
|||
|
|
确认提交
|
|||
|
|
</u-button>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</u-popup>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import CustomButton from '@/components/CustomButton'
|
|||
|
|
import {
|
|||
|
|
getDesForm,
|
|||
|
|
createModel,
|
|||
|
|
updateModel,
|
|||
|
|
getModelInfo,
|
|||
|
|
getdbformlist,
|
|||
|
|
getAssignList,
|
|||
|
|
getListCreate,
|
|||
|
|
deteleModel,
|
|||
|
|
launchFlow,
|
|||
|
|
getByProcess
|
|||
|
|
} from '@/api/apply/visualDev'
|
|||
|
|
import UserSelect from '@/components/Jnpf/CandidateSelect'
|
|||
|
|
import {getOrganizeSelector} from '@/api/common.js'
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
components: {
|
|||
|
|
CustomButton,
|
|||
|
|
UserSelect
|
|||
|
|
},
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
webType: '',
|
|||
|
|
type: 'all',
|
|||
|
|
showPage: false,
|
|||
|
|
btnLoading: false,
|
|||
|
|
loading: true,
|
|||
|
|
isPreview: '0',
|
|||
|
|
modelId: '',
|
|||
|
|
formConf: {},
|
|||
|
|
formData: {},
|
|||
|
|
dataForm: {
|
|||
|
|
id: '',
|
|||
|
|
data: ''
|
|||
|
|
},
|
|||
|
|
btnType: '',
|
|||
|
|
formPermissionList: {},
|
|||
|
|
formList: [],
|
|||
|
|
key: +new Date(),
|
|||
|
|
config: {},
|
|||
|
|
clickType: 'submit',
|
|||
|
|
prevDis: false,
|
|||
|
|
nextDis: false,
|
|||
|
|
index: 0,
|
|||
|
|
userInfo: {},
|
|||
|
|
isAdd: false,
|
|||
|
|
showMoreMenu: false,
|
|||
|
|
moreMenuList: [],
|
|||
|
|
lc_fire_operation_detail: [],
|
|||
|
|
deptList: [],
|
|||
|
|
showProcessDialog: false,
|
|||
|
|
processList: [],
|
|||
|
|
selectedProcess: '',
|
|||
|
|
loadingProcess: false,
|
|||
|
|
showApproverDialog: false,
|
|||
|
|
approverList: [],
|
|||
|
|
selectedApprover: null,
|
|||
|
|
loadingApprover: false,
|
|||
|
|
currentProcessId: '',
|
|||
|
|
selectedCandidates: {},
|
|||
|
|
approvalData: [], // 存储审批记录
|
|||
|
|
|
|||
|
|
//审批意见弹窗相关数据
|
|||
|
|
showApprovalReasonDialog: false, // 弹窗显示状态
|
|||
|
|
approvalType: '', // 审批类型:through(通过) / fail(不通过)
|
|||
|
|
approvalReason: '', // 审批意见内容
|
|||
|
|
approvalSubmitting: false // 提交加载状态
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
computed: {
|
|||
|
|
getOkText() {
|
|||
|
|
const text = this.formConf.confirmButtonTextI18nCode ?
|
|||
|
|
this.$t(this.formConf.confirmButtonTextI18nCode, this.formConf.confirmButtonText) :
|
|||
|
|
this.formConf.confirmButtonText;
|
|||
|
|
return text || this.$t('common.okText');
|
|||
|
|
},
|
|||
|
|
getCancelText() {
|
|||
|
|
const text = this.formConf.cancelButtonTextI18nCode ?
|
|||
|
|
this.$t(this.formConf.cancelButtonTextI18nCode, this.formConf.cancelButtonText) :
|
|||
|
|
this.formConf.cancelButtonText;
|
|||
|
|
return text || this.$t('common.cancelText');
|
|||
|
|
},
|
|||
|
|
isAllCandidatesSelected() {
|
|||
|
|
const result = this.approverList.every(item=>{
|
|||
|
|
const {taskDefinitionKey} = item
|
|||
|
|
return !!item[taskDefinitionKey]
|
|||
|
|
})
|
|||
|
|
return result
|
|||
|
|
},
|
|||
|
|
idDsabled() {
|
|||
|
|
const {approveStatus} = this.dataForm
|
|||
|
|
return approveStatus == 2 || approveStatus == 4
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
onLoad(option) {
|
|||
|
|
this.init(option)
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
init(option) {
|
|||
|
|
const parseConfig = (rawConfig) => {
|
|||
|
|
try {
|
|||
|
|
return JSON.parse(this.jnpf.base64.decode(rawConfig)) || {}
|
|||
|
|
} catch (error) {
|
|||
|
|
return {}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const config = parseConfig(option.config)
|
|||
|
|
const {
|
|||
|
|
index,
|
|||
|
|
currentMenu,
|
|||
|
|
btnType = '',
|
|||
|
|
modelId,
|
|||
|
|
isPreview = '0',
|
|||
|
|
id = ''
|
|||
|
|
} = config
|
|||
|
|
const formPermissionList =[]
|
|||
|
|
Object.assign(this, {
|
|||
|
|
userInfo: uni.getStorageSync('userInfo') || {},
|
|||
|
|
config,
|
|||
|
|
index,
|
|||
|
|
formPermissionList,
|
|||
|
|
formList: formPermissionList?.formList || [],
|
|||
|
|
btnType,
|
|||
|
|
modelId,
|
|||
|
|
isPreview,
|
|||
|
|
dataForm: {
|
|||
|
|
id
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if (id) {
|
|||
|
|
this.initMoreMenuList()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const getNavigationTitle = () => this.dataForm.id ? this.$t('common.editText') : this.$t('common.addText')
|
|||
|
|
uni.setNavigationBarTitle({
|
|||
|
|
title: getNavigationTitle() + this.config.name
|
|||
|
|
})
|
|||
|
|
this.getDesForm()
|
|||
|
|
},
|
|||
|
|
handleUserChange(node, value, data,index){
|
|||
|
|
const name = this.approverList[index]['taskDefinitionKey']
|
|||
|
|
this.approverList[index] ={
|
|||
|
|
...this.approverList[index],
|
|||
|
|
[name] : value
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
confirmLaunchFlow() {
|
|||
|
|
const result = this.approverList.every(item=>{
|
|||
|
|
const {taskDefinitionKey} = item
|
|||
|
|
return !!item[taskDefinitionKey]
|
|||
|
|
})
|
|||
|
|
if(!result){
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '请选择候选人',
|
|||
|
|
icon: 'error'
|
|||
|
|
})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
const assignee = {}
|
|||
|
|
this.approverList.forEach(item=>{
|
|||
|
|
const key = item.taskDefinitionKey;
|
|||
|
|
assignee[key] = item[key];
|
|||
|
|
})
|
|||
|
|
const params = {
|
|||
|
|
processType: 0,
|
|||
|
|
processDefinitionId: this.selectedProcess,
|
|||
|
|
id: this.dataForm.id,
|
|||
|
|
data: {
|
|||
|
|
assignee,
|
|||
|
|
dbFormId : this.modelId,
|
|||
|
|
dataId: this.dataForm.id,
|
|||
|
|
processDefinitionId: this.selectedProcess
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
getListCreate(params,this.modelId).then(res=>{
|
|||
|
|
if(res.code == 0) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '发起成功',
|
|||
|
|
icon: 'success'
|
|||
|
|
})
|
|||
|
|
setTimeout(() => {
|
|||
|
|
uni.$emit('refresh')
|
|||
|
|
uni.navigateBack()
|
|||
|
|
}, 1500)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
},
|
|||
|
|
initMoreMenuList() {
|
|||
|
|
let menuList = [
|
|||
|
|
// {
|
|||
|
|
// label: '通过',
|
|||
|
|
// value: 'through',
|
|||
|
|
// icon: 'icon-ym icon-ym-flow-launch',
|
|||
|
|
// color: '#67c23a'
|
|||
|
|
// },
|
|||
|
|
// {
|
|||
|
|
// label: '不通过',
|
|||
|
|
// value: 'fail',
|
|||
|
|
// icon: 'icon-ym icon-ym-flow-launch',
|
|||
|
|
// color: '#f56c6c'
|
|||
|
|
// },
|
|||
|
|
// {
|
|||
|
|
// label: '发起流程',
|
|||
|
|
// value: 'launchFlow',
|
|||
|
|
// icon: 'icon-ym icon-ym-flow-launch',
|
|||
|
|
// color: '#0293fc'
|
|||
|
|
// },
|
|||
|
|
{
|
|||
|
|
label: '删除',
|
|||
|
|
value: 'delete',
|
|||
|
|
icon: 'icon-ym icon-ym-app-delete',
|
|||
|
|
color: '#dd524d'
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
if(this.dataForm.approveStatus == 0 || this.dataForm.approveStatus == 3 || !this.dataForm.approveStatus){
|
|||
|
|
menuList.unshift({
|
|||
|
|
label: '发起流程',
|
|||
|
|
value: 'launchFlow',
|
|||
|
|
icon: 'icon-ym icon-ym-flow-launch',
|
|||
|
|
color: '#0293fc'
|
|||
|
|
},)
|
|||
|
|
}
|
|||
|
|
if(this.dataForm.approveStatus == 1){
|
|||
|
|
menuList.unshift({
|
|||
|
|
label: '通过',
|
|||
|
|
value: 'through',
|
|||
|
|
icon: 'icon-ym icon-ym-flow-launch',
|
|||
|
|
color: '#67c23a'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
label: '不通过',
|
|||
|
|
value: 'fail',
|
|||
|
|
icon: 'icon-ym icon-ym-flow-launch',
|
|||
|
|
color: '#f56c6c'
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
// if(this.dataForm.approveStatus == 1){
|
|||
|
|
// menuList.unshift({
|
|||
|
|
// label: '通过',
|
|||
|
|
// value: 'through',
|
|||
|
|
// icon: 'icon-ym icon-ym-flow-launch',
|
|||
|
|
// color: '#67c23a'
|
|||
|
|
// },
|
|||
|
|
// {
|
|||
|
|
// label: '不通过',
|
|||
|
|
// value: 'fail',
|
|||
|
|
// icon: 'icon-ym icon-ym-flow-launch',
|
|||
|
|
// color: '#f56c6c'
|
|||
|
|
// })
|
|||
|
|
// }
|
|||
|
|
this.moreMenuList = menuList
|
|||
|
|
},
|
|||
|
|
toggleMoreMenu() {
|
|||
|
|
this.showMoreMenu = !this.showMoreMenu
|
|||
|
|
if (this.showMoreMenu) {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
uni.$once('clickOutside', () => {
|
|||
|
|
this.showMoreMenu = false
|
|||
|
|
})
|
|||
|
|
}, 100)
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
handleMoreMenuClick(item) {
|
|||
|
|
this.showMoreMenu = false
|
|||
|
|
switch (item.value) {
|
|||
|
|
case 'edit':
|
|||
|
|
this.handleEdit()
|
|||
|
|
break
|
|||
|
|
case 'launchFlow':
|
|||
|
|
this.handleLaunchFlow()
|
|||
|
|
break
|
|||
|
|
case 'delete':
|
|||
|
|
this.handleDelete()
|
|||
|
|
break
|
|||
|
|
case 'through':
|
|||
|
|
this.handleThrough()
|
|||
|
|
break
|
|||
|
|
case 'fail':
|
|||
|
|
this.handleFail()
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
handleEdit() {
|
|||
|
|
this.btnType = 'btn_edit'
|
|||
|
|
this.initData()
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '进入编辑状态',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
},
|
|||
|
|
handleLaunchFlow() {
|
|||
|
|
this.getProcessList()
|
|||
|
|
},
|
|||
|
|
async getProcessList() {
|
|||
|
|
try {
|
|||
|
|
this.loadingProcess = true
|
|||
|
|
const res = await getdbformlist(this.modelId)
|
|||
|
|
if (res.code === 0 || res.code === 200) {
|
|||
|
|
this.processList = res.data || []
|
|||
|
|
if (this.processList.length === 0) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '暂无可用流程',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
this.showProcessDialog = true
|
|||
|
|
} else {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: res.msg || '获取流程列表失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取流程列表失败:', error)
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '获取流程列表失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
} finally {
|
|||
|
|
this.loadingProcess = false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
selectProcess(item) {
|
|||
|
|
this.selectedProcess = item
|
|||
|
|
},
|
|||
|
|
async launchSelectedProcess() {
|
|||
|
|
if (!this.selectedProcess) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '请选择一个流程',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
this.showProcessDialog = false
|
|||
|
|
await this.getApproverList()
|
|||
|
|
},
|
|||
|
|
async getApproverList() {
|
|||
|
|
try {
|
|||
|
|
const res = await getAssignList(this.selectedProcess)
|
|||
|
|
if (res.code === 0 || res.code === 200) {
|
|||
|
|
this.approverList = res.data || []
|
|||
|
|
let userSelectRules = res.data?.filter(rule => rule.type === 35)
|
|||
|
|
if(userSelectRules?.length > 0){
|
|||
|
|
this.loadingApprover = true
|
|||
|
|
this.showApproverDialog = true
|
|||
|
|
this.selectedCandidates = {}
|
|||
|
|
}else{
|
|||
|
|
const params = {
|
|||
|
|
processType: 0,
|
|||
|
|
processDefinitionId: this.selectedProcess,
|
|||
|
|
id: this.dataForm.id,
|
|||
|
|
data: {
|
|||
|
|
dbFormId : this.modelId,
|
|||
|
|
dataId: this.dataForm.id,
|
|||
|
|
processDefinitionId: this.selectedProcess
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const res = await getListCreate(params,this.modelId)
|
|||
|
|
if(res.code == 0) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '发起成功',
|
|||
|
|
icon: 'success'
|
|||
|
|
})
|
|||
|
|
setTimeout(() => {
|
|||
|
|
uni.$emit('refresh')
|
|||
|
|
uni.navigateBack()
|
|||
|
|
}, 1500)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: res.msg || '获取审批人失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取审批人失败:', error)
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '获取审批人失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
} finally {
|
|||
|
|
this.loadingApprover = false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
closeProcessDialog() {
|
|||
|
|
this.showProcessDialog = false
|
|||
|
|
this.selectedProcess = ''
|
|||
|
|
},
|
|||
|
|
closeApproverDialog() {
|
|||
|
|
this.showApproverDialog = false
|
|||
|
|
},
|
|||
|
|
handleDelete() {
|
|||
|
|
uni.showModal({
|
|||
|
|
title: '警告',
|
|||
|
|
content: '删除后数据无法恢复,确认删除吗?',
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.confirm) {
|
|||
|
|
createModel(this.modelId,{
|
|||
|
|
operateType: 3,
|
|||
|
|
id: this.dataForm.id,
|
|||
|
|
data: {}
|
|||
|
|
}, this.modelId).then(res => {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: res.msg || '删除成功',
|
|||
|
|
icon: 'success',
|
|||
|
|
complete: () => {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
uni.$emit('refresh')
|
|||
|
|
uni.navigateBack()
|
|||
|
|
}, 1500)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}).catch(err => {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: err.msg || '删除失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 点击通过 - 打开审批意见弹窗
|
|||
|
|
handleThrough() {
|
|||
|
|
this.approvalType = 'through'
|
|||
|
|
this.approvalReason = '' // 清空之前的意见
|
|||
|
|
this.showApprovalReasonDialog = true
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 点击不通过 - 打开审批意见弹窗
|
|||
|
|
handleFail() {
|
|||
|
|
this.approvalType = 'fail'
|
|||
|
|
this.approvalReason = '' // 清空之前的意见
|
|||
|
|
this.showApprovalReasonDialog = true
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 新增:提交审批结果(通过/不通过)
|
|||
|
|
async submitApprovalResult() {
|
|||
|
|
try {
|
|||
|
|
this.approvalSubmitting = true
|
|||
|
|
console.log(this.formData,'formData----')
|
|||
|
|
// 构造审批参数(
|
|||
|
|
const params = {
|
|||
|
|
processType: this.approvalType === 'through' ? 1 : 2, // 1=通过,2=不通过
|
|||
|
|
processInstanceId: this.formData.processInstanceId, // 流程实例ID
|
|||
|
|
id: this.formData.id,
|
|||
|
|
data: {
|
|||
|
|
dbFormId : this.modelId,
|
|||
|
|
id: this.approvalData && this.approvalData[0].id, // 审批记录第一条id
|
|||
|
|
reason: this.approvalReason || '', // 审批意见
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//调用审批接口(替换为你的实际审批接口)
|
|||
|
|
const res = await getListCreate(params,this.modelId)
|
|||
|
|
if (res.code !== 0) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: res.msg || '审批失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
// 关闭弹窗,刷新审批记录
|
|||
|
|
this.showApprovalReasonDialog = false
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '发起成功',
|
|||
|
|
icon: 'success'
|
|||
|
|
})
|
|||
|
|
setTimeout(() => {
|
|||
|
|
// 返回上一页或刷新列表
|
|||
|
|
uni.$emit('refresh')
|
|||
|
|
uni.navigateBack()
|
|||
|
|
}, 1500)
|
|||
|
|
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error('提交审批结果失败:', err)
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '提交失败,请重试',
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
} finally {
|
|||
|
|
this.approvalSubmitting = false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
async getDesForm() {
|
|||
|
|
try {
|
|||
|
|
const res = await getDesForm(this.config.modelId);
|
|||
|
|
if((res.code == 0 || res.code == 200) && res.data !== null){
|
|||
|
|
const data = res.data ? JSON.parse(res.data) : {};
|
|||
|
|
this.formConf = JSON.parse(data.formData);
|
|||
|
|
console.log(this.formConf,'formConf--')
|
|||
|
|
this.formConf.labelWidth = 160;
|
|||
|
|
this.lc_fire_operation_detail = data?.lc_fire_operation_detail || [];
|
|||
|
|
await this.getDeptList();
|
|||
|
|
await this.fillFormData(this.formConf, this.formData);
|
|||
|
|
this.showPage = true;
|
|||
|
|
await this.initData();
|
|||
|
|
this.loading = false;
|
|||
|
|
} else {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '暂无此页面',
|
|||
|
|
icon: 'none',
|
|||
|
|
complete: () => {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
uni.navigateBack();
|
|||
|
|
}, 1500)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取表单配置失败:', error);
|
|||
|
|
this.loading = false;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
getDeptList() {
|
|||
|
|
return new Promise((resolve) => {
|
|||
|
|
getOrganizeSelector({type:'all'}).then(res => {
|
|||
|
|
if (res.code == 0 && res.data) {
|
|||
|
|
this.deptList = this.formatDeptData(res.data);
|
|||
|
|
}
|
|||
|
|
resolve();
|
|||
|
|
}).catch((error) => {
|
|||
|
|
console.error('获取部门列表失败:', error);
|
|||
|
|
resolve();
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
},
|
|||
|
|
formatDeptData(data) {
|
|||
|
|
const result = [];
|
|||
|
|
const formatItem = (item) => {
|
|||
|
|
let deptId = item.depthd || item.id || item.deptId;
|
|||
|
|
let deptName = item.depthName || item.deptName || item.fullName || item.name || item.orgNameTree;
|
|||
|
|
deptId = String(deptId || '');
|
|||
|
|
return {
|
|||
|
|
...item,
|
|||
|
|
deptId: deptId,
|
|||
|
|
deptName: deptName ,
|
|||
|
|
depthd: item.depthd,
|
|||
|
|
depthName: item.depthName,
|
|||
|
|
id: item.id
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
if (Array.isArray(data)) {
|
|||
|
|
data.forEach(item => {
|
|||
|
|
const formatted = formatItem(item);
|
|||
|
|
if (formatted.deptId) {
|
|||
|
|
result.push(formatted);
|
|||
|
|
}
|
|||
|
|
if (item.children && Array.isArray(item.children)) {
|
|||
|
|
const children = this.formatDeptData(item.children);
|
|||
|
|
result.push(...children);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
},
|
|||
|
|
async initData() {
|
|||
|
|
try {
|
|||
|
|
await this.$nextTick();
|
|||
|
|
if (this.dataForm.id) {
|
|||
|
|
const extra = {
|
|||
|
|
modelId: this.modelId,
|
|||
|
|
id: this.dataForm.id,
|
|||
|
|
type: 1
|
|||
|
|
};
|
|||
|
|
uni.setStorageSync('dynamicModelExtra', extra);
|
|||
|
|
const res = await getModelInfo(this.modelId, this.dataForm.id);
|
|||
|
|
console.log(res.data,'res.data111')
|
|||
|
|
console.log(res.data.jeelowcode_subtable_data,'res.data222')
|
|||
|
|
if(!!res.data.approveStatus&&(res.data.approveStatus !== 0 || res.data.approveStatus == 3)){
|
|||
|
|
// 不是未发起和驳回的都不可编辑
|
|||
|
|
this.disableAllFormFields();
|
|||
|
|
}
|
|||
|
|
this.dataForm = res.data;
|
|||
|
|
if (!res.data) return;
|
|||
|
|
this.formData = {
|
|||
|
|
...res.data,
|
|||
|
|
id: this.dataForm.id,
|
|||
|
|
lc_fire_operation_detail: res.data.jeelowcode_subtable_data?.lc_fire_operation_detail || res.data?.lc_fire_operation_detail || [],
|
|||
|
|
sDate: res.data.sDate,
|
|||
|
|
eDate: res.data.eDate ? new Date(res.data.eDate).getTime() : null,
|
|||
|
|
applyDepId: res.data.applyDepId ? String(res.data.applyDepId) : '',
|
|||
|
|
applyDepName: res.data.applyDepName || '',
|
|||
|
|
applyDepData: res.data.applyDepData || null,
|
|||
|
|
};
|
|||
|
|
this.$nextTick(()=>{
|
|||
|
|
if (this.$refs.dynamicForm && this.$refs.dynamicForm.setFormData) {
|
|||
|
|
this.$refs.dynamicForm.setFormData('applyDepId', this.formData.applyDepId);
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
// 获取审批记录
|
|||
|
|
await this.getApprovalData();
|
|||
|
|
this.initMoreMenuList()
|
|||
|
|
} else {
|
|||
|
|
const {user,deptInfoList} = this.userInfo
|
|||
|
|
this.isAdd = true;
|
|||
|
|
this.formData = {
|
|||
|
|
...this.formData,
|
|||
|
|
lc_fire_operation_detail: this.lc_fire_operation_detail,
|
|||
|
|
applyDepId: deptInfoList ? String(deptInfoList[0].deptId) : '' ,
|
|||
|
|
applyDepName: deptInfoList && deptInfoList[0].deptName,
|
|||
|
|
applyUser: user.nickname
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
if (this.deptList && this.deptList.length > 0) {
|
|||
|
|
await this.fillFormData(this.formConf, this.formData);
|
|||
|
|
if (this.$refs.dynamicForm && this.$refs.dynamicForm.setFormData) {
|
|||
|
|
this.$refs.dynamicForm.setFormData(this.formConf.formData);
|
|||
|
|
}
|
|||
|
|
setTimeout(() => {
|
|||
|
|
this.key = +new Date();
|
|||
|
|
}, 200);
|
|||
|
|
} else {
|
|||
|
|
console.warn('部门列表未加载完成,等待重试');
|
|||
|
|
setTimeout(() => {
|
|||
|
|
this.initData();
|
|||
|
|
}, 300);
|
|||
|
|
}
|
|||
|
|
this.loading = false;
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('初始化数据失败:', error);
|
|||
|
|
this.loading = false;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
disableAllFormFields() {
|
|||
|
|
const disableField = (field) => {
|
|||
|
|
// 禁用当前字段
|
|||
|
|
if (field.__config__) {
|
|||
|
|
this.$set(field.__config__, 'disabled', true);
|
|||
|
|
this.$set(field, 'disabled', true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 禁用子表字段
|
|||
|
|
if (field.children && Array.isArray(field.children)) {
|
|||
|
|
field.children.forEach(child => disableField(child));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 禁用嵌套字段
|
|||
|
|
if (field.__config__ && field.__config__.children && Array.isArray(field.__config__.children)) {
|
|||
|
|
field.__config__.children.forEach(child => disableField(child));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 特殊处理组件值
|
|||
|
|
if (field.modelValue !== undefined) {
|
|||
|
|
this.$set(field, 'modelValue', field.modelValue);
|
|||
|
|
}
|
|||
|
|
if (field.value !== undefined) {
|
|||
|
|
this.$set(field, 'value', field.value);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 遍历所有顶级字段
|
|||
|
|
if (this.formConf && this.formConf.fields && Array.isArray(this.formConf.fields)) {
|
|||
|
|
this.formConf.fields.forEach(field => {
|
|||
|
|
disableField(field);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 禁用整个表单组件
|
|||
|
|
if (this.$refs.dynamicForm) {
|
|||
|
|
this.$refs.dynamicForm.disabled = true;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
async fillFormData(form, data) {
|
|||
|
|
return new Promise((resolve) => {
|
|||
|
|
this.$nextTick(() => {
|
|||
|
|
const loop = (list, parent) => {
|
|||
|
|
for (let i = 0; i < list.length; i++) {
|
|||
|
|
let item = list[i];
|
|||
|
|
let vModel = item.__vModel__;
|
|||
|
|
let config = item.__config__;
|
|||
|
|
if (vModel === 'applyDepId' && config.jnpfKey === 'organizeSelect') {
|
|||
|
|
this.type = item.type = config.type
|
|||
|
|
item.options = [...(this.deptList || [])].map(dept => ({
|
|||
|
|
id: String(dept.deptId || dept.id),
|
|||
|
|
orgNameTree: dept.deptName || dept.depthName || dept.orgNameTree ,
|
|||
|
|
deptId: dept.deptId,
|
|||
|
|
deptName: dept.deptName,
|
|||
|
|
...dept
|
|||
|
|
}));
|
|||
|
|
const applyDepId = data.applyDepId ? String(data.applyDepId) : '';
|
|||
|
|
console.log(applyDepId,'applyDepId---')
|
|||
|
|
const applyDepName = data.applyDepName || '';
|
|||
|
|
if (applyDepId && applyDepId !== '') {
|
|||
|
|
let matchedOption = item.options.find(opt =>
|
|||
|
|
String(opt.id) === applyDepId
|
|||
|
|
);
|
|||
|
|
if (!matchedOption && applyDepName) {
|
|||
|
|
matchedOption = {
|
|||
|
|
id: applyDepId,
|
|||
|
|
orgNameTree: applyDepName,
|
|||
|
|
deptId: applyDepId,
|
|||
|
|
deptName: applyDepName
|
|||
|
|
};
|
|||
|
|
item.options.unshift(matchedOption);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
// this.$set(item, 'modelValue', applyDepId);
|
|||
|
|
// this.$set(item, 'value', applyDepId); // 兼容部分组件的value字段
|
|||
|
|
// this.$set(item, '__value__', matchedOption ? matchedOption.orgNameTree : applyDepName);
|
|||
|
|
config.defaultValue = applyDepId;
|
|||
|
|
item.modelValue = applyDepId;
|
|||
|
|
item.value = applyDepId;
|
|||
|
|
item.__value__ = matchedOption ? matchedOption.orgNameTree : applyDepName;
|
|||
|
|
const innerSelectedData = matchedOption ? [
|
|||
|
|
{
|
|||
|
|
id: matchedOption.id,
|
|||
|
|
orgNameTree: matchedOption.orgNameTree,
|
|||
|
|
deptId: matchedOption.deptId,
|
|||
|
|
deptName: matchedOption.deptName
|
|||
|
|
}
|
|||
|
|
] : [];
|
|||
|
|
item.props = {
|
|||
|
|
value: 'id',
|
|||
|
|
label: 'orgNameTree',
|
|||
|
|
innerSelectedData: innerSelectedData
|
|||
|
|
};
|
|||
|
|
item.selectedData = matchedOption ? [
|
|||
|
|
{
|
|||
|
|
id: matchedOption.id,
|
|||
|
|
orgNameTree: matchedOption.orgNameTree,
|
|||
|
|
deptId: matchedOption.deptId,
|
|||
|
|
deptName: matchedOption.deptName
|
|||
|
|
}
|
|||
|
|
] : [];
|
|||
|
|
item.innerSelectedData = item.selectedData;
|
|||
|
|
if (!form.formData) form.formData = {};
|
|||
|
|
form.formData[vModel] = applyDepId;
|
|||
|
|
form.formData['applyDepName'] = item.__value__;
|
|||
|
|
console.log(form.formData,'form.formData---')
|
|||
|
|
console.log(item,'item---')
|
|||
|
|
} else {
|
|||
|
|
item.selectedData = [];
|
|||
|
|
item.modelValue = '';
|
|||
|
|
item.__value__ = '';
|
|||
|
|
config.defaultValue = '';
|
|||
|
|
if (form.formData) {
|
|||
|
|
form.formData[vModel] = '';
|
|||
|
|
form.formData['applyDepName'] = '';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (vModel) {
|
|||
|
|
let val = data.hasOwnProperty(vModel) ? data[vModel] : config.defaultValue;
|
|||
|
|
if (!config.isSubTable) config.defaultValue = val;
|
|||
|
|
if (this.isAdd || config.isSubTable) {
|
|||
|
|
if (config.defaultCurrent) {
|
|||
|
|
if (config.jnpfKey === 'datePicker') {
|
|||
|
|
if (!data.hasOwnProperty(vModel)) {
|
|||
|
|
let format = this.jnpf.handelFormat(item.format)
|
|||
|
|
let dateStr = this.jnpf.toDate(new Date().getTime(), format)
|
|||
|
|
let time = format === 'yyyy' ? '-01-01 00:00:00' : format === 'yyyy-MM' ?
|
|||
|
|
'-01 00:00:00' : format === 'yyyy-MM-dd' ?
|
|||
|
|
' 00:00:00' : ''
|
|||
|
|
val = new Date(dateStr + time).getTime()
|
|||
|
|
config.defaultValue = val
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (config.jnpfKey === 'timePicker') {
|
|||
|
|
if (!data.hasOwnProperty(vModel)) {
|
|||
|
|
config.defaultValue = this.jnpf.toDate(new Date(), item.format)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (config.jnpfKey === 'organizeSelect' && this.userInfo.organizeIds?.length) {
|
|||
|
|
config.defaultValue = item.multiple ? this.userInfo.organizeIds :
|
|||
|
|
this.userInfo.organizeId
|
|||
|
|
}
|
|||
|
|
if (config.jnpfKey === 'posSelect' && this.userInfo.positionIds?.length) {
|
|||
|
|
config.defaultValue = item.multiple ? this.userInfo.positionIds :
|
|||
|
|
this.userInfo.positionId
|
|||
|
|
}
|
|||
|
|
const userId = this.userInfo.userId
|
|||
|
|
if (config.jnpfKey === 'userSelect' && userId) {
|
|||
|
|
config.defaultValue = item.multiple ? [userId] : userId;
|
|||
|
|
}
|
|||
|
|
if (config.jnpfKey === 'usersSelect' && userId) {
|
|||
|
|
config.defaultValue = [userId + '--user'];
|
|||
|
|
}
|
|||
|
|
if (config.jnpfKey === 'sign' && this.userInfo.signImg) {
|
|||
|
|
config.defaultValue = this.userInfo.signImg
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const btn_detail = this.$permission.hasBtnP('btn_detail', this.formPermissionList?.menuId)
|
|||
|
|
const btn_edit = this.$permission.hasBtnP('btn_edit', this.formPermissionList?.menuId)
|
|||
|
|
if (!!this.dataForm.id && !btn_edit && btn_detail) item.disabled = btn_detail
|
|||
|
|
let noShow = !config.noShow ? false : config.noShow
|
|||
|
|
let isVisibility = false
|
|||
|
|
if (!config.visibility || (Array.isArray(config.visibility) && config.visibility.includes('app'))) {
|
|||
|
|
isVisibility = true
|
|||
|
|
}
|
|||
|
|
this.$set(config, 'isVisibility', isVisibility)
|
|||
|
|
if (this.formPermissionList.useFormPermission) {
|
|||
|
|
let id = config.isSubTable ? parent.__vModel__ + '-' + vModel : vModel
|
|||
|
|
noShow = true
|
|||
|
|
if (this.formList && this.formList.length) {
|
|||
|
|
noShow = !this.formList.some(o => o.enCode === id)
|
|||
|
|
}
|
|||
|
|
noShow = config.noShow ? config.noShow : noShow
|
|||
|
|
this.$set(config, 'noShow', noShow)
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
let noShow = config.noShow ? config.noShow : false,
|
|||
|
|
isVisibility = false
|
|||
|
|
if (!config.visibility || (Array.isArray(config.visibility) && config.visibility.includes('app'))) {
|
|||
|
|
isVisibility = true
|
|||
|
|
}
|
|||
|
|
this.$set(config, 'isVisibility', isVisibility)
|
|||
|
|
this.$set(config, 'noShow', noShow)
|
|||
|
|
}
|
|||
|
|
if (config && config.children && Array.isArray(config.children)) {
|
|||
|
|
loop(config.children, item);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
loop(form.fields);
|
|||
|
|
if (!form.formData) {
|
|||
|
|
form.formData = {};
|
|||
|
|
}
|
|||
|
|
const formDataToMerge = {
|
|||
|
|
...data,
|
|||
|
|
applyDepId: data.applyDepId || '',
|
|||
|
|
applyDepName: data.applyDepName || ''
|
|||
|
|
};
|
|||
|
|
form.formData = { ...form.formData, ...formDataToMerge };
|
|||
|
|
setTimeout(() => {
|
|||
|
|
const applyField = form.fields.find(f => f.__vModel__ === 'applyDepId');
|
|||
|
|
if (!applyField || !applyField.selectedData || applyField.selectedData.length === 0) {
|
|||
|
|
console.warn('申请单位无选中数据');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const dynamicForm = this.$refs.dynamicForm;
|
|||
|
|
if (!dynamicForm) return;
|
|||
|
|
const findOrganizeSelect = (component) => {
|
|||
|
|
if (component.$options.name === 'jnpf-organize-select') {
|
|||
|
|
return component;
|
|||
|
|
}
|
|||
|
|
for (let child of component.$children) {
|
|||
|
|
const res = findOrganizeSelect(child);
|
|||
|
|
if (res) return res;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
};
|
|||
|
|
const organizeSelect = findOrganizeSelect(dynamicForm);
|
|||
|
|
if (organizeSelect) {
|
|||
|
|
organizeSelect.selectedData = applyField.selectedData;
|
|||
|
|
} else {
|
|||
|
|
console.warn('未找到jnpf-organize-select组件');
|
|||
|
|
}
|
|||
|
|
}, 1000);
|
|||
|
|
this.key = +new Date();
|
|||
|
|
setTimeout(() => {
|
|||
|
|
const finalApplyField = form.fields.find(f => f.__vModel__ === 'applyDepId');
|
|||
|
|
if (finalApplyField) {
|
|||
|
|
}
|
|||
|
|
}, 100);
|
|||
|
|
resolve();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
sumbitForm(data, callback) {
|
|||
|
|
const {billNoPrefix} = this.config
|
|||
|
|
if (!data) return;
|
|||
|
|
const filePathArr = [...data.attachment]
|
|||
|
|
const attachment = filePathArr.map(item => item.fileUrl)
|
|||
|
|
this.btnLoading = true;
|
|||
|
|
const applyDepName = this.deptList?.filter(item=>item.deptId === data.applyDepId)[0]?.deptName
|
|||
|
|
const formData = {
|
|||
|
|
...this.formData,
|
|||
|
|
...data,
|
|||
|
|
id: data?.id || '',
|
|||
|
|
applyDepName,
|
|||
|
|
attachment: attachment.join(',')
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if(!this.dataForm.id){
|
|||
|
|
formData.billNo = billNoPrefix + new Date().getTime()
|
|||
|
|
}
|
|||
|
|
this.dataForm.data = JSON.stringify(formData);
|
|||
|
|
const params = {
|
|||
|
|
id: this.dataForm.id,
|
|||
|
|
operateType: this.dataForm.id ? 1 : 0,
|
|||
|
|
attachments: data.attachment,
|
|||
|
|
data: {
|
|||
|
|
...formData
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
const formMethod = createModel;
|
|||
|
|
formMethod(this.modelId, params).then(res => {
|
|||
|
|
uni.showToast({
|
|||
|
|
title:'保存成功',
|
|||
|
|
complete: () => {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
if (this.clickType == 'save_add') {
|
|||
|
|
this.key = +new Date();
|
|||
|
|
this.$nextTick(() => {
|
|||
|
|
this.$refs.dynamicForm && this.$refs.dynamicForm.resetForm();
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
this.btnLoading = false;
|
|||
|
|
this.initData();
|
|||
|
|
if (this.clickType != 'save_proceed' && this.clickType != 'save_add') {
|
|||
|
|
uni.$emit('refresh');
|
|||
|
|
uni.navigateBack();
|
|||
|
|
}
|
|||
|
|
}, 1500);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}).catch(() => {
|
|||
|
|
this.btnLoading = false;
|
|||
|
|
});
|
|||
|
|
if (callback && typeof callback === "function") callback();
|
|||
|
|
},
|
|||
|
|
commonSubmit(type) {
|
|||
|
|
this.clickType = type;
|
|||
|
|
this.submit(type);
|
|||
|
|
},
|
|||
|
|
submit(type) {
|
|||
|
|
this.clickType = type;
|
|||
|
|
if (this.isPreview == '1') return this.$u.toast('功能预览不支持数据保存');
|
|||
|
|
this.$refs.dynamicForm && this.$refs.dynamicForm.submitForm();
|
|||
|
|
},
|
|||
|
|
// 获取审批记录
|
|||
|
|
async getApprovalData() {
|
|||
|
|
try {
|
|||
|
|
const res = await getByProcess(this.formData.processInstanceId);
|
|||
|
|
const result = []
|
|||
|
|
if (res.code === 0) {
|
|||
|
|
// this.approvalData = res.data
|
|||
|
|
res.data.forEach((task) => {
|
|||
|
|
if (task.result !== 4) {
|
|||
|
|
result.push(task)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
result.sort((a, b) => {
|
|||
|
|
// 有已完成的情况,按照完成时间倒序
|
|||
|
|
if (a.endTime && b.endTime) {
|
|||
|
|
return b.endTime - a.endTime
|
|||
|
|
} else if (a.endTime) {
|
|||
|
|
return 1
|
|||
|
|
} else if (b.endTime) {
|
|||
|
|
return -1
|
|||
|
|
// 都是未完成,按照创建时间倒序
|
|||
|
|
} else {
|
|||
|
|
return b.createTime - a.createTime
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
this.approvalData = result
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error('获取审批记录失败:', err);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
// 状态样式
|
|||
|
|
getStatusClass(result) {
|
|||
|
|
return {
|
|||
|
|
'status-processing': result === 1,
|
|||
|
|
'status-pass': result === 2,
|
|||
|
|
'status-reject': result === 3
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
getStatusTagClass(result) {
|
|||
|
|
return {
|
|||
|
|
'tag-processing': result === 1,
|
|||
|
|
'tag-pass': result === 2,
|
|||
|
|
'tag-reject': result === 3
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
// 时间格式化
|
|||
|
|
formatTime(timestamp) {
|
|||
|
|
if (!timestamp) return '-';
|
|||
|
|
const date = new Date(timestamp);
|
|||
|
|
return `${date.getFullYear()}-${this.padZero(date.getMonth() + 1)}-${this.padZero(date.getDate())} ${this.padZero(date.getHours())}:${this.padZero(date.getMinutes())}:${this.padZero(date.getSeconds())}`;
|
|||
|
|
},
|
|||
|
|
padZero(num) {
|
|||
|
|
return num.toString().padStart(2, '0');
|
|||
|
|
},
|
|||
|
|
// 耗时格式化
|
|||
|
|
formatDuration(millis) {
|
|||
|
|
if (!millis) return '-';
|
|||
|
|
const seconds = Math.floor(millis / 1000);
|
|||
|
|
if (seconds < 60) {
|
|||
|
|
return `${seconds} 秒`;
|
|||
|
|
}
|
|||
|
|
const minutes = Math.floor(seconds / 60);
|
|||
|
|
if (minutes < 60) {
|
|||
|
|
return `${minutes} 分钟`;
|
|||
|
|
}
|
|||
|
|
const hours = Math.floor(minutes / 60);
|
|||
|
|
return `${hours} 小时 ${minutes % 60} 分钟`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss">
|
|||
|
|
page {
|
|||
|
|
background-color: #f0f2f6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.buttom-actions {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: flex-end;
|
|||
|
|
padding: 20rpx 30rpx;
|
|||
|
|
background: #fff;
|
|||
|
|
position: fixed;
|
|||
|
|
bottom: 0;
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
z-index: 99;
|
|||
|
|
gap: 20rpx;
|
|||
|
|
|
|||
|
|
.buttom-btn {
|
|||
|
|
min-width: 180rpx;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.more-btn {
|
|||
|
|
position: relative;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
width: 80rpx;
|
|||
|
|
height: 80rpx;
|
|||
|
|
|
|||
|
|
.more-text {
|
|||
|
|
font-size: 22rpx;
|
|||
|
|
color: #606266;
|
|||
|
|
margin-top: 4rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.more-menu {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 100%;
|
|||
|
|
right: 0;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 8rpx;
|
|||
|
|
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.1);
|
|||
|
|
width: 200rpx;
|
|||
|
|
z-index: 100;
|
|||
|
|
padding: 10rpx 0;
|
|||
|
|
|
|||
|
|
.menu-item {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 16rpx 20rpx;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
cursor: pointer;
|
|||
|
|
|
|||
|
|
&:hover {
|
|||
|
|
background-color: #f5f7fa;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.menu-icon {
|
|||
|
|
font-size: 32rpx;
|
|||
|
|
margin-right: 12rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.menu-label {
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 流程选择弹框样式 */
|
|||
|
|
.process-dialog {
|
|||
|
|
width: 90vw;
|
|||
|
|
max-height: 70vh;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 12rpx;
|
|||
|
|
overflow: hidden;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.dialog-header {
|
|||
|
|
padding: 30rpx;
|
|||
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.dialog-title {
|
|||
|
|
font-size: 32rpx;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #333;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.close-icon {
|
|||
|
|
padding: 10rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.process-list {
|
|||
|
|
flex: 1;
|
|||
|
|
overflow-y: auto;
|
|||
|
|
max-height: 50vh;
|
|||
|
|
padding: 20rpx 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.process-item {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: flex-start;
|
|||
|
|
padding: 24rpx 30rpx;
|
|||
|
|
border-bottom: 1rpx solid #f8f8f8;
|
|||
|
|
transition: background-color 0.3s;
|
|||
|
|
cursor: pointer;
|
|||
|
|
|
|||
|
|
&.selected-item {
|
|||
|
|
background-color: #f5f7fa;
|
|||
|
|
border-left: 4rpx solid #2979ff;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.process-item:active {
|
|||
|
|
background-color: #f0f2f5;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.process-item-left {
|
|||
|
|
margin-right: 20rpx;
|
|||
|
|
padding-top: 6rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty-process {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
padding: 60rpx 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty-text {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #999;
|
|||
|
|
margin-top: 20rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-process {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
padding: 60rpx 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-text {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #999;
|
|||
|
|
margin-top: 20rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.dialog-footer {
|
|||
|
|
display: flex;
|
|||
|
|
padding: 30rpx;
|
|||
|
|
border-top: 1rpx solid #f0f0f0;
|
|||
|
|
gap: 20rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.footer-btn {
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.cancel-btn {
|
|||
|
|
background: #f5f5f5;
|
|||
|
|
color: #666;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.submit-btn {
|
|||
|
|
background: linear-gradient(135deg, #3d6dcc, #2a52b5);
|
|||
|
|
color: #fff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.submit-btn[disabled] {
|
|||
|
|
opacity: 0.6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 审批人选择弹框样式 */
|
|||
|
|
.approver-dialog {
|
|||
|
|
width: 90vw;
|
|||
|
|
max-height: 80vh;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 12rpx;
|
|||
|
|
overflow: hidden;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approver-content {
|
|||
|
|
flex: 1;
|
|||
|
|
overflow-y: auto;
|
|||
|
|
max-height: 60vh;
|
|||
|
|
padding: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approver-node {
|
|||
|
|
margin-bottom: 40rpx;
|
|||
|
|
padding: 20rpx;
|
|||
|
|
background: #f9fafc;
|
|||
|
|
border-radius: 8rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.node-title {
|
|||
|
|
margin-bottom: 20rpx;
|
|||
|
|
padding-bottom: 10rpx;
|
|||
|
|
border-bottom: 1rpx solid #ebeef5;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.node-label {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #606266;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.node-name {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #333;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.candidate-section {
|
|||
|
|
margin-top: 20rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-title {
|
|||
|
|
margin-bottom: 16rpx;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-label {
|
|||
|
|
font-size: 26rpx;
|
|||
|
|
color: #606266;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-approver {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
padding: 60rpx 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty-approver {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
padding: 60rpx 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.confirm-btn {
|
|||
|
|
background: linear-gradient(135deg, #3d6dcc, #2a52b5);
|
|||
|
|
color: #fff;
|
|||
|
|
margin: 0 30rpx 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.confirm-btn[disabled] {
|
|||
|
|
opacity: 0.6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 审批记录样式 */
|
|||
|
|
.approval-title {
|
|||
|
|
font-size: 32rpx;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #333;
|
|||
|
|
padding: 20rpx 30rpx;
|
|||
|
|
border-bottom: 1rpx solid #eee;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-list {
|
|||
|
|
padding: 20rpx 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-item {
|
|||
|
|
display: flex;
|
|||
|
|
position: relative;
|
|||
|
|
margin-bottom: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-line-container {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
margin-right: 20rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-line {
|
|||
|
|
width: 2rpx;
|
|||
|
|
background-color: #e5e5e5;
|
|||
|
|
flex: 1;
|
|||
|
|
margin-top: 8rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.status-icon {
|
|||
|
|
width: 32rpx;
|
|||
|
|
height: 32rpx;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
|
|||
|
|
&.status-processing {
|
|||
|
|
background-color: #E6F7FF;
|
|||
|
|
}
|
|||
|
|
&.status-pass {
|
|||
|
|
background-color: #F0F9EB;
|
|||
|
|
}
|
|||
|
|
&.status-reject {
|
|||
|
|
background-color: #FFF2F0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-content {
|
|||
|
|
flex: 1;
|
|||
|
|
background-color: #fff;
|
|||
|
|
border-radius: 8rpx;
|
|||
|
|
padding: 20rpx;
|
|||
|
|
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.05);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.task-header {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
margin-bottom: 16rpx;
|
|||
|
|
|
|||
|
|
.task-name {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #333;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.status-tag {
|
|||
|
|
font-size: 24rpx;
|
|||
|
|
padding: 4rpx 12rpx;
|
|||
|
|
border-radius: 4rpx;
|
|||
|
|
margin-left: 12rpx;
|
|||
|
|
|
|||
|
|
&.tag-processing {
|
|||
|
|
background-color: #E6F7FF;
|
|||
|
|
color: #409EFF;
|
|||
|
|
}
|
|||
|
|
&.tag-pass {
|
|||
|
|
background-color: #F0F9EB;
|
|||
|
|
color: #67C23A;
|
|||
|
|
}
|
|||
|
|
&.tag-reject {
|
|||
|
|
background-color: #FFF2F0;
|
|||
|
|
color: #F56C6C;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-row {
|
|||
|
|
font-size: 24rpx;
|
|||
|
|
color: #666;
|
|||
|
|
line-height: 1.5;
|
|||
|
|
margin-bottom: 12rpx;
|
|||
|
|
|
|||
|
|
.info-label {
|
|||
|
|
color: #999;
|
|||
|
|
}
|
|||
|
|
.info-value {
|
|||
|
|
color: #666;
|
|||
|
|
}
|
|||
|
|
.dept-tag {
|
|||
|
|
display: inline-block;
|
|||
|
|
background-color: #F5F7FA;
|
|||
|
|
color: #666;
|
|||
|
|
padding: 2rpx 8rpx;
|
|||
|
|
border-radius: 4rpx;
|
|||
|
|
margin-left: 8rpx;
|
|||
|
|
font-size: 22rpx;
|
|||
|
|
}
|
|||
|
|
.ml-20 {
|
|||
|
|
margin-left: 20rpx;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.reason-box {
|
|||
|
|
font-size: 24rpx;
|
|||
|
|
color: #333;
|
|||
|
|
background-color: #F9F9F9;
|
|||
|
|
padding: 12rpx;
|
|||
|
|
border-radius: 4rpx;
|
|||
|
|
margin-top: 8rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 新增:审批意见弹窗样式 */
|
|||
|
|
.approval-reason-dialog {
|
|||
|
|
width: 80vw;
|
|||
|
|
max-width: 600rpx;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 12rpx;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-reason-dialog .dialog-header {
|
|||
|
|
padding: 20rpx 30rpx;
|
|||
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-reason-dialog .dialog-content {
|
|||
|
|
padding: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-reason-dialog .input-label {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #333;
|
|||
|
|
margin-bottom: 16rpx;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-reason-dialog .reason-input {
|
|||
|
|
font-size: 26rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.approval-reason-dialog .dialog-footer {
|
|||
|
|
padding: 20rpx 30rpx;
|
|||
|
|
border-top: 1rpx solid #f0f0f0;
|
|||
|
|
}
|
|||
|
|
</style>
|