123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- <script setup name="BasicInfo">
- import { storeToRefs } from 'pinia'
- import useFlowStore from '@/store/modules/flow'
- import { ref, nextTick, onMounted, computed, watch, onBeforeUnmount } from 'vue'
- import UseSelect from '@/components/scWorkflow/select'
- import flowDefinition from '@/api/flow/definition'
- import process from '@/api/flow/process'
- // 缓存 start
- import { EVENT_ENUM, EVENT_BUS, cacheTriggerFunc } from '@/utils/cacheHelper'
- const flowStore = useFlowStore()
- const { flowName, flowProcessId } = storeToRefs(flowStore)
- const cacheLoading = ref(false)
- const cacheLoadingNum = ref(600)
- const cacheLoadingFr = 1000
- const cacheLoadingIndex = ref(null)
- const cacheIndex = ref(null) // 缓存索引
- const cacheUpdateFr = 3000 // 缓存更新频率
- // 缓存 end
- const visiblePopover = ref(false)
- const selectVisible = ref(false)
- const useSelectRef = ref(null)
- const nodeRoleList = ref([])
- const nodeRoleManageList = ref([])
- const currentNode = ref('nodeRoleList')
- const processId = ref('') // 流程定义ID
- const formRef = ref()
- const options = ref([])
- const flowInfo = ref({
- processKey: '', // 流程唯一标识 key
- processName: '', // 流程定义名称
- displayName: '', // 流程显示名称
- processIcon: 'https://lf3-ea.bytetos.com/obj/goofy/ee/approval/approval-admin/image/iconLib/v5/cart.svg', // 流程图标
- categoryId: '', // 流程组分类ID
- useScope: 0, // 使用范围 0,全员 1,指定人员(业务关联) 2,均不可提交
- processActorList: [
- {
- actorId: 0, // 参与者ID
- actorName: '', // 参与者
- actorType: 0 // 参与者类型 0,用户 1,部门 2,用户组
- }
- ], // 流程参与者,当使用范围为指定人员时候设置
- processPermissionList: [
- {
- userId: 0, // 用户ID
- userName: '', // 用户名
- operateApproval: 0, // 允许编辑/停用/删除审批 0,否 1,
- operateOwner: 0, // 允许添加/移除审批负责人 0,否 1,是
- operateData: 0 // 允许审批数据查询与操作 0,否 1,是
- }
- ] // 流程定义权限
- })
- const rules = {
- processIcon: [
- {
- required: true,
- message: '请选择图标'
- }
- ],
- processKey: [
- {
- required: true,
- message: '请输入唯一标识'
- }
- ],
- processName: [
- {
- required: true,
- message: '请输入名称'
- }
- ],
- categoryId: [
- {
- required: true,
- message: '请选择分组'
- }
- ]
- }
- const validate = () => {
- return new Promise((resolve, reject) => {
- formRef.value.validate((valid, errObj) => {
- if (valid) {
- console.error('valid 成功')
- // cb?.(form.value)
- resolve(form.value)
- // return form.value
- return
- }
- return reject(['基本信息', errObj])
- })
- })
- }
- const openApprovePerson = () => {
- selectVisible.value = !selectVisible.value
- }
- const selectHandle = (type, data, name) => {
- currentNode.value = name
- openApprovePerson()
- nextTick(() => {
- useSelectRef.value.open(type, data)
- })
- }
- const selectContentEv = item => {
- if (currentNode.value === 'nodeRoleList') {
- nodeRoleList.value = item
- const flag = !item.length
- flowInfo.value.useScope = flag ? 0 : 1
- let processActorList = []
- for (let i in item) {
- processActorList.push({
- actorId: item[i].id,
- actorName: item[i].name,
- actorType: 0
- })
- }
- flowInfo.value.processActorList = processActorList
- } else {
- let processPermissionList = []
- for (let i in item) {
- processPermissionList.push({
- userId: item[i].id,
- userName: item[i].name,
- operateApproval: 0,
- operateOwner: 0,
- operateData: 0
- })
- }
- nodeRoleManageList.value = item
- flowInfo.value.processPermissionList = processPermissionList
- }
- }
- const delRole = (index, itemName) => {
- if (itemName === 'nodeRoleList') {
- nodeRoleList.value.splice(index, 1)
- } else {
- nodeRoleManageList.value.splice(index, 1)
- }
- }
- const getGroupList = async () => {
- const data = await flowDefinition.flowDefinitionListCategoryApi({})
- options.value = data || []
- }
- // 更新申请信息缓存
- const updateRemoteCache = async () => {
- try {
- const params = processId.value ? { ...flowInfo.value, processId: processId.value } : flowInfo.value
- const res = await process.progressCreateApi(params)
- flowProcessId.value = processId.value = res
- console.log('updateRemoteCache 实际调用接口, params = ', params, new Date().getTime())
- } catch (e) {
- console.log(e)
- }
- }
- const handleRemoteCacheRefresh = () => {
- cacheIndex.value && clearTimeout(cacheIndex.value)
- cacheIndex.value = setTimeout(() => {
- updateRemoteCache()
- }, cacheUpdateFr)
- }
- // 初始化缓存倒计时
- const handleCacheLoading = () => {
- cacheLoading.value = true
- cacheLoadingNum.value = 5
- cacheLoadingIndex.value && clearInterval(cacheLoadingIndex.value)
- cacheLoadingIndex.value = setInterval(() => {
- cacheLoadingNum.value = cacheLoadingNum.value - 1
- if (cacheLoadingNum.value <= 0) {
- cacheLoading.value = false
- cacheLoadingIndex.value && clearInterval(cacheLoadingIndex.value)
- bindCacheEvt()
- }
- }, cacheLoadingFr)
- }
- const closeCacheLoading = () => {
- console.log('组件销毁时: 关闭定时器---------')
- cacheLoadingIndex.value && clearInterval(cacheLoadingIndex.value)
- }
- const bindCacheEvt = () => {
- EVENT_BUS.off(EVENT_ENUM.UPDATE_CACHE)
- EVENT_BUS.on(EVENT_ENUM.UPDATE_CACHE, res => {
- console.log('dev.2 EVENT_ENUM.UPDATE_CACHE', res)
- handleRemoteCacheRefresh()
- })
- }
- // ----- 缓存相关 start ------
- const flowBaseInfoWatcher = computed(() => {
- const { processKey, processName, processIcon, categoryId, remark, useScope, processActorList, processPermissionList } = flowInfo.value
- // 只关注参数相关的数据变更
- const _s = {
- processKey, // 流程显示名称
- processName, // 流程定义名称
- processIcon, // 流程图标
- categoryId, // 流程组分类ID
- remark, // 备注说明
- useScope, // 使用范围 0,全员 1,指定人员(业务关联) 2,均不可提交
- processActorList, // 流程参与者,当使用范围为指定人员时候设置
- processPermissionList // 流程定义权限
- }
- console.log('第一步:监听的对象属性 ------', _s)
- return _s
- })
- watch(
- flowBaseInfoWatcher,
- (newVal, oldVal) => {
- console.log('第二步:执行同步emit方法 ------', newVal, oldVal)
- cacheTriggerFunc()
- },
- { deep: true }
- )
- // 流程名称变化
- watch(
- () => flowInfo.value.processName,
- newVal => {
- flowName.value = newVal
- }
- )
- // ----- 缓存相关 end ------
- onMounted(() => {
- getGroupList()
- handleCacheLoading()
- })
- onBeforeUnmount(() => {
- closeCacheLoading()
- })
- defineExpose({
- formRef,
- validate
- })
- </script>
- <template>
- <div class="base-info">
- <div v-if="cacheLoading" style="font-size: 18px; position: absolute; left: 10px; top: 20px; z-index: 9999; color: red">
- {{ cacheLoadingNum }}秒之后开启自动缓存...
- </div>
- <div class="base-info-panel">
- <el-form ref="formRef" :model="flowInfo" :rules="rules" label-position="top">
- <el-form-item label="图标" prop="processIcon">
- <el-space>
- <div class="icon-shower">
- <img :src="flowInfo.processIcon" alt="" />
- </div>
- </el-space>
- <el-popover placement="right-end" :width="450" trigger="focus" class="base-popover" :visible="visiblePopover">
- <div class="icon-selector__dialog__content">
- <div class="icon-selector-list">
- <div v-for="item in 27" :key="item" class="icon-selector-item" @click="visiblePopover = !visiblePopover">
- <img src="https://lf3-ea.bytetos.com/obj/goofy/ee/approval/approval-admin/image/iconLib/v5/cart.svg" alt="" />
- </div>
- </div>
- </div>
- <template #reference>
- <el-link :underline="false" @click="visiblePopover = !visiblePopover">修改</el-link>
- </template>
- </el-popover>
- </el-form-item>
- <el-form-item label="唯一标识 key" prop="processKey">
- <el-input v-model="flowInfo.processKey" clearable></el-input>
- </el-form-item>
- <el-form-item label="名称" prop="processName">
- <el-input v-model="flowInfo.processName" clearable></el-input>
- </el-form-item>
- <el-form-item label="说明" prop="remark">
- <el-input v-model="flowInfo.remark" type="textarea" clearable></el-input>
- </el-form-item>
- <el-form-item label="分组" prop="categoryId">
- <el-select v-model="flowInfo.categoryId">
- <el-option v-for="item in options" :key="item.categoryId" :label="item.categoryName" :value="item.categoryId" />
- </el-select>
- </el-form-item>
- <el-form-item label="谁可以发起该流程(不选择,默认全员)" prop="谁可以发起该流程">
- <div class="add-btn" @click="selectHandle(1, nodeRoleList, 'nodeRoleList')">
- <el-icon :size="18"><Plus /></el-icon>
- </div>
- <div class="tags-list" style="margin-top: 15px; width: 100%">
- <el-tag
- v-for="(role, index) in nodeRoleList"
- :key="role.id"
- type="info"
- closable
- style="margin-right: 8px"
- @close="delRole(index, 'nodeRoleList')"
- >{{ role.name }}</el-tag
- >
- </div>
- </el-form-item>
- <el-form-item label="管理员" prop="管理员">
- <div class="add-btn" @click="selectHandle(1, nodeRoleManageList, 'nodeRoleManageList')">
- <el-icon :size="18"><Plus /></el-icon>
- </div>
- <div class="tags-list" style="margin-top: 15px; width: 100%">
- <el-tag
- v-for="(role, index) in nodeRoleManageList"
- :key="role.id"
- type="info"
- closable
- style="margin-right: 8px"
- @close="delRole(index, 'nodeRoleManageList')"
- >{{ role.name }}</el-tag
- >
- </div>
- </el-form-item>
- </el-form>
- </div>
- <use-select v-if="selectVisible" ref="useSelectRef" @closed="selectVisible = false" @content-ev="selectContentEv"></use-select>
- </div>
- </template>
- <style scoped lang="scss">
- .basic-info-wrap {
- //background: var(--el-color-danger);
- }
- .flow-name {
- padding-right: 4px;
- color: var(--el-color-danger);
- }
- .base-info {
- margin: 0 auto;
- padding: 24px 0;
- height: 100%;
- text-align: center;
- overflow-y: auto;
- background-color: #eff0f1;
- position: relative;
- &-panel {
- display: inline-block;
- width: 1128px;
- padding: 24px 288px;
- background-color: #fff;
- text-align: left;
- }
- }
- .icon-selector__dialog__content {
- height: 384px;
- overflow-x: visible;
- overflow-y: scroll;
- scrollbar-width: none;
- -ms-overflow-style: none;
- .icon-selector-list {
- display: grid;
- grid-template-columns: repeat(5, 64px);
- grid-template-rows: repeat(auto, 64px);
- grid-gap: 16px;
- justify-content: flex-start;
- align-items: flex-start;
- flex-wrap: wrap;
- .icon-selector-item {
- width: 64px;
- height: 64px;
- padding: 8px;
- border: 1px solid #d0d3d6;
- box-sizing: border-box;
- border-radius: 6px;
- cursor: pointer;
- &:hover {
- border-color: #3370ff;
- }
- img {
- width: 100%;
- height: 100%;
- border-radius: 4px;
- overflow: hidden;
- }
- }
- }
- }
- .icon-shower {
- width: 48px;
- height: 48px;
- border-radius: 50%;
- overflow: hidden;
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- }
- .add-btn {
- width: 48px;
- height: 48px;
- font-family: PingFang SC, Microsoft YaHei;
- font-size: 14px;
- line-height: 20px;
- background-color: #eff0f1;
- border-radius: 50%;
- cursor: pointer;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- </style>
|