初始化版本,引入智慧食堂模块,第三方模块

This commit is contained in:
zjf committed 2024-12-06 18:48:18 +08:00
commit d22f88efd3
677 files changed
+69341

No files matched your search

+295
View File
@@ -0,0 +1,295 @@
<template>
<div class="layout-padding">
<div class="layout-padding-view">
<div class="titlebar">
<div class="f1"></div>
<div class="f2">
<span class="center_t" effect="dark" :activeStep="activeStep == 0" @click="activeStep = 0">
<span :activeStep="activeStep == 0">1</span>
<span>{{ $t('flow.basicInformation') }}</span>
</span>
<span class="center_t" effect="dark" :activeStep="activeStep == 1" @click="activeStep = 1">
<span :activeStep="activeStep == 1">2</span>
<span>{{ $t('flow.formDesign') }}</span>
</span>
<span class="center_t" effect="dark" :activeStep="activeStep == 2" @click="activeStep = 2">
<span :activeStep="activeStep == 2">3</span>
<span>{{ $t('flow.processDesign') }}</span>
</span>
</div>
<div class="f3">
<el-button type="primary" @click="publish">{{ $t('flow.publish') }}</el-button>
</div>
</div>
<el-scrollbar height="calc(100vh - 250px)">
<step1 v-show="activeStep === 0" :groupId="paramGroupId" ref="step1Ref" />
<step2 v-show="activeStep === 1" ref="step2Ref" />
<step3 v-show="activeStep === 2" :nodeConfigObj="step3NodeConfig" ref="step3Ref" />
</el-scrollbar>
<!-- //验证每一步-->
<el-dialog v-model="validateDialogShow" :title="$t('flow.processCheck')">
<el-steps :active="validateFlowStep" finish-status="success" simple style="margin-top: 20px">
<el-step :title="$t('flow.basicInformation')" />
<el-step :title="$t('flow.formDesign')" />
<el-step :title="$t('flow.processDesign')" />
</el-steps>
<div style="text-align: center">
<el-result v-if="validateFlowStep == 3" icon="success" :title="$t('flow.checkSuccess')" :sub-title="$t('flow.checkSubSuccess')">
<template #extra>
<el-button type="primary" @click="submitFlow">{{ $t('flow.submit') }}</el-button>
</template>
</el-result>
<el-result
:title="$t('flow.checkIng')"
:sub-title="$t('flow.checkSubIng')"
v-if="validateErrMsg.length == 0 && validateDialogShow && validatingShow && validateFlowStep < 3"
>
<template #icon>
<span v-loading="true" style="display: inline-block; border: 0px solid red; width: 100px; height: 100px"> </span>
</template>
</el-result>
<el-result v-if="validateErrMsg.length > 0" icon="error" title="检查失败">
<template #sub-title>
<div v-for="item in validateErrMsg" :key="item">
<el-text type="danger">
<el-icon>
<WarnTriangleFilled />
</el-icon>
{{ item }}
</el-text>
</div>
</template>
<template #extra>
<el-button type="primary" @click="gotoEdit">{{ $t('common.editBtn') }}</el-button>
</template>
</el-result>
</div>
</el-dialog>
</div>
</div>
</template>
<script lang="ts" setup>
import { WarnTriangleFilled } from '@element-plus/icons-vue';
import { addFlow } from '/@/api/flow/flow';
import Step1 from './step1.vue';
import Step2 from './step2.vue';
import Step3 from './step3.vue';
import { useFlowStore } from '../workflow/stores/flow';
import { LocationQuery, LocationQueryValue, useRouter } from 'vue-router';
let store = useFlowStore();
const step1Ref = ref();
const step2Ref = ref();
const step3Ref = ref();
const validateErrMsg = ref([]);
const activeStep = ref(0);
const validateFlowStep = ref(0);
const validateDialogShow = ref(false);
const validatingShow = ref(false);
const gotoEdit = () => {
activeStep.value = validateFlowStep.value;
validateDialogShow.value = false;
};
const publish = (t) => {
validateErrMsg.value = [];
validateFlowStep.value = 0;
validateDialogShow.value = true;
validatingShow.value = true;
setTimeout(function () {
//1
checkStep1();
}, 500);
};
import { useRoute } from 'vue-router';
import { getFlowDetail } from '/@/api/flow/flow';
import { useUserInfo } from '/@/stores/userInfo';
import other from '/@/utils/other';
const route = useRoute();
onMounted(() => {
const query: LocationQuery = route.query;
const groupId = (query.groupId as LocationQueryValue) ?? '';
const flowId = (query.flowId as LocationQueryValue) ?? '';
const cp = (query.cp as LocationQueryValue) ?? '';
if (groupId) {
paramGroupId.value = groupId;
}
if (flowId) {
getFlowDetail(flowId).then((res) => {
var { data } = res;
store.step1.adminList = JSON.parse(data.adminList);
store.step1.name = data.name;
store.step1.logo = data.logo;
if (!cp || !(parseInt(cp) === 1)) {
//复制
store.step1.flowId = flowId;
}
store.step1.remark = data.remark;
store.step1.groupId = data.groupId;
store.setStep2(JSON.parse(data.formItems));
step3NodeConfig = JSON.parse(data.process);
});
} else {
//新增
let userId = useUserInfo().userInfos.user.userId;
let name = useUserInfo().userInfos.user.username;
let avatar = useUserInfo().userInfos.user.avatar;
//清空 store 属性
store.clearStep1();
store.clearStep2();
store.step1.adminList = [
{
id: userId,
name: name,
avatar: avatar,
type: 'user',
},
];
}
});
let step3NodeConfig = reactive({});
var paramGroupId = ref();
const checkStep1 = () => {
step1Ref.value.validate(function (valid, arr) {
if (valid) {
validateFlowStep.value = 1;
setTimeout(function () {
checkStep2();
}, 500);
} else {
validatingShow.value = false;
//错误信息
validateErrMsg.value = arr;
}
});
};
const checkStep2 = () => {
step2Ref.value.validate(function (valid, arr) {
if (valid) {
setTimeout(function () {
validateFlowStep.value = 2;
checkStep3();
});
} else {
validatingShow.value = false;
//错误信息
validateErrMsg.value = arr;
}
});
};
const checkStep3 = () => {
setTimeout(function () {
step3Ref.value.validate(function (valid, arr) {
if (valid) {
validateFlowStep.value = 3;
} else {
validatingShow.value = false;
//错误信息
validateErrMsg.value = arr;
}
});
});
};
const router = useRouter();
const submitFlow = () => {
step3Ref.value.getProcessData().then((res) => {
let step1 = store.step1;
let step2 = store.step2;
let flow = other.deepClone(step1);
flow.formItems = JSON.stringify(step2);
flow.process = JSON.stringify(res);
flow.adminList = JSON.stringify(step1.adminList);
addFlow(flow).then((res) => {
validateDialogShow.value = false;
store.$reset();
router.push('/flow/list/index');
});
});
};
</script>
<style scoped lang="scss">
.f2-width {
--f2-width: 600px;
}
.titlebar {
padding-top: 10px;
padding-bottom: 10px;
height: 60px;
flex-direction: row;
margin-bottom: 40px;
text-align: center;
}
.f1 {
width: calc(100% / 2 - var(--f2-width) / 2);
}
.f2 {
width: var(--f2-width);
text-align: center;
}
.f3 {
width: calc(100% / 2 - var(--f2-width) / 2);
text-align: right;
line-height: 46px;
height: 46px;
padding-right: 20px;
}
.center_t {
cursor: pointer;
padding: 10px 20px;
display: inline-block;
}
.center_t span:first-child {
margin-right: 6px;
font-size: 16px;
font-weight: 400;
text-align: center;
line-height: 22px;
border: 1px solid;
border-radius: 50%;
width: 24px;
height: 24px;
display: inline-block;
}
.center_t span:first-child[activeStep='true'] {
color: white;
background-color: var(--el-color-primary);
}
.center_t span:last-child {
font-weight: 500;
font-size: 18px;
}
.center_t[activeStep='true'] {
border-bottom: 2px solid var(--el-color-primary);
color: var(--el-color-primary);
}
</style>
+131
View File
@@ -0,0 +1,131 @@
<template>
<div>
<div class="container-div">
<el-card class="box-card" style="padding-right: 10%; padding-left: 10%">
<el-form ref="ruleForm" :model="form" :rules="rules" label-position="top" status-icon label-width="120px" @submit.prevent>
<el-form-item :label="$t('flow.logo')" prop="logo">
<upload-img v-model:imageUrl="form.logo" height="100px" width="100px">
<template #empty>
<el-icon>
<Avatar />
</el-icon>
<span>{{ $t('flow.logo') }}</span>
</template>
</upload-img>
</el-form-item>
<el-form-item :label="$t('flow.name')" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item :label="$t('flow.remark')" prop="remark">
<el-input v-model="form.remark" />
</el-form-item>
<el-form-item :label="$t('flow.group')" prop="groupId">
<el-select v-model="form.groupId" :placeholder="$t('flow.groupTips')">
<el-option v-for="item in groupList" :key="item.id" :label="item.groupName" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('flow.admin')" prop="adminList">
<select-show v-model:orgList="form.adminList" type="user" :multiple="false"></select-show>
</el-form-item>
</el-form>
</el-card>
</div>
</div>
</template>
<script lang="ts" setup>
import type {FormRules} from 'element-plus';
import selectShow from '/@/components/OrgSelector/index.vue';
import {queryGroupList} from '/@/api/flow/group';
import {useRoute} from 'vue-router';
import {useFlowStore} from '../workflow/stores/flow';
import {GroupVO} from '/@/api/flow/group/types';
const { proxy } = getCurrentInstance();
const validate = (f) => {
proxy.$refs.ruleForm.validate((valid, fields) => {
var arr = [];
if (!valid) {
for (var err in fields) {
arr.push(fields[err][0].message);
}
}
f(valid, arr);
});
};
// 暴露方法和属性给父组件
defineExpose({ validate });
const rules = reactive<FormRules>({
name: [
{ required: true, message: '请填写名称', trigger: 'blur' },
{ min: 2, max: 10, message: '2-10个字符', trigger: 'blur' },
],
remark: [
{ required: false, message: '请填写描述', trigger: 'blur' },
{ min: 2, max: 20, message: '2-20个字符', trigger: 'blur' },
],
groupId: [
{
required: true,
message: '请选择分组',
trigger: 'change',
},
],
logo: [
{
required: true,
message: '请上传图标',
trigger: 'change',
},
],
adminList: [
{
required: true,
message: '请选择管理员',
trigger: 'change',
},
],
});
let props = defineProps({
groupId: {
type: Number,
default: undefined,
},
});
const route = useRoute();
const groupList = ref<GroupVO[]>([]);
onMounted(() => {
queryGroupList().then(({ data }) => {
groupList.value = data;
});
});
watch(
() => props.groupId,
(val) => {
if (!!val) {
form.value.groupId = parseInt(val);
}
}
);
const flowStore = useFlowStore();
const form = computed(() => {
return flowStore.step1;
});
</script>
<style scoped>
.container-div {
width: 800px;
height: 100vh; /* Set the container height to 100% of the viewport height */
margin-left: calc(50% - 400px);
text-align: center;
}
</style>
+17
View File
@@ -0,0 +1,17 @@
<template>
<div>
<flow-form-designer ref="flowFormDesignerRef" />
</div>
</template>
<script lang="ts" setup>
import FlowFormDesigner from '/@/views/flow/form/index.vue';
const flowFormDesignerRef = ref();
const validate = (f) => {
flowFormDesignerRef.value.validate(f);
};
defineExpose({ validate });
</script>
+136
View File
@@ -0,0 +1,136 @@
<template>
<div class="app-container">
<!-- 流程节点绘制 -->
<div class="fd-nav-content">
<el-scrollbar style="height: 600px">
<section class="dingflow-design">
<div class="zoom">
<div class="zoom-out" :class="nowVal === 50 && 'disabled'" @click="zoomSize(1)"></div>
<span>{{ nowVal }}%</span>
<div class="zoom-in" :class="nowVal === 300 && 'disabled'" @click="zoomSize(2)"></div>
</div>
<div class="box-scale" :style="`transform: scale(${nowVal / 100});`">
<nodeWrap v-model:nodeConfig="nodeConfig"/>
<div class="end-node">
<div class="end-node-circle"></div>
<div class="end-node-text">{{ $t('flow.end') }}</div>
</div>
</div>
</section>
</el-scrollbar>
</div>
<!-- 发起人 -->
<promoterDrawer/>
<!-- 审批人 -->
<approverDrawer/>
<!-- 抄送人 -->
<copyerDrawer/>
<!-- 条件分支 -->
<conditionDrawer/>
</div>
</template>
<script setup>
import nodeWrap from '../workflow/components/nodeWrap.vue';
import promoterDrawer from '../workflow/components/drawer/promoterDrawer.vue';
import approverDrawer from '../workflow/components/drawer/approverDrawer.vue';
import copyerDrawer from '../workflow/components/drawer/copyerDrawer.vue';
import conditionDrawer from '../workflow/components/drawer/conditionDrawer.vue';
import {useI18n} from 'vue-i18n';
import {useFlowStore} from "../workflow/stores/flow";
let store = useFlowStore();
const {t} = useI18n();
let tipList = ref([]);
let nowVal = ref(100);
let nodeConfig = ref({
nodeName: t('flow.initiator'),
type: 0,
id: 'root',
formPerms: {},
eventConfig: '',
nodeUserList: [],
childNode: {},
});
let props = defineProps({
nodeConfigObj: {
type: Object,
},
});
watch(
() => props.nodeConfigObj,
(val) => {
nodeConfig.value = val;
}
);
const reErr = ({childNode}) => {
if (childNode) {
let {type, error, nodeName, conditionNodes} = childNode;
if (type == 1 || type == 2) {
if (error) {
tipList.value.push(nodeName + ' 未设置人员');
}
reErr(childNode);
} else if (type == 3) {
reErr(childNode);
} else if (type == 4) {
reErr(childNode);
for (var i = 0; i < conditionNodes.length; i++) {
if (conditionNodes[i].error) {
tipList.value.push('请设置' + conditionNodes[i].nodeName + '的条件');
}
reErr(conditionNodes[i]);
}
}
} else {
childNode = null;
}
};
watch(() => nodeConfig.value, (v) => {
store.setStep3(v)
}, {deep: true})
const getProcessData = async () => {
return nodeConfig.value;
};
const zoomSize = (type) => {
if (type == 1) {
if (nowVal.value == 50) {
return;
}
nowVal.value -= 10;
} else {
if (nowVal.value == 300) {
return;
}
nowVal.value += 10;
}
};
const validate = (f) => {
tipList.value = [];
if (nodeConfig.value.childNode == undefined || nodeConfig.value.childNode.id === undefined) {
tipList.value = ['请完善流程节点'];
}
reErr(nodeConfig.value);
if (tipList.value.length != 0) {
f(false, tipList.value);
return;
}
f(true);
};
defineExpose({validate, getProcessData});
</script>
<style scoped lang="scss">
@import '../workflow/css/workflow.css';
.error-modal-list {
width: 455px;
}
</style>