123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- <template>
- <el-dialog
- :title="editData ? (props.mode === 'view' ? '查看审批流程' : '编辑审批流程') : '新建审批流程'"
- v-model="visible"
- width="900px"
- @close="onCancel"
- >
- <el-form :model="form" label-width="110px" :rules="rules" ref="formRef" :disabled="props.mode === 'view'">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="流程名称" prop="name">
- <el-input v-model="form.name" placeholder="请输入" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="适用场景" prop="scene">
- <el-input v-model="form.scene" placeholder="请输入" />
- </el-form-item>
- </el-col>
-
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="流程类型" prop="workflow_type">
- <el-select v-model="form.workflow_type" placeholder="请选择流程类型" :disabled="props.mode === 'view'">
- <el-option label="设备借用申请" value="0" />
- <el-option label="设备维修申请" value="1" />
- <el-option label="设备采购申请" value="2" />
- <el-option label="其他申请" value="3" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="流程描述" prop="description">
- <el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入流程描述" :disabled="props.mode === 'view'" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="是否启用" prop="is_active">
- <el-select v-model="form.is_active" placeholder="请选择启用还是禁用" :disabled="props.mode === 'view'">
- <el-option label="启用" :value="true" />
- <el-option label="禁用" :value="false" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-divider>条件选择</el-divider>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="借用天数大于" prop="condition.days">
- <el-input-number v-model="form.condition.days" :min="1" controls-position="right" style="width: 100px" />
- <span style="margin-left: 8px">天</span>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="用户角色" prop="condition.roles">
- <el-checkbox-group v-model="form.condition.roles">
- <el-checkbox label="教师" value="teacher" />
- <el-checkbox label="学生" value="student" />
- <el-checkbox label="非本院师生" value="external" />
- </el-checkbox-group>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="设备标签" prop="condition.equipment">
- <el-select v-model="form.condition.equipment" placeholder="请选择">
- <el-option
- v-for="(item, index) in resdevicelist"
- :key="index"
- :label="item.name"
- :value="item.id"
- />
- </el-select>
- <!-- <el-select v-model="form.condition.equipment" placeholder="请选择">
- <el-option label="贵重设备" value="贵重设备" />
- <el-option label="普通设备" value="普通设备" />
- </el-select> -->
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="借用类型" prop="condition.borrow_types">
- <el-checkbox-group v-model="form.condition.borrow_types" :disabled="props.mode === 'view'">
- <el-checkbox label="常规借用" value="0"></el-checkbox>
- <el-checkbox label="课堂借用" value="1"></el-checkbox>
- <el-checkbox label="特殊借用" value="2"></el-checkbox>
- </el-checkbox-group>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="借用方式" prop="condition.team_type">
- <el-checkbox-group v-model="form.condition.team_type" :disabled="props.mode === 'view'">
- <el-checkbox label="个人借用" value="0"></el-checkbox>
- <el-checkbox label="团队借用" value="1"></el-checkbox>
- </el-checkbox-group>
- </el-form-item>
- </el-col>
- </el-row>
- <el-divider>流程配置</el-divider>
- <div class="workflow-steps">
- <!-- 借用人 -->
- <div class="workflow-step">
- <el-card shadow="never" class="step-card borrower">
- <div class="step-title">借用人</div>
- </el-card>
- <div class="step-line"></div>
- </div>
- <!-- 审批步骤 -->
- <div class="workflow-step" v-for="(step, idx) in form.steps" :key="idx">
- <el-card shadow="never" class="step-card">
- <div class="step-title">
- 审批步骤{{ idx + 1 }}
- <el-button v-if="form.steps.length > 1 && idx !== 0" type="danger" size="small" @click="removeStep(idx)" style="margin-left: 10px">
- <el-icon><Minus /></el-icon> 删除步骤
- </el-button>
- </div>
- <div class="step-roles">
- <div v-for="(role, ridx) in step.roles" :key="ridx" class="role-row" style="position: relative; padding: 0 20px">
- <el-form-item
- :label="'角色'"
- :label-position="'left'"
- label-width="100px"
- :prop="`steps.${idx}.roles.${ridx}.name`"
- :rules="[{ required: true, message: '请选择角色', trigger: 'change' }]"
- >
- <!-- <el-select v-model="role.name" placeholder="请选择角色" style="width: 300px" @change="onRoleChange(idx, ridx, $event)"> -->
- <el-select v-model="role.name" placeholder="请选择角色" style="width: 300px">
- <el-option label="指导老师" value="指导老师" />
- <el-option label="管理员" value="管理员" />
- </el-select>
- </el-form-item>
- <el-form-item
- :label="'通过条件'"
- :label-position="'left'"
- :prop="`steps.${idx}.roles.${ridx}.passType`"
- :rules="[{ required: true, message: '请选择通过条件', trigger: 'change' }]"
- >
- <el-radio-group v-model="role.passType">
- <!-- <el-radio label="单人审核" value="0"></el-radio> -->
- <el-radio label="1名通过即可" value="1"></el-radio>
- <el-radio label="所有人员通过" value="2"></el-radio>
- </el-radio-group>
- </el-form-item>
- <el-button
- v-if="step.roles.length > 1 && ridx !== 0"
- type="danger"
- size="small"
- @click="removeRole(idx, ridx)"
- style="position: absolute; right: 0; top: 0"
- >
- <el-icon><Minus /></el-icon> 删除角色
- </el-button>
- </div>
- <div class="addRole" style="width: 100%; display: flex; justify-content: center">
- <el-button type="primary" size="small" @click="addRole(idx)" :disabled="step.roles.length >= 5">
- <el-icon><Plus /></el-icon> 添加角色
- </el-button>
- </div>
- </div>
- </el-card>
- <div class="step-line"></div>
- </div>
- <!-- 添加步骤按钮 -->
- <div style="text-align: center; margin: 16px 0">
- <el-button type="primary" @click="addStep" :disabled="form.steps.length >= 5">
- <el-icon><Plus /></el-icon> 添加审批步骤
- </el-button>
- </div>
- <!-- 审批完成 -->
- <div class="workflow-step">
- <el-card shadow="never" class="step-card done">
- <div class="step-title">审批完成</div>
- </el-card>
- </div>
- </div>
- </el-form>
- <template #footer>
- <el-button @click="onCancel">取消</el-button>
- <el-button v-if="props.mode !== 'view'" type="primary" @click="onSave">保存</el-button>
- </template>
- </el-dialog>
- </template>
- <script setup lang="ts">
- import { ref, watch, reactive ,nextTick } from 'vue';
- import { ElMessage } from 'element-plus';
- import { Plus, Minus } from '@element-plus/icons-vue';
- import * as api from '../api';
- import * as firstapi from './api';
- const props = defineProps<{
- visible: boolean;
- editData?: any;
- mode?: 'view' | 'edit' | 'add';
- }>();
- const emit = defineEmits(['update:visible', 'success']);
- const visible = ref(props.visible);
- watch(
- () => props.visible,
- (v) => (visible.value = v)
- );
- watch(visible, (v) => emit('update:visible', v));
- const resdevicelist=reactive([]);
- firstapi.GetDeviceClassList()
- .then(result => {
- const deviceData = result.data;
- // eslint-disable-next-line no-console
- console.log("获取到的data值:", deviceData);
- // 清空并填充响应式数组
- resdevicelist.splice(0, resdevicelist.length, ...deviceData);
- })
- .catch(error => {
- // eslint-disable-next-line no-console
- console.error("请求失败:", error);
- });
- const defaultRole = () => ({
- name: '',
- passType: '',
- });
- const defaultStep = () => ({
- roles: [defaultRole()],
- });
- const form = reactive({
- name: '',
- scene: '',
- workflow_type: "0", // 新增
- description: '', // 新增
- is_active: true,
- condition: {
- days: 1,
- roles: [],
- equipment: [],
- borrow_types: [], // 新增
- team_type:[],
- },
- steps: [defaultStep()],
- });
- const rules = reactive({
- name: [{ required: true, message: '请输入流程名称', trigger: 'blur' }],
- workflow_type: [{ required: true, message: '请选择流程类型', trigger: 'change' }],
- description: [{ required: true, message: '请输入流程描述', trigger: 'blur' }],
- is_active:[{ required: true, message: '请输选择是否启用', trigger: 'blur' }],
- 'condition.days': [{ required: true, message: '请输入借用天数', trigger: 'change' }],
- 'condition.roles': [{ required: true, message: '请选择用户角色', trigger: 'change' }],
- 'condition.equipment': [{ required: true, message: '请选择设备标签', trigger: 'change' }],
- 'condition.borrow_types': [{ required: true, message: '请选择借用类型', trigger: 'change' }],
- 'condition.team_type': [{ required: true, message: '请选择借用方式', trigger: 'change' }],
- });
- const formRef = ref();
- function generateStepRules() {
- form.steps.forEach((step, stepIdx) => {
- step.roles.forEach((role, roleIdx) => {
- rules[`steps.${stepIdx}.roles.${roleIdx}.name`] = [
- { required: true, message: '请选择角色', trigger: 'change' },
- ];
- rules[`steps.${stepIdx}.roles.${roleIdx}.passType`] = [
- { required: true, message: '请选择通过条件', trigger: 'change' },
- ];
- });
- });
- }
- watch(
- () => props.editData,
- async (val) => {
- // eslint-disable-next-line no-console
- console.error("编辑时获取到的值val:", val);
- if (val) {
- // Object.assign(form, JSON.parse(JSON.stringify(val)));
- const cloned = JSON.parse(JSON.stringify(val));
- form.name = cloned.name || '';
- form.scene = cloned.scene || '';
- form.workflow_type = String(cloned.workflow_type ?? '0');
- form.description = cloned.description || '';
- form.is_active = cloned.is_active ?? true;
- const tc = cloned.trigger_conditions || {};
- form.condition = {
- days: 1,
- roles: tc.user_types || [],
- equipment: Array.isArray(tc.equipment_categories) ? tc.equipment_categories[0] : '',
- borrow_types: tc.borrow_types || [],
- team_type: tc.team_type || [],
- };
- const res = await api.GetObj(cloned.id);
- // eslint-disable-next-line no-console
- console.log("编辑时res.data.steps:", res.data.steps);
- form.steps = Array.isArray(res.data.steps) && res.data.steps.length
- ? res.data.steps.map((step: any) => ({
- roles: [
- {
- name: step.step_name || '',
- passType: String(step.step_type ?? '1'),
- },
- ],
- }))
- : [defaultStep()];
- // Object.assign(form, cloned);
- } else {
- form.name = '';
- form.scene = '';
- form.workflow_type = "0";
- form.description = '';
- form.is_active = true;
- form.condition = { days: 1, roles: [], equipment: [], borrow_types: [],team_type:[] };
- form.steps = [defaultStep()];
- }
- generateStepRules();
- await nextTick();
- },
- { immediate: true }
- );
- function addStep() {
- if (form.steps.length >= 5) {
- ElMessage.warning('最多只能添加 5 个审批步骤');
- return;
- }
- form.steps.push(defaultStep());
- }
- function removeStep(idx: number) {
- if (form.steps.length > 1) form.steps.splice(idx, 1);
- }
- function addRole(stepIdx: number) {
- const step = form.steps[stepIdx];
- if (step.roles.length >= 5) {
- ElMessage.warning('每个步骤最多只能添加 5 个角色');
- return;
- }
- form.steps[stepIdx].roles.push(defaultRole());
- }
- function removeRole(stepIdx: number, roleIdx: number) {
- if (form.steps[stepIdx].roles.length > 1) form.steps[stepIdx].roles.splice(roleIdx, 1);
- }
- function onCancel() {
- visible.value = false;
- }
- const roleNameToId: { [key: string]: number } = {
- '管理员': 1,
- '指导老师': 2
- };
- async function onSave() {
- try {
- await formRef.value?.validate();
- } catch (err) {
- // eslint-disable-next-line no-console
- console.warn('表单验证失败:', err);
- return;
- }
- // 组装接口需要的数据
- const payload = {
- name: form.name,
- workflow_type: form.workflow_type,
- description: form.description,
- is_active: typeof form.is_active === 'boolean' ? form.is_active : true,
- trigger_conditions: {
- equipment_categories: form.condition?.equipment ? [form.condition.equipment] : ['贵重设备'],
- borrow_types: form.condition?.borrow_types?.length ? form.condition.borrow_types : ['0', '1', '2'],
- team_type: form.condition?.team_type?.length ? form.condition.team_type : ['0', '1'],
- user_types: form.condition?.roles?.length ? form.condition.roles:['student', 'teacher'],
- },
- };
- // eslint-disable-next-line no-console
- // console.log(payload);
- //创建审批
- const res = await api.AddObj(payload);
- const workflowId = res?.data?.id;
- if (!workflowId) {
- ElMessage.error('未能获取流程 ID');
- return;
- }
- for (let i = 0; i < form.steps.length; i++) {
- const step = form.steps[i];
- const stepOrder = i + 1;
- const roleNames = step.roles.map(role => role.name).filter(Boolean);
- const passTypes = step.roles.map(role => role.passType).filter(Boolean);
- const stepType = passTypes[0] || '1';
- const approverRoles = roleNames.map(name => roleNameToId[name]).filter(Boolean);
- const stepPayload = {
- workflow: String(workflowId),
- step_name: `${roleNames.join(',')}审批`,
- step_order: stepOrder,
- step_type: stepType,
- description: `由${roleNames.join(',')}进行审批`,
- approvers: [1], // 可选:你可以根据需要填入具体 ID
- approver_roles: approverRoles,
- approver_depts: [],
- approval_conditions: {
- required_fields: [],
- value_ranges: {}
- },
- timeout_hours: 24,
- timeout_action: "auto_reject",
- is_active: true
- };
- // eslint-disable-next-line no-console
- console.log(`步骤 ${stepOrder} payload`, stepPayload);
- await api.AddFirstObj(stepPayload);
- }
- // const selectedRoleNames = form.steps
- // .flatMap(step => step.roles.map(role => role.name))
- // .filter(name => !!name);
- // const selectedPassTypes = form.steps
- // .flatMap(step => step.roles.map(role => role.passType));
- // //组装审核接口
- // const firstpayload={
- // workflow: String(workflowId),
- // step_name: String(selectedRoleNames),
- // step_order: 1,
- // step_type: String(selectedPassTypes),
- // description:"由指导老师进行初审",
- // approvers: [1], // 指定审核人ID列表,可选
- // approver_roles: [1], // 审核角色ID列表,可选
- // approver_depts: [], // 审核部门ID列表,可选
- // approval_conditions: { // 审核条件,可以为空
- // required_fields: [], // 必填字段
- // value_ranges: {} // 字段值范围限制
- // },
- // timeout_hours: 24, // 超时时间(小时)
- // timeout_action: "auto_reject", // 超时处理:auto_approve=自动通过,auto_reject=自动拒绝,escalate=升级处理
- // is_active: true // 是否启用:true=启用,false=禁用
- // };
- // // eslint-disable-next-line no-console
- // console.log(firstpayload);
- // await api.AddFirstObj(firstpayload);
- ElMessage.success('保存成功');
- emit('success');
- visible.value = false;
- }
- </script>
- <style scoped>
- .workflow-steps {
- margin: 0 40px;
- }
- .workflow-step {
- position: relative;
- }
- .step-card {
- margin-bottom: 0;
- }
- .borrower {
- background: #e3f0ff;
- }
- .done {
- background: #eee;
- }
- .step-title {
- font-weight: bold;
- font-size: 16px;
- margin-bottom: 8px;
- }
- .step-line {
- width: 4px;
- height: 32px;
- background: #409eff;
- margin: 0 auto;
- }
- .role-row {
- margin-bottom: 8px;
- }
- </style>
|