Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into pay_extension
Conflicts: sql/ruoyi-vue-pro.sql yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysDictTypeConstants.java yudao-admin-server/src/main/resources/application-local.yaml yudao-admin-server/src/main/resources/application.yaml yudao-admin-server/src/test/resources/sql/clean.sql yudao-admin-server/src/test/resources/sql/create_tables.sql yudao-admin-ui/src/utils/dict.js
This commit is contained in:
173
yudao-admin-ui/src/views/bpm/definition/index.vue
Normal file
173
yudao-admin-ui/src/views/bpm/definition/index.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="定义编号" align="center" prop="id" width="400" />
|
||||
<el-table-column label="定义名称" align="center" prop="name" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="handleBpmnDetail(scope.row)">
|
||||
<span>{{ scope.row.name }}</span>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="定义分类" align="center" prop="category" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDictDataLabel(DICT_TYPE.BPM_MODEL_CATEGORY, scope.row.category) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="表单信息" align="center" prop="formType" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="scope.row.formId" type="text" @click="handleFormDetail(scope.row)">
|
||||
<span>{{ scope.row.formName }}</span>
|
||||
</el-button>
|
||||
<el-button v-else-if="scope.row.formCustomCreatePath" type="text" @click="handleFormDetail(scope.row)">
|
||||
<span>{{ scope.row.formCustomCreatePath }}</span>
|
||||
</el-button>
|
||||
<label v-else>暂无表单</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="流程版本" align="center" prop="processDefinition.version" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="medium" v-if="scope.row">v{{ scope.row.version }}</el-tag>
|
||||
<el-tag size="medium" type="warning" v-else>未部署</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="version" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag>
|
||||
<el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="部署时间" align="center" prop="deploymentTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.deploymentTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="定义描述" align="center" prop="description" width="300" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" width="150" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)"
|
||||
v-hasPermi="['bpm:task-assign-rule:update']">分配规则</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 流程表单配置详情 -->
|
||||
<el-dialog title="表单详情" :visible.sync="detailOpen" width="50%" append-to-body>
|
||||
<parser :key="new Date().getTime()" :form-conf="detailForm" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 流程模型图的预览 -->
|
||||
<el-dialog title="流程图" :visible.sync="showBpmnOpen" width="80%" append-to-body>
|
||||
<my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- ========== 流程任务分配规则 ========== -->
|
||||
<taskAssignRuleDialog ref="taskAssignRuleDialog" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getProcessDefinitionBpmnXML, getProcessDefinitionPage} from "@/api/bpm/definition";
|
||||
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
|
||||
import {getForm} from "@/api/bpm/form";
|
||||
import {decodeFields} from "@/utils/formGenerator";
|
||||
import Parser from '@/components/parser/Parser'
|
||||
import taskAssignRuleDialog from "../taskAssignRule/taskAssignRuleDialog";
|
||||
|
||||
export default {
|
||||
name: "processDefinition",
|
||||
components: {
|
||||
Parser,
|
||||
taskAssignRuleDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 表格数据
|
||||
list: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
|
||||
// 流程表单详情
|
||||
detailOpen: false,
|
||||
detailForm: {
|
||||
fields: []
|
||||
},
|
||||
|
||||
// BPMN 数据
|
||||
showBpmnOpen: false,
|
||||
bpmnXML: null,
|
||||
bpmnControlForm: {
|
||||
prefix: "activiti"
|
||||
},
|
||||
|
||||
// 数据字典
|
||||
categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY),
|
||||
};
|
||||
},
|
||||
created() {
|
||||
const key = this.$route.query && this.$route.query.key
|
||||
if (key) {
|
||||
this.queryParams['key'] = key
|
||||
}
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询流程定义列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
getProcessDefinitionPage(this.queryParams).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
/** 流程表单的详情按钮操作 */
|
||||
handleFormDetail(row) {
|
||||
// 流程表单
|
||||
if (row.formId) {
|
||||
// 设置值
|
||||
this.detailForm = {
|
||||
...JSON.parse(row.formConf),
|
||||
fields: decodeFields(row.formFields)
|
||||
}
|
||||
// 弹窗打开
|
||||
this.detailOpen = true
|
||||
// 业务表单
|
||||
} else if (row.formCustomCreatePath) {
|
||||
this.$router.push({ path: row.formCustomCreatePath});
|
||||
}
|
||||
},
|
||||
/** 流程图的详情按钮操作 */
|
||||
handleBpmnDetail(row) {
|
||||
getProcessDefinitionBpmnXML(row.id).then(response => {
|
||||
this.bpmnXML = response.data
|
||||
// 弹窗打开
|
||||
this.showBpmnOpen = true
|
||||
})
|
||||
},
|
||||
/** 处理任务分配规则列表的按钮操作 */
|
||||
handleAssignRule(row) {
|
||||
this.$refs['taskAssignRuleDialog'].initProcessDefinition(row.id);
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.my-process-designer {
|
||||
height: calc(100vh - 200px);
|
||||
}
|
||||
</style>
|
||||
570
yudao-admin-ui/src/views/bpm/form/formEditor.vue
Normal file
570
yudao-admin-ui/src/views/bpm/form/formEditor.vue
Normal file
@@ -0,0 +1,570 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="left-board">
|
||||
<div class="logo-wrapper">
|
||||
<div class="logo">流程表单</div>
|
||||
</div>
|
||||
<el-scrollbar class="left-scrollbar">
|
||||
<!-- 左边:表单项 -->
|
||||
<div class="components-list">
|
||||
<div v-for="(item, listIndex) in leftComponents" :key="listIndex">
|
||||
<div class="components-title">
|
||||
<svg-icon icon-class="component" />
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<draggable
|
||||
class="components-draggable"
|
||||
:list="item.list"
|
||||
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
|
||||
:clone="cloneComponent"
|
||||
draggable=".components-item"
|
||||
:sort="false"
|
||||
@end="onEnd"
|
||||
>
|
||||
<div
|
||||
v-for="(element, index) in item.list"
|
||||
:key="index"
|
||||
class="components-item"
|
||||
@click="addComponent(element)"
|
||||
>
|
||||
<div class="components-body">
|
||||
<svg-icon :icon-class="element.__config__.tagIcon" />
|
||||
{{ element.__config__.label }}
|
||||
</div>
|
||||
</div>
|
||||
</draggable>
|
||||
</div>
|
||||
|
||||
<!-- 左边:动态表单 -->
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="表单名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入表单名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开启状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
|
||||
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input type="textarea" v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<div class="center-board">
|
||||
<div class="action-bar">
|
||||
<el-button icon="el-icon-check" type="text" @click="save">保存</el-button>
|
||||
<!-- <el-button icon="el-icon-video-play" type="text" @click="run">-->
|
||||
<!-- 运行-->
|
||||
<!-- </el-button>-->
|
||||
<el-button icon="el-icon-view" type="text" @click="showJson">
|
||||
查看json
|
||||
</el-button>
|
||||
<!-- <el-button icon="el-icon-download" type="text" @click="download">-->
|
||||
<!-- 导出vue文件-->
|
||||
<!-- </el-button>-->
|
||||
<!-- <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">-->
|
||||
<!-- 复制代码-->
|
||||
<!-- </el-button>-->
|
||||
<el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
|
||||
清空
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 中间,表单项 -->
|
||||
<el-scrollbar class="center-scrollbar">
|
||||
<el-row class="center-board-row" :gutter="formConf.gutter">
|
||||
<el-form
|
||||
:size="formConf.size"
|
||||
:label-position="formConf.labelPosition"
|
||||
:disabled="formConf.disabled"
|
||||
:label-width="formConf.labelWidth + 'px'"
|
||||
>
|
||||
<draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
|
||||
<draggable-item
|
||||
v-for="(item, index) in drawingList"
|
||||
:key="item.renderKey"
|
||||
:drawing-list="drawingList"
|
||||
:current-item="item"
|
||||
:index="index"
|
||||
:active-id="activeId"
|
||||
:form-conf="formConf"
|
||||
@activeItem="activeFormItem"
|
||||
@copyItem="drawingItemCopy"
|
||||
@deleteItem="drawingItemDelete"
|
||||
/>
|
||||
</draggable>
|
||||
<div v-show="!drawingList.length" class="empty-info">
|
||||
从左侧拖入或点选组件进行表单设计
|
||||
</div>
|
||||
</el-form>
|
||||
</el-row>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<!-- 右边:组件属性/表单属性 -->
|
||||
<right-panel
|
||||
:active-data="activeData"
|
||||
:form-conf="formConf"
|
||||
:show-field="!!drawingList.length"
|
||||
@tag-change="tagChange"
|
||||
@fetch-data="fetchData"
|
||||
/>
|
||||
|
||||
<!-- <form-drawer-->
|
||||
<!-- :visible.sync="drawerVisible"-->
|
||||
<!-- :form-data="formData"-->
|
||||
<!-- size="100%"-->
|
||||
<!-- :generate-conf="generateConf"-->
|
||||
<!-- />-->
|
||||
|
||||
<json-drawer
|
||||
size="60%"
|
||||
:visible.sync="jsonDrawerVisible"
|
||||
:json-str="JSON.stringify(formData)"
|
||||
@refresh="refreshJson"
|
||||
/>
|
||||
|
||||
<!-- <code-type-dialog-->
|
||||
<!-- :visible.sync="dialogVisible"-->
|
||||
<!-- title="选择生成类型"-->
|
||||
<!-- :show-file-name="showFileName"-->
|
||||
<!-- @confirm="generate"-->
|
||||
<!-- />-->
|
||||
|
||||
<!-- <input id="copyNode" type="hidden">-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import { debounce } from 'throttle-debounce'
|
||||
import { saveAs } from 'file-saver'
|
||||
import ClipboardJS from 'clipboard'
|
||||
import render from '@/components/render/render'
|
||||
import FormDrawer from '@/views/tool/build/FormDrawer'
|
||||
import JsonDrawer from '@/views/tool/build/JsonDrawer'
|
||||
import RightPanel from '@/views/tool/build/RightPanel'
|
||||
import {
|
||||
inputComponents, selectComponents, layoutComponents, formConf
|
||||
} from '@/components/generator/config'
|
||||
import {
|
||||
exportDefault, beautifierConf, isNumberStr, titleCase, deepClone, isObjectObject
|
||||
} from '@/utils/index'
|
||||
import {
|
||||
makeUpHtml, vueTemplate, vueScript, cssStyle
|
||||
} from '@/components/generator/html'
|
||||
import { makeUpJs } from '@/components/generator/js'
|
||||
import { makeUpCss } from '@/components/generator/css'
|
||||
import drawingDefalut from '@/components/generator/drawingDefalut'
|
||||
import logo from '@/assets/logo/logo.png'
|
||||
import CodeTypeDialog from '@/views/tool/build/CodeTypeDialog'
|
||||
import DraggableItem from '@/views/tool/build/DraggableItem'
|
||||
import {
|
||||
getDrawingList, saveDrawingList, getIdGlobal, saveIdGlobal, getFormConf
|
||||
} from '@/utils/db'
|
||||
import loadBeautifier from '@/utils/loadBeautifier'
|
||||
import {SysCommonStatusEnum} from "@/utils/constants";
|
||||
import {createForm, getForm, updateForm} from "@/api/bpm/form";
|
||||
import {decodeFields} from "@/utils/formGenerator";
|
||||
|
||||
let beautifier
|
||||
const emptyActiveData = { style: {}, autosize: {} }
|
||||
let oldActiveId
|
||||
let tempActiveData
|
||||
const drawingListInDB = getDrawingList()
|
||||
const formConfInDB = getFormConf()
|
||||
const idGlobal = getIdGlobal()
|
||||
|
||||
export default {
|
||||
components: {
|
||||
draggable,
|
||||
render,
|
||||
FormDrawer,
|
||||
JsonDrawer,
|
||||
RightPanel,
|
||||
CodeTypeDialog,
|
||||
DraggableItem
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
logo,
|
||||
idGlobal,
|
||||
formConf,
|
||||
inputComponents,
|
||||
selectComponents,
|
||||
layoutComponents,
|
||||
labelWidth: 100,
|
||||
// drawingList: drawingDefalut,
|
||||
drawingData: {}, // 生成后的表单数据
|
||||
activeId: drawingDefalut[0].__config__.formId,
|
||||
|
||||
drawingList: [], // 表单项的数组
|
||||
// activeId: undefined,
|
||||
// activeData: {},
|
||||
|
||||
drawerVisible: false,
|
||||
formData: {},
|
||||
dialogVisible: false,
|
||||
jsonDrawerVisible: false,
|
||||
generateConf: null,
|
||||
showFileName: false,
|
||||
activeData: drawingDefalut[0], // 右边编辑器激活的表单项
|
||||
saveDrawingListDebounce: debounce(340, saveDrawingList),
|
||||
saveIdGlobalDebounce: debounce(340, saveIdGlobal),
|
||||
leftComponents: [
|
||||
{
|
||||
title: '输入型组件',
|
||||
list: inputComponents
|
||||
},
|
||||
{
|
||||
title: '选择型组件',
|
||||
list: selectComponents
|
||||
},
|
||||
{
|
||||
title: '布局型组件',
|
||||
list: layoutComponents
|
||||
}
|
||||
],
|
||||
|
||||
// 表单参数
|
||||
form: {
|
||||
status: SysCommonStatusEnum.ENABLE,
|
||||
},
|
||||
// 表单校验
|
||||
rules: {
|
||||
name: [{ required: true, message: "表单名不能为空", trigger: "blur" }],
|
||||
status: [{ required: true, message: "开启状态不能为空", trigger: "blur" }],
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
// eslint-disable-next-line func-names
|
||||
'activeData.__config__.label': function (val, oldVal) {
|
||||
if (
|
||||
this.activeData.placeholder === undefined
|
||||
|| !this.activeData.__config__.tag
|
||||
|| oldActiveId !== this.activeId
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val
|
||||
},
|
||||
activeId: {
|
||||
handler(val) {
|
||||
oldActiveId = val
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
drawingList: {
|
||||
handler(val) {
|
||||
this.saveDrawingListDebounce(val)
|
||||
if (val.length === 0) this.idGlobal = 100
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
idGlobal: {
|
||||
handler(val) {
|
||||
this.saveIdGlobalDebounce(val)
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 【add by 芋道源码】不读缓存
|
||||
// if (Array.isArray(drawingListInDB) && drawingListInDB.length > 0) {
|
||||
// this.drawingList = drawingListInDB
|
||||
// } else {
|
||||
// this.drawingList = drawingDefalut
|
||||
// }
|
||||
// this.activeFormItem(this.drawingList[0])
|
||||
// if (formConfInDB) {
|
||||
// this.formConf = formConfInDB
|
||||
// }
|
||||
loadBeautifier(btf => {
|
||||
beautifier = btf
|
||||
})
|
||||
const clipboard = new ClipboardJS('#copyNode', {
|
||||
text: trigger => {
|
||||
const codeStr = this.generateCode()
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '代码已复制到剪切板,可粘贴。',
|
||||
type: 'success'
|
||||
})
|
||||
return codeStr
|
||||
}
|
||||
})
|
||||
clipboard.on('error', e => {
|
||||
this.$message.error('代码复制失败')
|
||||
})
|
||||
},
|
||||
created() {
|
||||
// 读取表单配置
|
||||
const formId = this.$route.query && this.$route.query.formId
|
||||
if (formId) {
|
||||
getForm(formId).then(response => {
|
||||
const data = response.data
|
||||
this.form = {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
status: data.status,
|
||||
remark: data.remark
|
||||
}
|
||||
this.formConf = JSON.parse(data.conf)
|
||||
this.drawingList = decodeFields(data.fields)
|
||||
// 设置激活的表单项
|
||||
this.activeData = this.drawingList[0]
|
||||
this.activeId = this.activeData.__config__.formId
|
||||
// 设置 idGlobal,避免重复
|
||||
this.idGlobal += this.drawingList.length
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setObjectValueReduce(obj, strKeys, data) {
|
||||
const arr = strKeys.split('.')
|
||||
arr.reduce((pre, item, i) => {
|
||||
if (arr.length === i + 1) {
|
||||
pre[item] = data
|
||||
} else if (!isObjectObject(pre[item])) {
|
||||
pre[item] = {}
|
||||
}
|
||||
return pre[item]
|
||||
}, obj)
|
||||
},
|
||||
setRespData(component, resp) {
|
||||
const { dataPath, renderKey, dataConsumer } = component.__config__
|
||||
if (!dataPath || !dataConsumer) return
|
||||
const respData = dataPath.split('.').reduce((pre, item) => pre[item], resp)
|
||||
|
||||
// 将请求回来的数据,赋值到指定属性。
|
||||
// 以el-tabel为例,根据Element文档,应该将数据赋值给el-tabel的data属性,所以dataConsumer的值应为'data';
|
||||
// 此时赋值代码可写成 component[dataConsumer] = respData;
|
||||
// 但为支持更深层级的赋值(如:dataConsumer的值为'options.data'),使用setObjectValueReduce
|
||||
this.setObjectValueReduce(component, dataConsumer, respData)
|
||||
const i = this.drawingList.findIndex(item => item.__config__.renderKey === renderKey)
|
||||
if (i > -1) this.$set(this.drawingList, i, component)
|
||||
},
|
||||
fetchData(component) {
|
||||
const { dataType, method, url } = component.__config__
|
||||
if (dataType === 'dynamic' && method && url) {
|
||||
this.setLoading(component, true)
|
||||
this.$axios({
|
||||
method,
|
||||
url
|
||||
}).then(resp => {
|
||||
this.setLoading(component, false)
|
||||
this.setRespData(component, resp.data)
|
||||
})
|
||||
}
|
||||
},
|
||||
setLoading(component, val) {
|
||||
const { directives } = component
|
||||
if (Array.isArray(directives)) {
|
||||
const t = directives.find(d => d.name === 'loading')
|
||||
if (t) t.value = val
|
||||
}
|
||||
},
|
||||
activeFormItem(currentItem) {
|
||||
this.activeData = currentItem
|
||||
this.activeId = currentItem.__config__.formId
|
||||
},
|
||||
onEnd(obj) {
|
||||
if (obj.from !== obj.to) {
|
||||
this.fetchData(tempActiveData)
|
||||
this.activeData = tempActiveData
|
||||
this.activeId = this.idGlobal
|
||||
}
|
||||
},
|
||||
addComponent(item) {
|
||||
const clone = this.cloneComponent(item)
|
||||
this.fetchData(clone)
|
||||
this.drawingList.push(clone)
|
||||
this.activeFormItem(clone)
|
||||
},
|
||||
cloneComponent(origin) {
|
||||
const clone = deepClone(origin)
|
||||
const config = clone.__config__
|
||||
config.span = this.formConf.span // 生成代码时,会根据span做精简判断
|
||||
this.createIdAndKey(clone)
|
||||
clone.placeholder !== undefined && (clone.placeholder += config.label)
|
||||
tempActiveData = clone
|
||||
return tempActiveData
|
||||
},
|
||||
createIdAndKey(item) {
|
||||
const config = item.__config__
|
||||
config.formId = ++this.idGlobal
|
||||
config.renderKey = `${config.formId}${+new Date()}` // 改变renderKey后可以实现强制更新组件
|
||||
if (config.layout === 'colFormItem') {
|
||||
item.__vModel__ = `field${this.idGlobal}`
|
||||
} else if (config.layout === 'rowFormItem') {
|
||||
config.componentName = `row${this.idGlobal}`
|
||||
!Array.isArray(config.children) && (config.children = [])
|
||||
delete config.label // rowFormItem无需配置label属性
|
||||
}
|
||||
if (Array.isArray(config.children)) {
|
||||
config.children = config.children.map(childItem => this.createIdAndKey(childItem))
|
||||
}
|
||||
return item
|
||||
},
|
||||
// 获得表单数据
|
||||
AssembleFormData() {
|
||||
this.formData = {
|
||||
fields: deepClone(this.drawingList),
|
||||
...this.formConf
|
||||
}
|
||||
},
|
||||
save() {
|
||||
// this.AssembleFormData()
|
||||
// console.log(this.formData)
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
const form = {
|
||||
conf: JSON.stringify(this.formConf), // 表单配置
|
||||
fields: this.encodeFields(), // 表单项的数组
|
||||
...this.form // 表单名等
|
||||
}
|
||||
// 修改的提交
|
||||
if (this.form.id != null) {
|
||||
updateForm(form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.close()
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 添加的提交
|
||||
createForm(form).then(response => {
|
||||
this.msgSuccess("新增成功");
|
||||
this.close()
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 关闭按钮 */
|
||||
close() {
|
||||
this.$store.dispatch("tagsView/delView", this.$route);
|
||||
this.$router.push({ path: "/bpm/manager/form", query: { t: Date.now()}})
|
||||
},
|
||||
encodeFields() {
|
||||
const fields = []
|
||||
this.drawingList.forEach(item => {
|
||||
fields.push(JSON.stringify(item))
|
||||
})
|
||||
return fields
|
||||
},
|
||||
generate(data) {
|
||||
const func = this[`exec${titleCase(this.operationType)}`]
|
||||
this.generateConf = data
|
||||
func && func(data)
|
||||
},
|
||||
execRun(data) {
|
||||
this.AssembleFormData()
|
||||
this.drawerVisible = true
|
||||
},
|
||||
execDownload(data) {
|
||||
const codeStr = this.generateCode()
|
||||
const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
|
||||
saveAs(blob, data.fileName)
|
||||
},
|
||||
execCopy(data) {
|
||||
document.getElementById('copyNode').click()
|
||||
},
|
||||
empty() {
|
||||
this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
|
||||
() => {
|
||||
this.drawingList = []
|
||||
this.idGlobal = 100
|
||||
}
|
||||
)
|
||||
},
|
||||
drawingItemCopy(item, list) {
|
||||
let clone = deepClone(item)
|
||||
clone = this.createIdAndKey(clone)
|
||||
list.push(clone)
|
||||
this.activeFormItem(clone)
|
||||
},
|
||||
drawingItemDelete(index, list) {
|
||||
list.splice(index, 1)
|
||||
this.$nextTick(() => {
|
||||
const len = this.drawingList.length
|
||||
if (len) {
|
||||
this.activeFormItem(this.drawingList[len - 1])
|
||||
}
|
||||
})
|
||||
},
|
||||
generateCode() {
|
||||
const { type } = this.generateConf
|
||||
this.AssembleFormData()
|
||||
const script = vueScript(makeUpJs(this.formData, type))
|
||||
const html = vueTemplate(makeUpHtml(this.formData, type))
|
||||
const css = cssStyle(makeUpCss(this.formData))
|
||||
return beautifier.html(html + script + css, beautifierConf.html)
|
||||
},
|
||||
showJson() {
|
||||
this.AssembleFormData()
|
||||
this.jsonDrawerVisible = true
|
||||
},
|
||||
download() {
|
||||
this.dialogVisible = true
|
||||
this.showFileName = true
|
||||
this.operationType = 'download'
|
||||
},
|
||||
run() {
|
||||
this.dialogVisible = true
|
||||
this.showFileName = false
|
||||
this.operationType = 'run'
|
||||
},
|
||||
copy() {
|
||||
this.dialogVisible = true
|
||||
this.showFileName = false
|
||||
this.operationType = 'copy'
|
||||
},
|
||||
tagChange(newTag) {
|
||||
newTag = this.cloneComponent(newTag)
|
||||
const config = newTag.__config__
|
||||
newTag.__vModel__ = this.activeData.__vModel__
|
||||
config.formId = this.activeId
|
||||
config.span = this.activeData.__config__.span
|
||||
this.activeData.__config__.tag = config.tag
|
||||
this.activeData.__config__.tagIcon = config.tagIcon
|
||||
this.activeData.__config__.document = config.document
|
||||
if (typeof this.activeData.__config__.defaultValue === typeof config.defaultValue) {
|
||||
config.defaultValue = this.activeData.__config__.defaultValue
|
||||
}
|
||||
Object.keys(newTag).forEach(key => {
|
||||
if (this.activeData[key] !== undefined) {
|
||||
newTag[key] = this.activeData[key]
|
||||
}
|
||||
})
|
||||
this.activeData = newTag
|
||||
this.updateDrawingList(newTag, this.drawingList)
|
||||
},
|
||||
updateDrawingList(newTag, list) {
|
||||
const index = list.findIndex(item => item.__config__.formId === this.activeId)
|
||||
if (index > -1) {
|
||||
list.splice(index, 1, newTag)
|
||||
} else {
|
||||
list.forEach(item => {
|
||||
if (Array.isArray(item.__config__.children)) this.updateDrawingList(newTag, item.__config__.children)
|
||||
})
|
||||
}
|
||||
},
|
||||
refreshJson(data) {
|
||||
this.drawingList = deepClone(data.fields)
|
||||
delete data.fields
|
||||
this.formConf = data
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
@import '@/styles/home';
|
||||
</style>
|
||||
166
yudao-admin-ui/src/views/bpm/form/index.vue
Normal file
166
yudao-admin-ui/src/views/bpm/form/index.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="表单名" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入表单名" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['bpm:form:create']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="id" />
|
||||
<el-table-column label="表单名" align="center" prop="name" />
|
||||
<el-table-column label="开启状态" align="center" prop="status">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleDetail(scope.row)"
|
||||
v-hasPermi="['bpm:form:query']">详情</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['bpm:form:update']">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['bpm:form:delete']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!--表单配置详情-->
|
||||
<el-dialog title="表单详情" :visible.sync="detailOpen" width="50%" append-to-body>
|
||||
<div class="test-form">
|
||||
<parser :key="new Date().getTime()" :form-conf="detailForm" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {deleteForm, getForm, getFormPage} from "@/api/bpm/form";
|
||||
import Parser from '@/components/parser/Parser'
|
||||
import {decodeFields} from "@/utils/formGenerator";
|
||||
|
||||
export default {
|
||||
name: "Form",
|
||||
components: {
|
||||
Parser
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 工作流的列表
|
||||
list: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
},
|
||||
// 表单详情
|
||||
detailOpen: false,
|
||||
detailForm: {
|
||||
fields: []
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
// 执行查询
|
||||
getFormPage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 详情按钮操作 */
|
||||
handleDetail(row) {
|
||||
getForm(row.id).then(response => {
|
||||
// 设置值
|
||||
const data = response.data
|
||||
this.detailForm = {
|
||||
...JSON.parse(data.conf),
|
||||
fields: decodeFields(data.fields)
|
||||
}
|
||||
// 弹窗打开
|
||||
this.detailOpen = true
|
||||
})
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.$router.push({
|
||||
path:"/bpm/manager/form/edit"
|
||||
});
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.$router.push({
|
||||
path:"/bpm/manager/form/edit",
|
||||
query:{
|
||||
formId: row.id
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const id = row.id;
|
||||
this.$confirm('是否确认删除工作流的编号为"' + id + '"的数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return deleteForm(id);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("删除成功");
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
254
yudao-admin-ui/src/views/bpm/group/index.vue
Normal file
254
yudao-admin-ui/src/views/bpm/group/index.vue
Normal file
@@ -0,0 +1,254 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="组名" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入组名" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
|
||||
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['bpm:user-group:create']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="id" />
|
||||
<el-table-column label="组名" align="center" prop="name" />
|
||||
<el-table-column label="描述" align="center" prop="description" />
|
||||
<el-table-column label="成员" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span v-for="userId in scope.row.memberUserIds">
|
||||
{{ getUserNickname(userId) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['bpm:user-group:update']">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['bpm:user-group:delete']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="组名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入组名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" prop="description">
|
||||
<el-input v-model="form.description" placeholder="请输入描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="成员" prop="memberUserIds">
|
||||
<el-select v-model="form.memberUserIds" multiple placeholder="请选择成员">
|
||||
<el-option v-for="user in users" :key="parseInt(user.id)" :label="user.nickname" :value="parseInt(user.id)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
|
||||
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createUserGroup, updateUserGroup, deleteUserGroup, getUserGroup, getUserGroupPage } from "@/api/bpm/userGroup";
|
||||
import {SysCommonStatusEnum} from "@/utils/constants";
|
||||
import {listSimpleUsers} from "@/api/system/user";
|
||||
|
||||
export default {
|
||||
name: "UserGroup",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 用户组列表
|
||||
list: [],
|
||||
// 用户列表
|
||||
users: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
dateRangeCreateTime: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
status: null,
|
||||
tenantId: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
name: [{ required: true, message: "组名不能为空", trigger: "blur" }],
|
||||
description: [{ required: true, message: "描述不能为空", trigger: "blur" }],
|
||||
memberUserIds: [{ required: true, message: "成员不能为空", trigger: "change" }],
|
||||
status: [{ required: true, message: "状态不能为空", trigger: "blur" }],
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
// 获得用户列表
|
||||
listSimpleUsers().then(response => {
|
||||
this.users = response.data;
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
||||
// 执行查询
|
||||
getUserGroupPage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
description: undefined,
|
||||
memberUserIds: [],
|
||||
status: SysCommonStatusEnum.ENABLE,
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeCreateTime = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加用户组";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id;
|
||||
getUserGroup(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改用户组";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 修改的提交
|
||||
if (this.form.id != null) {
|
||||
updateUserGroup(this.form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 添加的提交
|
||||
createUserGroup(this.form).then(response => {
|
||||
this.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const id = row.id;
|
||||
this.$confirm('是否确认删除用户组编号为"' + id + '"的数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return deleteUserGroup(id);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("删除成功");
|
||||
})
|
||||
},
|
||||
getUserNickname(userId) {
|
||||
for (const user of this.users) {
|
||||
if (user.id === userId) {
|
||||
return user.nickname;
|
||||
}
|
||||
}
|
||||
return '未知(' + userId + ')';
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
556
yudao-admin-ui/src/views/bpm/model/index.vue
Normal file
556
yudao-admin-ui/src/views/bpm/model/index.vue
Normal file
@@ -0,0 +1,556 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="流程标识" prop="key">
|
||||
<el-input v-model="queryParams.key" placeholder="请输入流程标识" clearable style="width: 240px;" size="small"
|
||||
@keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程名称" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入流程名称" clearable style="width: 240px;" size="small"
|
||||
@keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程分类" prop="category">
|
||||
<el-select v-model="queryParams.category" placeholder="流程分类" clearable size="small" style="width: 240px">
|
||||
<el-option v-for="dict in categoryDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['bpm:model:create']">新建流程</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" icon="el-icon-upload2" size="mini" @click="handleImport"
|
||||
v-hasPermi="['bpm:model:import']">导入流程</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="流程标识" align="center" prop="key" />
|
||||
<el-table-column label="流程名称" align="center" prop="name" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="handleBpmnDetail(scope.row)">
|
||||
<span>{{ scope.row.name }}</span>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="流程分类" align="center" prop="category" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDictDataLabel(DICT_TYPE.BPM_MODEL_CATEGORY, scope.row.category) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="表单信息" align="center" prop="formType" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="scope.row.formId" type="text" @click="handleFormDetail(scope.row)">
|
||||
<span>{{ scope.row.formName }}</span>
|
||||
</el-button>
|
||||
<el-button v-else-if="scope.row.formCustomCreatePath" type="text" @click="handleFormDetail(scope.row)">
|
||||
<span>{{ scope.row.formCustomCreatePath }}</span>
|
||||
</el-button>
|
||||
<label v-else>暂无表单</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最新部署的流程定义" align="center">
|
||||
<el-table-column label="流程版本" align="center" prop="processDefinition.version" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="medium" v-if="scope.row.processDefinition">v{{ scope.row.processDefinition.version }}</el-tag>
|
||||
<el-tag size="medium" type="warning" v-else>未部署</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="激活状态" align="center" prop="processDefinition.version" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-switch v-if="scope.row.processDefinition" v-model="scope.row.processDefinition.suspensionState"
|
||||
:active-value="1" :inactive-value="2" @change="handleChangeState(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="部署时间" align="center" prop="deploymentTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.processDefinition">{{ parseTime(scope.row.processDefinition.deploymentTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="450" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['bpm:model:update']">修改流程</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-setting" @click="handleDesign(scope.row)"
|
||||
v-hasPermi="['bpm:model:update']">设计流程</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)"
|
||||
v-hasPermi="['bpm:task-assign-rule:query']">分配规则</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-thumb" @click="handleDeploy(scope.row)"
|
||||
v-hasPermi="['bpm:model:deploy']">发布流程</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-ice-cream-round" @click="handleDefinitionList(scope.row)"
|
||||
v-hasPermi="['bpm:process-definition:query']">流程定义</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['bpm:model:delete']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 流程表单配置详情 -->
|
||||
<el-dialog title="表单详情" :visible.sync="detailOpen" width="50%" append-to-body>
|
||||
<parser :key="new Date().getTime()" :form-conf="detailForm" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 流程模型图的预览 -->
|
||||
<el-dialog title="流程图" :visible.sync="showBpmnOpen" width="80%" append-to-body>
|
||||
<my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="110px">
|
||||
<el-form-item label="流程标识" prop="key">
|
||||
<el-input v-model="form.key" placeholder="请输入流标标识" style="width: 330px;" :disabled="form.id" />
|
||||
<el-tooltip v-if="!form.id" class="item" effect="light" content="新建后,流程标识不可修改!" placement="top">
|
||||
<i style="padding-left: 5px;" class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
<el-tooltip v-else class="item" effect="light" content="流程标识不可修改!" placement="top">
|
||||
<i style="padding-left: 5px;" class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入流程名称" :disabled="form.id" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.id" label="流程分类" prop="category">
|
||||
<el-select v-model="form.category" placeholder="请选择流程分类" clearable style="width: 100%">
|
||||
<el-option v-for="dict in categoryDictDatas" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程描述" prop="description">
|
||||
<el-input type="textarea" v-model="form.description" clearable />
|
||||
</el-form-item>
|
||||
<div v-if="form.id">
|
||||
<el-form-item label="表单类型" prop="formType">
|
||||
<el-radio-group v-model="form.formType">
|
||||
<el-radio v-for="dict in modelFormTypeDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
|
||||
{{dict.label}}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.formType === 10" label="流程表单" prop="formId">
|
||||
<el-select v-model="form.formId" clearable style="width: 100%">
|
||||
<el-option v-for="form in forms" :key="form.id" :label="form.name" :value="form.id"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.formType === 20" label="表单提交路由" prop="formCustomCreatePath" >
|
||||
<el-input v-model="form.formCustomCreatePath" placeholder="请输入表单提交路由" style="width: 330px;" />
|
||||
<el-tooltip class="item" effect="light" content="自定义表单的提交路径,使用 Vue 的路由地址,例如说:bpm/oa/leave/create" placement="top">
|
||||
<i style="padding-left: 5px;" class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.formType === 20" label="表单查看路由" prop="formCustomViewPath">
|
||||
<el-input v-model="form.formCustomViewPath" placeholder="请输入表单查看路由" style="width: 330px;" />
|
||||
<el-tooltip class="item" effect="light" content="自定义表单的查看路径,使用 Vue 的路由地址,例如说:bpm/oa/leave/view" placement="top">
|
||||
<i style="padding-left: 5px;" class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 用户导入对话框 -->
|
||||
<el-dialog title="导入流程" :visible.sync="upload.open" width="400px" append-to-body>
|
||||
<el-upload ref="upload" :limit="1" accept=".bpmn, .xml" :headers="upload.headers" :action="upload.url"
|
||||
:disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess"
|
||||
:auto-upload="false" name="bpmnFile" :data="upload.form" drag>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或
|
||||
<em>点击上传</em>
|
||||
</div>
|
||||
<div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“bpm”或“xml”格式文件!</div>
|
||||
<div class="el-upload__tip" slot="tip">
|
||||
<el-form ref="uploadForm" size="mini" label-width="90px" :model="upload.form" :rules="upload.rules" @submit.native.prevent>
|
||||
<el-form-item label="流程标识" prop="key">
|
||||
<el-input v-model="upload.form.key" placeholder="请输入流标标识" style="width: 250px;" />
|
||||
<el-tooltip class="item" effect="light" content="新建后,流程标识不可修改!" placement="top">
|
||||
<i style="padding-left: 5px;" class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程名称" prop="name">
|
||||
<el-input v-model="upload.form.name" placeholder="请输入流程名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="流程描述" prop="description">
|
||||
<el-input type="textarea" v-model="upload.form.description" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitFileForm">确 定</el-button>
|
||||
<el-button @click="uploadClose">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- ========== 流程任务分配规则 ========== -->
|
||||
<taskAssignRuleDialog ref="taskAssignRuleDialog" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
deleteModel,
|
||||
deployModel,
|
||||
getModelPage,
|
||||
getModel,
|
||||
updateModelState,
|
||||
createModel,
|
||||
updateModel
|
||||
} from "@/api/bpm/model";
|
||||
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
|
||||
import {getForm, getSimpleForms} from "@/api/bpm/form";
|
||||
import {decodeFields} from "@/utils/formGenerator";
|
||||
import Parser from '@/components/parser/Parser'
|
||||
import {getBaseHeader} from "@/utils/request";
|
||||
import taskAssignRuleDialog from "../taskAssignRule/taskAssignRuleDialog";
|
||||
|
||||
import Treeselect from "@riophae/vue-treeselect";
|
||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||
|
||||
export default {
|
||||
name: "model",
|
||||
components: {
|
||||
Parser,
|
||||
Treeselect,
|
||||
taskAssignRuleDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 表格数据
|
||||
list: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
|
||||
// BPMN 数据
|
||||
showBpmnOpen: false,
|
||||
bpmnXML: null,
|
||||
bpmnControlForm: {
|
||||
prefix: "activiti"
|
||||
},
|
||||
|
||||
// 流程表单详情
|
||||
detailOpen: false,
|
||||
detailForm: {
|
||||
fields: []
|
||||
},
|
||||
|
||||
// 流程表单
|
||||
title: "",
|
||||
open: false,
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
key: [{ required: true, message: "流程标识不能为空", trigger: "blur" }],
|
||||
name: [{ required: true, message: "流程名称不能为空", trigger: "blur" }],
|
||||
formType: [{ required: true, message: "流程名称不能为空", trigger: "blur" }],
|
||||
formId: [{ required: true, message: "业务表单不能为空", trigger: "blur" }],
|
||||
category: [{ required: true, message: "流程分类不能为空", trigger: "blur" }],
|
||||
formCustomCreatePath: [{ required: true, message: "表单提交路由不能为空", trigger: "blur" }],
|
||||
formCustomViewPath: [{ required: true, message: "表单查看路由不能为空", trigger: "blur" }],
|
||||
},
|
||||
|
||||
// 流程导入参数
|
||||
upload: {
|
||||
// 是否显示弹出层(用户导入)
|
||||
open: false,
|
||||
// 是否禁用上传
|
||||
isUploading: false,
|
||||
// 设置上传的请求头部
|
||||
headers: getBaseHeader(),
|
||||
// 上传的地址
|
||||
url: process.env.VUE_APP_BASE_API + '/api/' + "/bpm/model/import",
|
||||
// 表单
|
||||
form: {},
|
||||
// 校验规则
|
||||
rules: {
|
||||
key: [{ required: true, message: "流程标识不能为空", trigger: "blur" }],
|
||||
name: [{ required: true, message: "流程名称不能为空", trigger: "blur" }],
|
||||
},
|
||||
},
|
||||
// 流程表单的下拉框的数据
|
||||
forms: [],
|
||||
|
||||
// 数据字典
|
||||
categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY),
|
||||
modelFormTypeDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_FORM_TYPE),
|
||||
taskAssignRuleDictDatas: getDictDatas(DICT_TYPE.BPM_TASK_ASSIGN_RULE_TYPE),
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
// 获得流程表单的下拉框的数据
|
||||
getSimpleForms().then(response => {
|
||||
this.forms = response.data
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
/** 查询流程模型列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
getModelPage(this.queryParams).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
key: undefined,
|
||||
name: undefined,
|
||||
description: undefined,
|
||||
category: undefined,
|
||||
formType: undefined,
|
||||
formId: undefined,
|
||||
formCustomCreatePath: undefined,
|
||||
formCustomViewPath: undefined
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRange = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.title = "新建模型";
|
||||
this.open = true;
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
this.title = "修改模型";
|
||||
this.open = true;
|
||||
// 设置 form
|
||||
this.form = {
|
||||
...row
|
||||
};
|
||||
// 触发一次校验
|
||||
// this.$refs["form"].validate();
|
||||
},
|
||||
/** 设计按钮操作 */
|
||||
handleDesign(row) {
|
||||
this.$router.push({
|
||||
path:"/bpm/manager/model/design",
|
||||
query:{
|
||||
modelId: row.id
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 更新
|
||||
if (this.form.id) {
|
||||
updateModel({
|
||||
...this.form,
|
||||
formId: this.form.formType === 10 ? this.form.formId : undefined,
|
||||
formCustomCreatePath: this.form.formType === 20 ? this.form.formCustomCreatePath : undefined,
|
||||
formCustomViewPath: this.form.formType === 20 ? this.form.formCustomViewPath : undefined,
|
||||
}).then(response => {
|
||||
this.msgSuccess("修改模型成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 创建
|
||||
createModel(this.form).then(response => {
|
||||
this.open = false;
|
||||
this.getList();
|
||||
this.$alert('<strong>新建模型成功!</strong>后续需要执行如下 4 个步骤:' +
|
||||
'<div>1. 点击【修改流程】按钮,配置流程的分类、表单信息</div>' +
|
||||
'<div>2. 点击【设计流程】按钮,绘制流程图</div>' +
|
||||
'<div>3. 点击【分配规则】按钮,设置每个用户任务的审批人</div>' +
|
||||
'<div>4. 点击【发布流程】按钮,完成流程的最终发布</div>' +
|
||||
'另外,每次流程修改后,都需要点击【发布流程】按钮,才能正式生效!!!',
|
||||
'重要提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const that = this;
|
||||
this.$confirm('是否删除该流程!!', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
deleteModel(row.id).then(response => {
|
||||
that.getList();
|
||||
that.msgSuccess("删除成功");
|
||||
})
|
||||
})
|
||||
},
|
||||
/** 部署按钮操作 */
|
||||
handleDeploy(row) {
|
||||
const that = this;
|
||||
this.$confirm('是否部署该流程!!', "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "success"
|
||||
}).then(function() {
|
||||
deployModel(row.id).then(response => {
|
||||
that.getList();
|
||||
that.msgSuccess("部署成功");
|
||||
})
|
||||
})
|
||||
},
|
||||
/** 流程表单的详情按钮操作 */
|
||||
handleFormDetail(row) {
|
||||
// 流程表单
|
||||
if (row.formId) {
|
||||
getForm(row.formId).then(response => {
|
||||
// 设置值
|
||||
const data = response.data
|
||||
this.detailForm = {
|
||||
...JSON.parse(data.conf),
|
||||
fields: decodeFields(data.fields)
|
||||
}
|
||||
// 弹窗打开
|
||||
this.detailOpen = true
|
||||
})
|
||||
// 业务表单
|
||||
} else if (row.formCustomCreatePath) {
|
||||
this.$router.push({ path: row.formCustomCreatePath});
|
||||
}
|
||||
},
|
||||
/** 流程图的详情按钮操作 */
|
||||
handleBpmnDetail(row) {
|
||||
getModel(row.id).then(response => {
|
||||
this.bpmnXML = response.data.bpmnXml
|
||||
// 弹窗打开
|
||||
this.showBpmnOpen = true
|
||||
})
|
||||
},
|
||||
/** 跳转流程定义的列表 */
|
||||
handleDefinitionList(row) {
|
||||
this.$router.push({
|
||||
path:"/bpm/manager/definition",
|
||||
query:{
|
||||
key: row.key
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 更新状态操作 */
|
||||
handleChangeState(row) {
|
||||
const id = row.id;
|
||||
let state = row.processDefinition.suspensionState;
|
||||
let statusState = state === 1 ? '激活' : '挂起';
|
||||
this.$confirm('是否确认' + statusState + '流程名字为"' + row.name + '"的数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return updateModelState(id, state);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess(statusState + "成功");
|
||||
})
|
||||
},
|
||||
/** 导入按钮操作 */
|
||||
handleImport() {
|
||||
this.upload.open = true;
|
||||
},
|
||||
// 文件上传中处理
|
||||
handleFileUploadProgress(event, file, fileList) {
|
||||
this.upload.isUploading = true;
|
||||
},
|
||||
// 文件上传成功处理
|
||||
handleFileSuccess(response, file, fileList) {
|
||||
if (response.code !== 0) {
|
||||
this.msgError(response.msg)
|
||||
return;
|
||||
}
|
||||
// 重置表单
|
||||
this.uploadClose();
|
||||
// 提示,并刷新
|
||||
this.msgSuccess("导入流程成功!请点击【设计流程】按钮,进行编辑保存后,才可以进行【发布流程】");
|
||||
this.getList();
|
||||
},
|
||||
uploadClose() {
|
||||
// 关闭弹窗
|
||||
this.upload.open = false;
|
||||
// 重置上传状态和文件
|
||||
this.upload.isUploading = false;
|
||||
this.$refs.upload.clearFiles();
|
||||
// 重置表单
|
||||
this.upload.form = {};
|
||||
this.resetForm("uploadForm");
|
||||
},
|
||||
/** 提交上传文件 */
|
||||
submitFileForm() {
|
||||
this.$refs["uploadForm"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
this.$refs.upload.submit();
|
||||
})
|
||||
},
|
||||
/** 处理任务分配规则列表的按钮操作 */
|
||||
handleAssignRule(row) {
|
||||
this.$refs['taskAssignRuleDialog'].initModel(row.id);
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.my-process-designer {
|
||||
height: calc(100vh - 200px);
|
||||
}
|
||||
</style>
|
||||
186
yudao-admin-ui/src/views/bpm/model/modelEditor.vue
Normal file
186
yudao-admin-ui/src/views/bpm/model/modelEditor.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 流程设计器,负责绘制流程等 -->
|
||||
<my-process-designer :key="`designer-${reloadIndex}`" v-model="xmlString" v-bind="controlForm"
|
||||
keyboard ref="processDesigner" @init-finished="initModeler"
|
||||
@save="save"/>
|
||||
|
||||
<!-- 流程属性器,负责编辑每个流程节点的属性 -->
|
||||
<my-properties-panel :key="`penal-${reloadIndex}`" :bpmn-modeler="modeler" :prefix="controlForm.prefix" class="process-panel"
|
||||
:model="model" />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import translations from "@/components/bpmnProcessDesigner/src/translations";
|
||||
// 自定义元素选中时的弹出菜单(修改 默认任务 为 用户任务)
|
||||
import CustomContentPadProvider from "@/components/bpmnProcessDesigner/package/designer/plugins/content-pad";
|
||||
// 自定义左侧菜单(修改 默认任务 为 用户任务)
|
||||
import CustomPaletteProvider from "@/components/bpmnProcessDesigner/package/designer/plugins/palette";
|
||||
// import xmlObj2json from "./utils/xml2json";
|
||||
import MyProcessPalette from "@/components/bpmnProcessDesigner/package/palette/ProcessPalette";
|
||||
import {createModel, getModel, updateModel} from "@/api/bpm/model";
|
||||
// 自定义侧边栏
|
||||
// import MyProcessPanel from "../package/process-panel/ProcessPanel";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
components: { MyProcessPalette },
|
||||
data() {
|
||||
return {
|
||||
xmlString: "", // BPMN XML
|
||||
modeler: null,
|
||||
reloadIndex: 0,
|
||||
controlDrawerVisible: false,
|
||||
translationsSelf: translations,
|
||||
controlForm: {
|
||||
simulation: true,
|
||||
labelEditing: false,
|
||||
labelVisible: false,
|
||||
prefix: "activiti",
|
||||
headerButtonSize: "mini",
|
||||
additionalModel: [CustomContentPadProvider, CustomPaletteProvider]
|
||||
},
|
||||
addis: {
|
||||
CustomContentPadProvider,
|
||||
CustomPaletteProvider
|
||||
},
|
||||
// 流程模型的信息
|
||||
model: {},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// 如果 modelId 非空,说明是修改流程模型
|
||||
const modelId = this.$route.query && this.$route.query.modelId
|
||||
if (modelId) {
|
||||
getModel(modelId).then(response => {
|
||||
this.xmlString = response.data.bpmnXml
|
||||
this.model = {
|
||||
...response.data,
|
||||
bpmnXml: undefined, // 清空 bpmnXml 属性
|
||||
}
|
||||
// this.controlForm.processId = response.data.key
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initModeler(modeler) {
|
||||
setTimeout(() => {
|
||||
this.modeler = modeler;
|
||||
console.log(modeler);
|
||||
}, 10);
|
||||
},
|
||||
reloadProcessDesigner(deep) {
|
||||
this.controlForm.additionalModel = [];
|
||||
for (let key in this.addis) {
|
||||
if (this.addis[key]) {
|
||||
this.controlForm.additionalModel.push(this.addis[key]);
|
||||
}
|
||||
}
|
||||
deep && (this.xmlString = undefined);
|
||||
this.reloadIndex += 1;
|
||||
this.modeler = null; // 避免 panel 异常
|
||||
// if (deep) {
|
||||
// this.xmlString = undefined;
|
||||
// this.$refs.processDesigner.processRestart();
|
||||
// }
|
||||
},
|
||||
save(bpmnXml) {
|
||||
const data = {
|
||||
...this.model,
|
||||
bpmnXml: bpmnXml, // this.bpmnXml 只是初始化流程图,后续修改无法通过它获得
|
||||
}
|
||||
|
||||
// 修改的提交
|
||||
if (data.id) {
|
||||
updateModel(data).then(response => {
|
||||
this.msgSuccess("修改成功")
|
||||
// 跳转回去
|
||||
this.close()
|
||||
})
|
||||
return
|
||||
}
|
||||
// 添加的提交
|
||||
createModel(data).then(response => {
|
||||
this.msgSuccess("保存成功")
|
||||
// 跳转回去
|
||||
this.close()
|
||||
})
|
||||
},
|
||||
/** 关闭按钮 */
|
||||
close() {
|
||||
this.$store.dispatch("tagsView/delView", this.$route);
|
||||
this.$router.push({ path: "/bpm/manager/model", query: { t: Date.now()}})
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
//body {
|
||||
// overflow: hidden;
|
||||
// margin: 0;
|
||||
// box-sizing: border-box;
|
||||
//}
|
||||
//.app {
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// box-sizing: border-box;
|
||||
// display: inline-grid;
|
||||
// grid-template-columns: 100px auto max-content;
|
||||
//}
|
||||
.demo-control-bar {
|
||||
position: fixed;
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
z-index: 1;
|
||||
.open-control-dialog {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
font-size: 32px;
|
||||
background: rgba(64, 158, 255, 1);
|
||||
color: #ffffff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 芋艿:去掉多余的 faq
|
||||
//.info-tip {
|
||||
// position: fixed;
|
||||
// top: 40px;
|
||||
// right: 500px;
|
||||
// z-index: 10;
|
||||
// color: #999999;
|
||||
//}
|
||||
|
||||
.control-form {
|
||||
.el-radio {
|
||||
width: 100%;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.element-overlays {
|
||||
box-sizing: border-box;
|
||||
padding: 8px;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
border-radius: 4px;
|
||||
color: #fafafa;
|
||||
}
|
||||
|
||||
.my-process-designer {
|
||||
height: calc(100vh - 84px);
|
||||
}
|
||||
.process-panel__container {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 55px;
|
||||
height: calc(100vh - 84px);
|
||||
}
|
||||
|
||||
</style>
|
||||
76
yudao-admin-ui/src/views/bpm/oa/leave/create.vue
Normal file
76
yudao-admin-ui/src/views/bpm/oa/leave/create.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="开始时间" prop="startTime">
|
||||
<el-date-picker clearable size="small" v-model="form.startTime" type="date" value-format="timestamp" placeholder="选择开始时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间" prop="endTime">
|
||||
<el-date-picker clearable size="small" v-model="form.endTime" type="date" value-format="timestamp" placeholder="选择结束时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="请假类型" prop="type">
|
||||
<el-select v-model="form.type" placeholder="请选择">
|
||||
<el-option v-for="dict in typeDictData" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="原因" prop="reason">
|
||||
<el-col :span="10">
|
||||
<el-input type="textarea" :rows="3" v-model="form.reason" placeholder="请输入原因" />
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提 交</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createLeave} from "@/api/bpm/leave"
|
||||
import { getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
|
||||
export default {
|
||||
name: "LeaveCreate",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 表单参数
|
||||
form: {
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
type: undefined,
|
||||
reason: undefined,
|
||||
},
|
||||
// 表单校验
|
||||
rules: {
|
||||
startTime: [{ required: true, message: "开始时间不能为空", trigger: "blur" }],
|
||||
endTime: [{ required: true, message: "结束时间不能为空", trigger: "blur" }],
|
||||
type: [{ required: true, message: "请假类型不能为空", trigger: "change" }],
|
||||
reason: [{ required: true, message: "请假原因不能为空", trigger: "change" }],
|
||||
},
|
||||
|
||||
typeDictData: getDictDatas(DICT_TYPE.BPM_OA_LEAVE_TYPE),
|
||||
};
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加的提交
|
||||
createLeave(this.form).then(response => {
|
||||
this.msgSuccess("发起成功");
|
||||
this.$store.dispatch("tagsView/delView", this.$route);
|
||||
this.$router.push({ path: "/bpm/oa/leave"});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
54
yudao-admin-ui/src/views/bpm/oa/leave/detail.vue
Normal file
54
yudao-admin-ui/src/views/bpm/oa/leave/detail.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="开始时间:" prop="startTime"> {{parseTime(form.startTime, '{y}-{m}-{d}')}} </el-form-item>
|
||||
<el-form-item label="结束时间:" prop="endTime"> {{parseTime(form.endTime, '{y}-{m}-{d}')}} </el-form-item>
|
||||
<el-form-item label="请假类型:" prop="type">{{ typeFormat(form) }}</el-form-item>
|
||||
<el-form-item label="原因:" prop="reason"> {{ form.reason }}</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLeave} from "@/api/bpm/leave"
|
||||
import {getDictDatas, DICT_TYPE, getDictDataLabel} from '@/utils/dict'
|
||||
export default {
|
||||
name: "LeaveDetail",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
id: undefined, // 请假编号
|
||||
// 表单参数
|
||||
form: {
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
type: undefined,
|
||||
reason: undefined,
|
||||
},
|
||||
|
||||
typeDictData: getDictDatas(DICT_TYPE.BPM_OA_LEAVE_TYPE),
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.id = this.$route.query.id;
|
||||
if (!this.id) {
|
||||
this.$message.error('未传递 id 参数,无法查看 OA 请假信息');
|
||||
return;
|
||||
}
|
||||
this.getDetail();
|
||||
},
|
||||
methods: {
|
||||
/** 获得请假信息 */
|
||||
getDetail() {
|
||||
getLeave(this.id).then(response => {
|
||||
this.form = response.data;
|
||||
});
|
||||
},
|
||||
typeFormat(row) {
|
||||
return getDictDataLabel(DICT_TYPE.BPM_OA_LEAVE_TYPE, row.type)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
174
yudao-admin-ui/src/views/bpm/oa/leave/index.vue
Normal file
174
yudao-admin-ui/src/views/bpm/oa/leave/index.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="请假类型" prop="type">
|
||||
<el-select v-model="queryParams.type" placeholder="请选择请假类型" clearable>
|
||||
<el-option v-for="dict in leaveTypeDictData" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请时间">
|
||||
<el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结果" prop="result">
|
||||
<el-select v-model="queryParams.result" placeholder="请选择流结果" clearable size="small">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT)"
|
||||
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="原因" prop="reason">
|
||||
<el-input v-model="queryParams.reason" placeholder="请输入原因" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" icon="el-icon-plus" size="mini" v-hasPermi="['bpm:oa-leave:create']" @click="handleAdd">发起请假</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="申请编号" align="center" prop="id" />
|
||||
<el-table-column label="状态" align="center" prop="result" :formatter="resultFormat" />
|
||||
<el-table-column label="开始时间" align="center" prop="startTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.startTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束时间" align="center" prop="endTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.endTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="请假类型" align="center" prop="type" :formatter="typeFormat" />
|
||||
<el-table-column label="原因" align="center" prop="reason" />
|
||||
<el-table-column label="申请时间" align="center" prop="applyTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleCancel(scope.row)"
|
||||
v-hasPermi="['bpm:oa-leave:create']" v-if="scope.row.result === 1">取消请假</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleDetail(scope.row)"
|
||||
v-hasPermi="['bpm:oa-leave:query']">详情</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleProcessDetail(scope.row)">审批进度</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLeavePage } from "@/api/bpm/leave"
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
import {cancelProcessInstance} from "@/api/bpm/processInstance";
|
||||
|
||||
export default {
|
||||
name: "Leave",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 请假申请列表
|
||||
list: [],
|
||||
//审批进度弹出层
|
||||
dateRangeCreateTime: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
result: null,
|
||||
type: null,
|
||||
reason: null,
|
||||
},
|
||||
|
||||
leaveTypeDictData: getDictDatas(DICT_TYPE.BPM_OA_LEAVE_TYPE),
|
||||
leaveResultData: getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT),
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
||||
// 执行查询
|
||||
getLeavePage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeCreateTime = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.$router.push({ path: "/bpm/oa/leave/create"});
|
||||
},
|
||||
/** 详情按钮操作 */
|
||||
handleDetail(row) {
|
||||
this.$router.push({ path: "/bpm/oa/leave/detail", query: { id: row.id}});
|
||||
},
|
||||
/** 查看审批进度的操作 */
|
||||
handleProcessDetail(row) {
|
||||
this.$router.push({ path: "/bpm/process-instance/detail", query: { id: row.processInstanceId}});
|
||||
},
|
||||
/** 取消请假 */
|
||||
handleCancel(row) {
|
||||
const id = row.processInstanceId;
|
||||
this.$prompt('请输入取消原因?', "取消流程", {
|
||||
type: 'warning',
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/, // 判断非空,且非空格
|
||||
inputErrorMessage: "取消原因不能为空",
|
||||
}).then(({ value }) => {
|
||||
return cancelProcessInstance(id, value);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("取消成功");
|
||||
})
|
||||
},
|
||||
resultFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, row.result)
|
||||
},
|
||||
typeFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.BPM_OA_LEAVE_TYPE, row.type)
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
169
yudao-admin-ui/src/views/bpm/processInstance/create.vue
Normal file
169
yudao-admin-ui/src/views/bpm/processInstance/create.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 第一步,通过流程定义的列表,选择对应的流程 -->
|
||||
<div v-if="!selectProcessInstance">
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="流程名称" align="center" prop="name" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="handleBpmnDetail(scope.row)">
|
||||
<span>{{ scope.row.name }}</span>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="流程分类" align="center" prop="category" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDictDataLabel(DICT_TYPE.BPM_MODEL_CATEGORY, scope.row.category) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="流程版本" align="center" prop="processDefinition.version" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="medium" v-if="scope.row">v{{ scope.row.version }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="流程描述" align="center" prop="description" width="300" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" icon="el-icon-plus" @click="handleSelect(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 第二步,填写表单,进行流程的提交 -->
|
||||
<div v-else>
|
||||
<el-card class="box-card" >
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="el-icon-document">申请信息【{{ selectProcessInstance.name }}】</span>
|
||||
<el-button style="float: right;" type="primary" @click="selectProcessInstance = undefined">选择其它流程</el-button>
|
||||
</div>
|
||||
<el-col :span="16" :offset="6">
|
||||
<div>
|
||||
<parser :key="new Date().getTime()" :form-conf="detailForm" @submit="submitForm" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-card>
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="el-icon-picture-outline">流程图</span>
|
||||
</div>
|
||||
<my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" />
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getProcessDefinitionBpmnXML, getProcessDefinitionList} from "@/api/bpm/definition";
|
||||
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
|
||||
import {getForm} from "@/api/bpm/form";
|
||||
import {decodeFields} from "@/utils/formGenerator";
|
||||
import Parser from '@/components/parser/Parser'
|
||||
import {createProcessInstance, getMyProcessInstancePage} from "@/api/bpm/processInstance";
|
||||
|
||||
// 流程实例的发起
|
||||
export default {
|
||||
name: "ProcessInstanceCreate",
|
||||
components: {
|
||||
Parser
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 表格数据
|
||||
list: [],
|
||||
|
||||
// 流程表单详情
|
||||
detailForm: {
|
||||
fields: []
|
||||
},
|
||||
|
||||
// BPMN 数据
|
||||
bpmnXML: null,
|
||||
bpmnControlForm: {
|
||||
prefix: "activiti"
|
||||
},
|
||||
|
||||
// 流程表单
|
||||
selectProcessInstance: undefined, // 选择的流程实例
|
||||
|
||||
// 数据字典
|
||||
categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY),
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询流程定义列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
getProcessDefinitionList({
|
||||
suspensionState: 1
|
||||
}).then(response => {
|
||||
this.list = response.data
|
||||
this.loading = false
|
||||
}
|
||||
);
|
||||
},
|
||||
/** 处理选择流程的按钮操作 **/
|
||||
handleSelect(row) {
|
||||
// 设置选择的流程
|
||||
this.selectProcessInstance = row;
|
||||
|
||||
// 流程表单
|
||||
if (row.formId) {
|
||||
// 设置对应的表单
|
||||
this.detailForm = {
|
||||
...JSON.parse(row.formConf),
|
||||
fields: decodeFields(row.formFields)
|
||||
}
|
||||
|
||||
// 加载流程图
|
||||
getProcessDefinitionBpmnXML(row.id).then(response => {
|
||||
this.bpmnXML = response.data
|
||||
})
|
||||
} else if (row.formCustomCreatePath) {
|
||||
this.$router.push({ path: row.formCustomCreatePath});
|
||||
// 这里暂时无需加载流程图,因为跳出到另外个 Tab;
|
||||
}
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm(params) {
|
||||
if (!params) {
|
||||
return;
|
||||
}
|
||||
// 设置表单禁用
|
||||
const conf = params.conf;
|
||||
conf.disabled = true; // 表单禁用
|
||||
conf.formBtns = false; // 按钮隐藏
|
||||
|
||||
// 提交表单,创建流程
|
||||
const variables = params.values;
|
||||
createProcessInstance({
|
||||
processDefinitionId: this.selectProcessInstance.id,
|
||||
variables: variables
|
||||
}).then(response => {
|
||||
this.msgSuccess("发起流程成功");
|
||||
// 关闭当前窗口
|
||||
this.$store.dispatch("tagsView/delView", this.$route);
|
||||
this.$router.go(-1);
|
||||
}).catch(() => {
|
||||
conf.disabled = false; // 表单开启
|
||||
conf.formBtns = true; // 按钮展示
|
||||
})
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.my-process-designer {
|
||||
height: calc(100vh - 200px);
|
||||
}
|
||||
|
||||
.box-card {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
424
yudao-admin-ui/src/views/bpm/processInstance/detail.vue
Normal file
424
yudao-admin-ui/src/views/bpm/processInstance/detail.vue
Normal file
@@ -0,0 +1,424 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 审批信息 -->
|
||||
<el-card class="box-card" v-loading="processInstanceLoading" v-for="(item, index) in runningTasks" :key="index">
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="el-icon-picture-outline">审批任务【{{ item.name }}】</span>
|
||||
</div>
|
||||
<el-col :span="16" :offset="6" >
|
||||
<el-form :ref="'form' + index" :model="auditForms[index]" :rules="auditRule" label-width="100px">
|
||||
<el-form-item label="流程名" v-if="processInstance && processInstance.name">
|
||||
{{ processInstance.name }}
|
||||
</el-form-item>
|
||||
<el-form-item label="流程发起人" v-if="processInstance && processInstance.startUser">
|
||||
{{ processInstance.startUser.nickname }}
|
||||
<el-tag type="info" size="mini">{{ processInstance.startUser.deptName }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="审批建议" prop="comment">
|
||||
<el-input type="textarea" v-model="auditForms[index].comment" placeholder="请输入审批建议" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="margin-left: 10%; margin-bottom: 20px; font-size: 14px;">
|
||||
<el-button icon="el-icon-edit-outline" type="success" size="mini" @click="handleAudit(item, true)">通过</el-button>
|
||||
<el-button icon="el-icon-circle-close" type="danger" size="mini" @click="handleAudit(item, false)">不通过</el-button>
|
||||
<el-button icon="el-icon-edit-outline" type="primary" size="mini" @click="handleUpdateAssignee(item)">转办</el-button>
|
||||
<el-button icon="el-icon-edit-outline" type="primary" size="mini" @click="handleDelegate(item)">委派</el-button>
|
||||
<el-button icon="el-icon-refresh-left" type="warning" size="mini" @click="handleBack(item)">退回</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-card>
|
||||
<!-- 申请信息 -->
|
||||
<el-card class="box-card" v-loading="processInstanceLoading">
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="el-icon-document">申请信息【{{ processInstance.name }}】</span>
|
||||
</div>
|
||||
<el-col v-if="this.processInstance.processDefinition && this.processInstance.processDefinition.formType === 10"
|
||||
:span="16" :offset="6">
|
||||
<div >
|
||||
<parser :key="new Date().getTime()" :form-conf="detailForm" @submit="submitForm" />
|
||||
</div>
|
||||
</el-col>
|
||||
<div v-if="this.processInstance.processDefinition && this.processInstance.processDefinition.formType === 20">
|
||||
<router-link :to="this.processInstance.processDefinition.formCustomViewPath + '?id='
|
||||
+ this.processInstance.businessKey">
|
||||
<el-button type="primary">点击查看</el-button>
|
||||
</router-link>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card class="box-card" v-loading="tasksLoad">
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="el-icon-picture-outline">审批记录</span>
|
||||
</div>
|
||||
<el-col :span="16" :offset="4" >
|
||||
<div class="block">
|
||||
<el-timeline>
|
||||
<el-timeline-item v-for="(item, index) in tasks" :key="index"
|
||||
:icon="getTimelineItemIcon(item)" :type="getTimelineItemType(item)">
|
||||
<p style="font-weight: 700">任务:{{ item.name }}</p>
|
||||
<el-card :body-style="{ padding: '10px' }">
|
||||
<label v-if="item.assigneeUser" style="font-weight: normal; margin-right: 30px;">
|
||||
审批人:{{ item.assigneeUser.nickname }}
|
||||
<el-tag type="info" size="mini">{{ item.assigneeUser.deptName }}</el-tag>
|
||||
</label>
|
||||
<label style="font-weight: normal">创建时间:</label>
|
||||
<label style="color:#8a909c; font-weight: normal">{{ parseTime(item.createTime) }}</label>
|
||||
<label v-if="item.endTime" style="margin-left: 30px;font-weight: normal">审批时间:</label>
|
||||
<label v-if="item.endTime" style="color:#8a909c;font-weight: normal"> {{ parseTime(item.endTime) }}</label>
|
||||
<label v-if="item.durationInMillis" style="margin-left: 30px;font-weight: normal">耗时:</label>
|
||||
<label v-if="item.durationInMillis" style="color:#8a909c;font-weight: normal"> {{ getDateStar(item.durationInMillis) }} </label>
|
||||
<p v-if="item.comment">
|
||||
<el-tag :type="getTimelineItemType(item)">{{ item.comment }}</el-tag>
|
||||
</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-card>
|
||||
|
||||
<!-- 高亮流程图 -->
|
||||
<el-card class="box-card" v-loading="processInstanceLoading">
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="el-icon-picture-outline">流程图</span>
|
||||
</div>
|
||||
<my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :activityData="activityList"
|
||||
:processInstanceData="processInstance" :taskData="tasks" />
|
||||
</el-card>
|
||||
|
||||
<!-- 对话框(转派审批人) -->
|
||||
<el-dialog title="转派审批人" :visible.sync="updateAssignee.open" width="500px" append-to-body>
|
||||
<el-form ref="updateAssigneeForm" :model="updateAssignee.form" :rules="updateAssignee.rules" label-width="110px">
|
||||
<el-form-item label="新审批人" prop="assigneeUserId">
|
||||
<el-select v-model="updateAssignee.form.assigneeUserId" clearable style="width: 100%">
|
||||
<el-option v-for="item in userOptions" :key="parseInt(item.id)" :label="item.nickname" :value="parseInt(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitUpdateAssigneeForm">确 定</el-button>
|
||||
<el-button @click="cancelUpdateAssigneeForm">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getProcessDefinitionBpmnXML} from "@/api/bpm/definition";
|
||||
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
|
||||
import store from "@/store";
|
||||
import {decodeFields} from "@/utils/formGenerator";
|
||||
import Parser from '@/components/parser/Parser'
|
||||
import {createProcessInstance, getProcessInstance} from "@/api/bpm/processInstance";
|
||||
import {approveTask, getTaskListByProcessInstanceId, rejectTask, updateTaskAssignee} from "@/api/bpm/task";
|
||||
import {getDate} from "@/utils/dateUtils";
|
||||
import {listSimpleUsers} from "@/api/system/user";
|
||||
import {getActivityList} from "@/api/bpm/activity";
|
||||
|
||||
// 流程实例的详情页,可用于审批
|
||||
export default {
|
||||
name: "ProcessInstanceDetail",
|
||||
components: {
|
||||
Parser
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
processInstanceLoading: true,
|
||||
// 流程实例
|
||||
id: undefined, // 流程实例的编号
|
||||
processInstance: {},
|
||||
|
||||
// 流程表单详情
|
||||
detailForm: {
|
||||
fields: []
|
||||
},
|
||||
|
||||
// BPMN 数据
|
||||
bpmnXML: null,
|
||||
bpmnControlForm: {
|
||||
prefix: "activiti"
|
||||
},
|
||||
activityList: [],
|
||||
|
||||
// 审批记录
|
||||
tasksLoad: true,
|
||||
tasks: [],
|
||||
|
||||
// 审批表单
|
||||
runningTasks: [],
|
||||
auditForms: [],
|
||||
auditRule: {
|
||||
comment: [{ required: true, message: "审批建议不能为空", trigger: "blur" }],
|
||||
},
|
||||
|
||||
// 转派审批人
|
||||
userOptions: [],
|
||||
updateAssignee: {
|
||||
open: false,
|
||||
form: {
|
||||
assigneeUserId: undefined,
|
||||
},
|
||||
rules: {
|
||||
assigneeUserId: [{ required: true, message: "新审批人不能为空", trigger: "change" }],
|
||||
}
|
||||
},
|
||||
|
||||
// 数据字典
|
||||
categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY),
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.id = this.$route.query.id;
|
||||
if (!this.id) {
|
||||
this.$message.error('未传递 id 参数,无法查看流程信息');
|
||||
return;
|
||||
}
|
||||
this.getDetail();
|
||||
|
||||
// 获得用户列表
|
||||
this.userOptions = [];
|
||||
listSimpleUsers().then(response => {
|
||||
this.userOptions.push(...response.data);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
/** 获得流程实例 */
|
||||
getDetail() {
|
||||
// 获得流程实例相关
|
||||
this.processInstanceLoading = true;
|
||||
getProcessInstance(this.id).then(response => {
|
||||
if (!response.data) {
|
||||
this.$message.error('查询不到流程信息!');
|
||||
return;
|
||||
}
|
||||
// 设置流程信息
|
||||
this.processInstance = response.data;
|
||||
|
||||
// 设置表单信息
|
||||
if (this.processInstance.processDefinition.formType === 10) {
|
||||
this.detailForm = {
|
||||
...JSON.parse(this.processInstance.processDefinition.formConf),
|
||||
disabled: true, // 表单禁用
|
||||
formBtns: false, // 按钮隐藏
|
||||
fields: decodeFields(this.processInstance.processDefinition.formFields)
|
||||
}
|
||||
// 设置表单的值
|
||||
this.detailForm.fields.forEach(item => {
|
||||
const val = this.processInstance.formVariables[item.__vModel__]
|
||||
if (val) {
|
||||
item.__config__.defaultValue = val
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 加载流程图
|
||||
getProcessDefinitionBpmnXML(this.processInstance.processDefinition.id).then(response => {
|
||||
this.bpmnXML = response.data
|
||||
});
|
||||
// 加载活动列表
|
||||
getActivityList({
|
||||
processInstanceId: this.processInstance.id
|
||||
}).then(response => {
|
||||
this.activityList = response.data;
|
||||
});
|
||||
|
||||
// 取消加载中
|
||||
this.processInstanceLoading = false;
|
||||
});
|
||||
|
||||
// 获得流程任务列表(审批记录)
|
||||
this.tasksLoad = true;
|
||||
this.runningTasks = [];
|
||||
this.auditForms = [];
|
||||
getTaskListByProcessInstanceId(this.id).then(response => {
|
||||
// 审批记录
|
||||
this.tasks = response.data;
|
||||
// 排序,将未完成的排在前面,已完成的排在后面;
|
||||
this.tasks.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;
|
||||
}
|
||||
});
|
||||
|
||||
// 需要审核的记录
|
||||
const userId = store.getters.userId;
|
||||
this.tasks.forEach(task => {
|
||||
if (task.result !== 1) { // 只有待处理才需要
|
||||
return;
|
||||
}
|
||||
if (!task.assigneeUser || task.assigneeUser.id !== userId) { // 自己不是处理人
|
||||
return;
|
||||
}
|
||||
this.runningTasks.push({...task});
|
||||
this.auditForms.push({
|
||||
comment: ''
|
||||
})
|
||||
});
|
||||
|
||||
// 取消加载中
|
||||
this.tasksLoad = false;
|
||||
});
|
||||
},
|
||||
/** 处理选择流程的按钮操作 **/
|
||||
handleSelect(row) {
|
||||
// 设置选择的流程
|
||||
this.selectProcessInstance = row;
|
||||
|
||||
// 流程表单
|
||||
if (row.formId) {
|
||||
// 设置对应的表单
|
||||
this.detailForm = {
|
||||
...JSON.parse(row.formConf),
|
||||
fields: decodeFields(row.formFields)
|
||||
}
|
||||
} else if (row.formCustomCreatePath) {
|
||||
this.$router.push({ path: row.formCustomCreatePath});
|
||||
// 这里暂时无需加载流程图,因为跳出到另外个 Tab;
|
||||
}
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm(params) {
|
||||
if (!params) {
|
||||
return;
|
||||
}
|
||||
// 设置表单禁用
|
||||
const conf = params.conf;
|
||||
conf.disabled = true; // 表单禁用
|
||||
conf.formBtns = false; // 按钮隐藏
|
||||
|
||||
// 提交表单,创建流程
|
||||
const variables = params.values;
|
||||
createProcessInstance({
|
||||
processDefinitionId: this.selectProcessInstance.id,
|
||||
variables: variables
|
||||
}).then(response => {
|
||||
this.msgSuccess("发起流程成功");
|
||||
// 关闭当前窗口
|
||||
this.$store.dispatch("tagsView/delView", this.$route);
|
||||
this.$router.go(-1);
|
||||
}).catch(() => {
|
||||
conf.disabled = false; // 表单开启
|
||||
conf.formBtns = true; // 按钮展示
|
||||
})
|
||||
},
|
||||
getDateStar(ms) {
|
||||
return getDate(ms);
|
||||
},
|
||||
getTimelineItemIcon(item) {
|
||||
if (item.result === 1) {
|
||||
return 'el-icon-time';
|
||||
}
|
||||
if (item.result === 2) {
|
||||
return 'el-icon-check';
|
||||
}
|
||||
if (item.result === 3) {
|
||||
return 'el-icon-close';
|
||||
}
|
||||
if (item.result === 4) {
|
||||
return 'el-icon-remove-outline';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
getTimelineItemType(item) {
|
||||
if (item.result === 1) {
|
||||
return 'primary';
|
||||
}
|
||||
if (item.result === 2) {
|
||||
return 'success';
|
||||
}
|
||||
if (item.result === 3) {
|
||||
return 'danger';
|
||||
}
|
||||
if (item.result === 4) {
|
||||
return 'info';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
/** 处理审批通过和不通过的操作 */
|
||||
handleAudit(task, pass) {
|
||||
const index = this.runningTasks.indexOf(task);
|
||||
this.$refs['form' + index][0].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
const data = {
|
||||
id: task.id,
|
||||
comment: this.auditForms[index].comment
|
||||
}
|
||||
if (pass) {
|
||||
approveTask(data).then(response => {
|
||||
this.msgSuccess("审批通过成功!");
|
||||
this.getDetail(); // 获得最新详情
|
||||
});
|
||||
} else {
|
||||
rejectTask(data).then(response => {
|
||||
this.msgSuccess("审批不通过成功!");
|
||||
this.getDetail(); // 获得最新详情
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 处理转派审批人 */
|
||||
handleUpdateAssignee(task) {
|
||||
// 设置表单
|
||||
this.resetUpdateAssigneeForm();
|
||||
this.updateAssignee.form.id = task.id;
|
||||
// 设置为打开
|
||||
this.updateAssignee.open = true;
|
||||
},
|
||||
/** 提交转派审批人 */
|
||||
submitUpdateAssigneeForm() {
|
||||
this.$refs['updateAssigneeForm'].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
updateTaskAssignee(this.updateAssignee.form).then(response => {
|
||||
this.msgSuccess("转派任务成功!");
|
||||
this.updateAssignee.open = false;
|
||||
this.getDetail(); // 获得最新详情
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 取消转派审批人 */
|
||||
cancelUpdateAssigneeForm() {
|
||||
this.updateAssignee.open = false;
|
||||
this.resetUpdateAssigneeForm();
|
||||
},
|
||||
/** 重置转派审批人 */
|
||||
resetUpdateAssigneeForm() {
|
||||
this.updateAssignee.form = {
|
||||
id: undefined,
|
||||
assigneeUserId: undefined,
|
||||
};
|
||||
this.resetForm("updateAssigneeForm");
|
||||
},
|
||||
/** 处理审批退回的操作 */
|
||||
handleDelegate(task) {
|
||||
this.msgError("暂不支持【委派】功能,可以使用【转派】替代!");
|
||||
},
|
||||
/** 处理审批退回的操作 */
|
||||
handleBack(task) {
|
||||
this.msgError("暂不支持【退回】功能!");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.my-process-designer {
|
||||
height: calc(100vh - 200px);
|
||||
}
|
||||
|
||||
.box-card {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
215
yudao-admin-ui/src/views/bpm/processInstance/index.vue
Normal file
215
yudao-admin-ui/src/views/bpm/processInstance/index.vue
Normal file
@@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="流程名" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属流程" prop="processDefinitionId">
|
||||
<el-input v-model="queryParams.processDefinitionId" placeholder="请输入流程定义的编号" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程分类" prop="category">
|
||||
<el-select v-model="queryParams.category" placeholder="请选择流程分类" clearable size="small">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY)"
|
||||
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="提交时间">
|
||||
<el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS)"
|
||||
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="结果" prop="result">
|
||||
<el-select v-model="queryParams.result" placeholder="请选择流结果" clearable size="small">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT)"
|
||||
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['bpm:process-instance:query']">发起流程</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="id" width="320" />
|
||||
<el-table-column label="流程名" align="center" prop="name" />
|
||||
<el-table-column label="流程分类" align="center" prop="category">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDictDataLabel(DICT_TYPE.BPM_MODEL_CATEGORY, scope.row.category) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前审批任务" align="center" prop="tasks">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-for="task in scope.row.tasks" type="text" @click="handleFormDetail(task.id)">
|
||||
<span>{{ task.name }}</span>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template slot-scope="scope">
|
||||
<span>
|
||||
<el-tag type="primary" v-if="scope.row.status === 1"> <!-- 进行中 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, scope.row.status) }}
|
||||
</el-tag>
|
||||
<el-tag type="success" v-if="scope.row.status === 2"> <!-- 已结束 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, scope.row.status) }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结果" align="center" prop="result">
|
||||
<template slot-scope="scope">
|
||||
<span>
|
||||
<el-tag type="primary" v-if="scope.row.result === 1"> <!-- 进行中 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
|
||||
</el-tag>
|
||||
<el-tag type="success" v-if="scope.row.result === 2"> <!-- 通过 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
|
||||
</el-tag>
|
||||
<el-tag type="danger" v-if="scope.row.result === 3"> <!-- 不通过 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
|
||||
</el-tag>
|
||||
<el-tag type="info" v-if="scope.row.result === 4"> <!-- 撤回 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="提交时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.endTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" icon="el-icon-delete" v-if="scope.row.result === 1"
|
||||
v-hasPermi="['bpm:process-instance:cancel']" @click="handleCancel(scope.row)">取消</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleDetail(scope.row)"
|
||||
v-hasPermi="['bpm:process-instance:query']">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getMyProcessInstancePage,
|
||||
createProcessInstanceExt,
|
||||
updateProcessInstanceExt,
|
||||
deleteProcessInstanceExt,
|
||||
getProcessInstanceExt,
|
||||
getProcessInstanceExtPage,
|
||||
exportProcessInstanceExtExcel, cancelProcessInstance
|
||||
} from "@/api/bpm/processInstance";
|
||||
import {deleteErrorCode} from "@/api/system/errorCode";
|
||||
|
||||
export default {
|
||||
name: "ProcessInstance",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 工作流的流程实例的拓展列表
|
||||
list: [],
|
||||
// 是否显示弹出层
|
||||
dateRangeCreateTime: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
processDefinitionId: null,
|
||||
category: null,
|
||||
status: null,
|
||||
result: null,
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
||||
// 执行查询
|
||||
getMyProcessInstancePage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeCreateTime = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 新增按钮操作 **/
|
||||
handleAdd() {
|
||||
this.$router.push({ path: "/bpm/process-instance/create"})
|
||||
},
|
||||
/** 取消按钮操作 */
|
||||
handleCancel(row) {
|
||||
const id = row.id;
|
||||
this.$prompt('请输入取消原因?', "取消流程", {
|
||||
type: 'warning',
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/, // 判断非空,且非空格
|
||||
inputErrorMessage: "取消原因不能为空",
|
||||
}).then(({ value }) => {
|
||||
return cancelProcessInstance(id, value);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("取消成功");
|
||||
})
|
||||
},
|
||||
/** 处理详情按钮 */
|
||||
handleDetail(row) {
|
||||
this.$router.push({ path: "/bpm/process-instance/detail", query: { id: row.id}});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
136
yudao-admin-ui/src/views/bpm/task/done.vue
Normal file
136
yudao-admin-ui/src/views/bpm/task/done.vue
Normal file
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="流程名" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="任务编号" align="center" prop="id" width="320" fixed />
|
||||
<el-table-column label="任务名称" align="center" prop="name" width="200" />
|
||||
<el-table-column label="所属流程" align="center" prop="processInstance.name" width="200" />
|
||||
<el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" width="120" />
|
||||
<el-table-column label="结果" align="center" prop="result">
|
||||
<template slot-scope="scope">
|
||||
<span>
|
||||
<el-tag type="primary" v-if="scope.row.result === 1"> <!-- 进行中 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
|
||||
</el-tag>
|
||||
<el-tag type="success" v-if="scope.row.result === 2"> <!-- 通过 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
|
||||
</el-tag>
|
||||
<el-tag type="danger" v-if="scope.row.result === 3"> <!-- 不通过 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
|
||||
</el-tag>
|
||||
<el-tag type="info" v-if="scope.row.result === 4"> <!-- 撤回 -->
|
||||
{{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批意见" align="center" prop="comment" width="200" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批时间" align="center" prop="endTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.endTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="耗时" align="center" prop="durationInMillis" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDateStar(scope.row.durationInMillis) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleAudit(scope.row)"
|
||||
v-hasPermi="['bpm:task:query']">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getDoneTaskPage} from '@/api/bpm/task'
|
||||
import {getDate} from "@/utils/dateUtils";
|
||||
|
||||
export default {
|
||||
name: "Done",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 已办任务列表
|
||||
list: [],
|
||||
// 查询参数
|
||||
dateRangeCreateTime: [],
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
||||
getDoneTaskPage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeCreateTime = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
getDateStar(ms) {
|
||||
return getDate(ms);
|
||||
},
|
||||
/** 处理审批按钮 */
|
||||
handleAudit(row) {
|
||||
this.$router.push({ path: "/bpm/process-instance/detail", query: { id: row.processInstance.id}});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
110
yudao-admin-ui/src/views/bpm/task/todo.vue
Normal file
110
yudao-admin-ui/src/views/bpm/task/todo.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="流程名" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="任务编号" align="center" prop="id" width="320" />
|
||||
<el-table-column label="任务名称" align="center" prop="name" />
|
||||
<el-table-column label="所属流程" align="center" prop="processInstance.name" />
|
||||
<el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="version" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag>
|
||||
<el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleAudit(scope.row)"
|
||||
v-hasPermi="['bpm:task:update']">审批</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getTodoTaskPage} from '@/api/bpm/task'
|
||||
import {listSimpleUsers} from "@/api/system/user";
|
||||
|
||||
export default {
|
||||
name: "Todo",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 待办任务列表
|
||||
list: [],
|
||||
// 查询参数
|
||||
dateRangeCreateTime: [],
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
||||
getTodoTaskPage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeCreateTime = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 处理审批按钮 */
|
||||
handleAudit(row) {
|
||||
this.$router.push({ path: "/bpm/process-instance/detail", query: { id: row.processInstance.id}});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 列表弹窗 -->
|
||||
<el-dialog title="任务分配规则" :visible.sync="visible" width="800px" append-to-body>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="任务名" align="center" prop="taskDefinitionName" width="120" fixed />
|
||||
<el-table-column label="任务标识" align="center" prop="taskDefinitionKey" width="120" show-tooltip-when-overflow />
|
||||
<el-table-column label="规则类型" align="center" prop="type" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDictDataLabel(DICT_TYPE.BPM_TASK_ASSIGN_RULE_TYPE, scope.row.type) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规则范围" align="center" prop="options" width="440px">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="medium" v-if="scope.row.options" v-for="option in scope.row.options">
|
||||
{{ getAssignRuleOptionName(scope.row.type, option) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="modelId" label="操作" align="center" width="80" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdateTaskAssignRule(scope.row)"
|
||||
v-hasPermi="['bpm:task-assign-rule:update']">修改</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
<!-- 添加/修改弹窗 -->
|
||||
<el-dialog title="修改任务规则" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="taskAssignRuleForm" :model="form" :rules="rules" label-width="110px">
|
||||
<el-form-item label="任务名称" prop="taskDefinitionName">
|
||||
<el-input v-model="form.taskDefinitionName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="任务标识" prop="taskDefinitionKey">
|
||||
<el-input v-model="form.taskDefinitionKey" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="规则类型" prop="type">
|
||||
<el-select v-model="form.type" clearable style="width: 100%">
|
||||
<el-option v-for="dict in taskAssignRuleTypeDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === 10" label="指定角色" prop="roleIds">
|
||||
<el-select v-model="form.roleIds" multiple clearable style="width: 100%">
|
||||
<el-option v-for="item in roleOptions" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === 20 || form.type === 21" label="指定部门" prop="deptIds">
|
||||
<treeselect v-model="form.deptIds" :options="deptTreeOptions" multiple flat :defaultExpandLevel="3"
|
||||
placeholder="请选择指定部门" :normalizer="normalizer"/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === 22" label="指定岗位" prop="postIds">
|
||||
<el-select v-model="form.postIds" multiple clearable style="width: 100%">
|
||||
<el-option v-for="item in postOptions" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === 30" label="指定用户" prop="userIds">
|
||||
<el-select v-model="form.userIds" multiple clearable style="width: 100%">
|
||||
<el-option v-for="item in userOptions" :key="parseInt(item.id)" :label="item.nickname" :value="parseInt(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === 40" label="指定用户组" prop="userGroupIds">
|
||||
<el-select v-model="form.userGroupIds" multiple clearable style="width: 100%">
|
||||
<el-option v-for="item in userGroupOptions" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === 50" label="指定脚本" prop="scripts">
|
||||
<el-select v-model="form.scripts" multiple clearable style="width: 100%">
|
||||
<el-option v-for="dict in taskAssignScriptDictDatas" :key="parseInt(dict.value)"
|
||||
:label="dict.label" :value="parseInt(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitAssignRuleForm">确 定</el-button>
|
||||
<el-button @click="cancelAssignRuleForm">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
|
||||
import {createTaskAssignRule, getTaskAssignRuleList, updateTaskAssignRule} from "@/api/bpm/taskAssignRule";
|
||||
import {listSimpleRoles} from "@/api/system/role";
|
||||
import {listSimpleDepts} from "@/api/system/dept";
|
||||
|
||||
import Treeselect from "@riophae/vue-treeselect";
|
||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||
import {listSimplePosts} from "@/api/system/post";
|
||||
import {listSimpleUsers} from "@/api/system/user";
|
||||
import {listSimpleUserGroups} from "@/api/bpm/userGroup";
|
||||
|
||||
export default {
|
||||
name: "taskAssignRuleDialog",
|
||||
components: {
|
||||
Treeselect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 如下参数,可传递
|
||||
modelId: undefined, // 流程模型的编号。如果 modelId 非空,则用于流程模型的查看与配置
|
||||
processDefinitionId: undefined, // 流程定义的编号。如果 processDefinitionId 非空,则用于流程定义的查看,不支持配置
|
||||
visible: false,
|
||||
|
||||
// 任务分配规则表单
|
||||
row: undefined, // 选中的流程模型
|
||||
list: [], // 选中流程模型的任务分配规则们
|
||||
loading: false, // 加载中
|
||||
open: false, // 是否打开
|
||||
form: {}, // 表单
|
||||
rules: { // 表单校验规则
|
||||
type: [{ required: true, message: "规则类型不能为空", trigger: "change" }],
|
||||
roleIds: [{required: true, message: "指定角色不能为空", trigger: "change" }],
|
||||
deptIds: [{required: true, message: "指定部门不能为空", trigger: "change" }],
|
||||
postIds: [{required: true, message: "指定岗位不能为空", trigger: "change"}],
|
||||
userIds: [{required: true, message: "指定用户不能为空", trigger: "change"}],
|
||||
userGroupIds: [{required: true, message: "指定用户组不能为空", trigger: "change"}],
|
||||
scripts: [{required: true, message: "指定脚本不能为空", trigger: "change"}],
|
||||
},
|
||||
|
||||
// 各种下拉框
|
||||
roleOptions: [],
|
||||
deptOptions: [],
|
||||
deptTreeOptions: [],
|
||||
postOptions: [],
|
||||
userOptions: [],
|
||||
userGroupOptions: [],
|
||||
|
||||
// 数据字典
|
||||
modelFormTypeDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_FORM_TYPE),
|
||||
taskAssignRuleTypeDictDatas: getDictDatas(DICT_TYPE.BPM_TASK_ASSIGN_RULE_TYPE),
|
||||
taskAssignScriptDictDatas: getDictDatas(DICT_TYPE.BPM_TASK_ASSIGN_SCRIPT),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
initModel(modelId) {
|
||||
this.modelId = modelId;
|
||||
this.processDefinitionId = undefined;
|
||||
|
||||
// 初始化所有下拉框
|
||||
this.init0();
|
||||
},
|
||||
initProcessDefinition(processDefinitionId) {
|
||||
this.modelId = undefined;
|
||||
this.processDefinitionId = processDefinitionId;
|
||||
|
||||
// 初始化所有下拉框
|
||||
this.init0();
|
||||
},
|
||||
/** 初始化 */
|
||||
init0() {
|
||||
// 设置可见
|
||||
this.visible = true;
|
||||
// 获得列表
|
||||
this.getList();
|
||||
|
||||
// 获得角色列表
|
||||
this.roleOptions = [];
|
||||
listSimpleRoles().then(response => {
|
||||
this.roleOptions.push(...response.data);
|
||||
});
|
||||
// 获得部门列表
|
||||
this.deptOptions = [];
|
||||
this.deptTreeOptions = [];
|
||||
listSimpleDepts().then(response => {
|
||||
this.deptOptions.push(...response.data);
|
||||
this.deptTreeOptions.push(...this.handleTree(response.data, "id"));
|
||||
});
|
||||
// 获得岗位列表
|
||||
this.postOptions = [];
|
||||
listSimplePosts().then(response => {
|
||||
this.postOptions.push(...response.data);
|
||||
});
|
||||
// 获得用户列表
|
||||
this.userOptions = [];
|
||||
listSimpleUsers().then(response => {
|
||||
this.userOptions.push(...response.data);
|
||||
});
|
||||
// 获得用户组列表
|
||||
this.userGroupOptions = [];
|
||||
listSimpleUserGroups().then(response => {
|
||||
this.userGroupOptions.push(...response.data);
|
||||
});
|
||||
},
|
||||
/** 获得任务分配规则列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
getTaskAssignRuleList({
|
||||
modelId: this.modelId,
|
||||
processDefinitionId: this.processDefinitionId,
|
||||
}).then(response => {
|
||||
this.loading = false;
|
||||
this.list = response.data;
|
||||
})
|
||||
},
|
||||
/** 处理修改任务分配规则的按钮操作 */
|
||||
handleUpdateTaskAssignRule(row) {
|
||||
// 先重置标识
|
||||
this.resetAssignRuleForm();
|
||||
// 设置表单
|
||||
this.form = {
|
||||
...row,
|
||||
options: [],
|
||||
roleIds: [],
|
||||
deptIds: [],
|
||||
postIds: [],
|
||||
userIds: [],
|
||||
userGroupIds: [],
|
||||
scripts: [],
|
||||
};
|
||||
// 将 options 赋值到对应的 roleIds 等选项
|
||||
if (row.type === 10) {
|
||||
this.form.roleIds.push(...row.options);
|
||||
} else if (row.type === 20 || row.type === 21) {
|
||||
this.form.deptIds.push(...row.options);
|
||||
} else if (row.type === 22) {
|
||||
this.form.postIds.push(...row.options);
|
||||
} else if (row.type === 30) {
|
||||
this.form.userIds.push(...row.options);
|
||||
} else if (row.type === 40) {
|
||||
this.form.userGroupIds.push(...row.options);
|
||||
} else if (row.type === 50) {
|
||||
this.form.scripts.push(...row.options);
|
||||
}
|
||||
this.open = true;
|
||||
},
|
||||
/** 提交任务分配规则的表单 */
|
||||
submitAssignRuleForm() {
|
||||
this.$refs["taskAssignRuleForm"].validate(valid => {
|
||||
if (valid) {
|
||||
// 构建表单
|
||||
let form = {
|
||||
...this.form,
|
||||
taskDefinitionName: undefined,
|
||||
};
|
||||
// 将 roleIds 等选项赋值到 options 中
|
||||
if (form.type === 10) {
|
||||
form.options = form.roleIds;
|
||||
} else if (form.type === 20 || form.type === 21) {
|
||||
form.options = form.deptIds;
|
||||
} else if (form.type === 22) {
|
||||
form.options = form.postIds;
|
||||
} else if (form.type === 30) {
|
||||
form.options = form.userIds;
|
||||
} else if (form.type === 40) {
|
||||
form.options = form.userGroupIds;
|
||||
} else if (form.type === 50) {
|
||||
form.options = form.scripts;
|
||||
}
|
||||
form.roleIds = undefined;
|
||||
form.deptIds = undefined;
|
||||
form.postIds = undefined;
|
||||
form.userIds = undefined;
|
||||
form.userGroupIds = undefined;
|
||||
form.scripts = undefined;
|
||||
// 新增
|
||||
if (!form.id) {
|
||||
form.modelId = this.modelId; // 模型编号
|
||||
createTaskAssignRule(form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
// 修改
|
||||
} else {
|
||||
form.taskDefinitionKey = undefined; // 无法修改
|
||||
updateTaskAssignRule(form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 取消任务分配规则的表单 */
|
||||
cancelAssignRuleForm() {
|
||||
this.open = false;
|
||||
this.resetAssignRuleForm();
|
||||
},
|
||||
/** 表单重置 */
|
||||
resetAssignRuleForm() {
|
||||
this.form = {};
|
||||
this.resetForm("taskAssignRuleForm");
|
||||
},
|
||||
getAssignRuleOptionName(type, option) {
|
||||
if (type === 10) {
|
||||
for (const roleOption of this.roleOptions) {
|
||||
if (roleOption.id === option) {
|
||||
return roleOption.name;
|
||||
}
|
||||
}
|
||||
} else if (type === 20 || type === 21) {
|
||||
for (const deptOption of this.deptOptions) {
|
||||
if (deptOption.id === option) {
|
||||
return deptOption.name;
|
||||
}
|
||||
}
|
||||
} else if (type === 22) {
|
||||
for (const postOption of this.postOptions) {
|
||||
if (postOption.id === option) {
|
||||
return postOption.name;
|
||||
}
|
||||
}
|
||||
} else if (type === 30) {
|
||||
for (const userOption of this.userOptions) {
|
||||
if (userOption.id === option) {
|
||||
return userOption.nickname;
|
||||
}
|
||||
}
|
||||
} else if (type === 40) {
|
||||
for (const userGroupOption of this.userGroupOptions) {
|
||||
if (userGroupOption.id === option) {
|
||||
return userGroupOption.name;
|
||||
}
|
||||
}
|
||||
} else if (type === 50) {
|
||||
option = option + ''; // 转换成 string
|
||||
for (const dictData of this.taskAssignScriptDictDatas) {
|
||||
if (dictData.value === option) {
|
||||
return dictData.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
return '未知(' + option + ')';
|
||||
},
|
||||
// 格式化部门的下拉框
|
||||
normalizer(node) {
|
||||
return {
|
||||
id: node.id,
|
||||
label: node.name,
|
||||
children: node.children
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row>
|
||||
<el-button type="primary" v-on:click="leave">请假申请</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getStartForm } from "@/api/oa/flow";
|
||||
export default {
|
||||
name: "Flow",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 表单参数
|
||||
form: {},
|
||||
|
||||
rules: {
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
leave() {
|
||||
getStartForm('leave-formkey').then(response => {
|
||||
const route = response.data;
|
||||
this.$router.replace(route);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,93 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="开始时间" prop="startTime">
|
||||
<el-date-picker clearable size="small" v-model="form.startTime" type="date" value-format="timestamp" placeholder="选择开始时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间" prop="endTime">
|
||||
<el-date-picker clearable size="small" v-model="form.endTime" type="date" value-format="timestamp" placeholder="选择结束时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
<el-select v-model="form.leaveType" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in leaveTypeDictData"
|
||||
:key="parseInt(dict.value)"
|
||||
:label="dict.label"
|
||||
:value="parseInt(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="原因" prop="reason">
|
||||
<el-col :span="10">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
v-model="form.reason"
|
||||
placeholder="请输入原因" />
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请时间" prop="applyTime">
|
||||
<el-date-picker clearable size="small" v-model="form.applyTime" type="date" value-format="timestamp" placeholder="选择申请时间" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createFormKeyLeave } from "@/api/oa/leave"
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
export default {
|
||||
name: "ApplyLeave",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
startTime: [{ required: true, message: "开始时间不能为空", trigger: "blur" }],
|
||||
endTime: [{ required: true, message: "结束时间不能为空", trigger: "blur" }],
|
||||
applyTime: [{ required: true, message: "申请时间不能为空", trigger: "blur" }],
|
||||
},
|
||||
statusFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, row.status)
|
||||
},
|
||||
leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
|
||||
leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS)
|
||||
};
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 修改的提交
|
||||
// if (this.form.id != null) {
|
||||
// updateLeave(this.form).then(response => {
|
||||
// this.msgSuccess("修改成功");
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// 添加的提交
|
||||
createFormKeyLeave(this.form).then(response => {
|
||||
this.msgSuccess("新增成功");
|
||||
this.$store.dispatch('tagsView/delView', this.$route).then(({ visitedViews }) => {
|
||||
//if (this.isActive(this.$route)) {
|
||||
this.$router.push({path: '/oa/todo'})
|
||||
//}
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,190 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="任务处理">
|
||||
<el-form ref="form" :model="form" label-width="80px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-form-item label="申请人" >{{form.userId}}</el-form-item></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
{{ getDictDataLabel(DICT_TYPE.OA_LEAVE_TYPE, form.leaveType) }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6"><el-form-item label="原因" prop="reason">{{form.reason}}</el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-form-item label="开始时间" >{{ parseTime(form.startTime) }}</el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="结束时间" prop="endTime">{{ parseTime(form.endTime) }}</el-form-item></el-col>
|
||||
<el-form-item label="申请时间" prop="applyTime">{{ parseTime(form.applyTime) }}</el-form-item>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-divider></el-divider>
|
||||
<el-form ref="taskForm" :model="leaveApprove" :rules="rules" label-width="80px">
|
||||
<el-form-item label="是否同意" prop="approved">
|
||||
<el-select v-model="leaveApprove.approved" placeholder="是否同意" v-on:change="approveChange">
|
||||
<el-option
|
||||
v-for="dict in approvedData"
|
||||
:key="parseInt(dict.value)"
|
||||
:label="dict.label"
|
||||
:value="parseInt(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="处理意见" prop="comment">
|
||||
<el-col :span="11">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
v-model="leaveApprove.comment">
|
||||
</el-input>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="历史跟踪">
|
||||
<el-steps :active="stepActive" simple finish-status="success">
|
||||
<el-step :title="stepTitle(item)" icon="el-icon-edit" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
<br/>
|
||||
<el-steps direction="vertical" :active="stepActive" space="65px">
|
||||
<el-step :title="stepTitle(item)" :description="stepDes(item)" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="流程图">流程图-TODO</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLeave } from "@/api/oa/leave"
|
||||
import { completeTask,taskSteps } from "@/api/oa/todo";
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
export default {
|
||||
name: "HrApproveLeave",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
comment: [{ required: true, message: "意见不能为空", trigger: "blur" }]
|
||||
},
|
||||
handleTask: {
|
||||
historyTask:[]
|
||||
},
|
||||
leaveApprove: {
|
||||
approved : 1,
|
||||
variables: {},
|
||||
taskId: "",
|
||||
comment: "同意"
|
||||
},
|
||||
approvedData: [
|
||||
{
|
||||
value: 1,
|
||||
label: '同意'
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
label: '不同意'
|
||||
}
|
||||
],
|
||||
statusFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, row.status)
|
||||
},
|
||||
leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
|
||||
leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS)
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
stepActive: function () {
|
||||
let idx = 0;
|
||||
for(let i=0; i<this.handleTask.historyTask.length; i++){
|
||||
if(this.handleTask.historyTask[i].status === 1){
|
||||
idx= idx+1;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
},
|
||||
stepTitle() {
|
||||
return function (item) {
|
||||
let name = item.stepName;
|
||||
if (item.status === 1) {
|
||||
name += '(已完成)'
|
||||
}
|
||||
if (item.status === 0) {
|
||||
name += '(进行中)'
|
||||
}
|
||||
return name;
|
||||
}
|
||||
},
|
||||
stepDes(){
|
||||
return function (item) {
|
||||
let desc = "";
|
||||
if (item.status === 1) {
|
||||
desc+="审批人:["+ item.assignee +"] 审批意见: [" + item.comment + "] 审批时间: " + this.parseTime(item.endTime);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const businessKey = this.$route.query.businessKey;
|
||||
const taskId = this.$route.query.taskId;
|
||||
this.leaveApprove.taskId = taskId;
|
||||
this.getForm(businessKey);
|
||||
},
|
||||
methods: {
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["taskForm"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
if (this.leaveApprove.approved == 1) {
|
||||
this.leaveApprove.variables["hrApproved"] = true;
|
||||
}
|
||||
if (this.leaveApprove.approved == 0) {
|
||||
this.leaveApprove.variables["hrApproved"] = false;
|
||||
}
|
||||
completeTask(this.leaveApprove).then(response => {
|
||||
this.msgSuccess("执行任务成功");
|
||||
this.$store.dispatch('tagsView/delView', this.$route).then(({ visitedViews }) => {
|
||||
//if (this.isActive(this.$route)) {
|
||||
this.$router.push({path: '/oa/todo'})
|
||||
//}
|
||||
})
|
||||
})
|
||||
});
|
||||
},
|
||||
getForm(id){
|
||||
getLeave(id).then(response => {
|
||||
this.form = response.data;
|
||||
});
|
||||
const data = {
|
||||
taskId : this.leaveApprove.taskId,
|
||||
businessKey: id,
|
||||
}
|
||||
taskSteps(data).then(response => {
|
||||
this.handleTask = response.data;
|
||||
|
||||
});
|
||||
},
|
||||
approveChange(){
|
||||
if (this.leaveApprove.approved === 1) {
|
||||
this.leaveApprove.comment = "同意"
|
||||
}
|
||||
if(this.leaveApprove.approved === 0){
|
||||
this.leaveApprove.comment = "不同意"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,190 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="任务处理">
|
||||
<el-form ref="form" :model="form" label-width="80px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-form-item label="申请人" >{{form.userId}}</el-form-item></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
{{ getDictDataLabel(DICT_TYPE.OA_LEAVE_TYPE, form.leaveType) }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6"><el-form-item label="原因" prop="reason">{{form.reason}}</el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-form-item label="开始时间" >{{ parseTime(form.startTime) }}</el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="结束时间" prop="endTime">{{ parseTime(form.endTime) }}</el-form-item></el-col>
|
||||
<el-form-item label="申请时间" prop="applyTime">{{ parseTime(form.applyTime) }}</el-form-item>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-divider></el-divider>
|
||||
<el-form ref="taskForm" :model="leaveApprove" :rules="rules" label-width="80px">
|
||||
<el-form-item label="是否同意" prop="approved">
|
||||
<el-select v-model="leaveApprove.approved" placeholder="是否同意" v-on:change="approveChange">
|
||||
<el-option
|
||||
v-for="dict in approvedData"
|
||||
:key="parseInt(dict.value)"
|
||||
:label="dict.label"
|
||||
:value="parseInt(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="处理意见" prop="comment">
|
||||
<el-col :span="11">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
v-model="leaveApprove.comment">
|
||||
</el-input>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="历史跟踪">
|
||||
<el-steps :active="stepActive" simple finish-status="success">
|
||||
<el-step :title="stepTitle(item)" icon="el-icon-edit" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
<br/>
|
||||
<el-steps direction="vertical" :active="stepActive" space="65px">
|
||||
<el-step :title="stepTitle(item)" :description="stepDes(item)" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="流程图">流程图-TODO</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLeave } from "@/api/oa/leave"
|
||||
import { completeTask,taskSteps } from "@/api/oa/todo";
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
export default {
|
||||
name: "ApproveLeaderLeave",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
comment: [{ required: true, message: "意见不能为空", trigger: "blur" }]
|
||||
},
|
||||
handleTask: {
|
||||
historyTask:[]
|
||||
},
|
||||
leaveApprove: {
|
||||
approved : 1,
|
||||
variables: {},
|
||||
taskId: "",
|
||||
comment: "同意"
|
||||
},
|
||||
approvedData: [
|
||||
{
|
||||
value: 1,
|
||||
label: '同意'
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
label: '不同意'
|
||||
}
|
||||
],
|
||||
statusFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, row.status)
|
||||
},
|
||||
leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
|
||||
leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS)
|
||||
};
|
||||
},
|
||||
created() {
|
||||
const businessKey = this.$route.query.businessKey;
|
||||
const taskId = this.$route.query.taskId;
|
||||
this.leaveApprove.taskId = taskId;
|
||||
this.getForm(businessKey);
|
||||
},
|
||||
computed:{
|
||||
stepActive: function () {
|
||||
let idx = 0;
|
||||
for(let i=0; i<this.handleTask.historyTask.length; i++){
|
||||
if(this.handleTask.historyTask[i].status === 1){
|
||||
idx= idx+1;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
},
|
||||
stepTitle() {
|
||||
return function (item) {
|
||||
let name = item.stepName;
|
||||
if (item.status === 1) {
|
||||
name += '(已完成)'
|
||||
}
|
||||
if (item.status === 0) {
|
||||
name += '(进行中)'
|
||||
}
|
||||
return name;
|
||||
}
|
||||
},
|
||||
stepDes(){
|
||||
return function (item) {
|
||||
let desc = "";
|
||||
if (item.status === 1) {
|
||||
desc+="审批人:["+ item.assignee +"] 审批意见: [" + item.comment + "] 审批时间: " + this.parseTime(item.endTime);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["taskForm"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
if (this.leaveApprove.approved == 1) {
|
||||
this.leaveApprove.variables["deptLeaderApproved"] = true;
|
||||
}
|
||||
if (this.leaveApprove.approved == 0) {
|
||||
this.leaveApprove.variables["deptLeaderApproved"] = false;
|
||||
}
|
||||
completeTask(this.leaveApprove).then(response => {
|
||||
this.msgSuccess("执行任务成功");
|
||||
this.$store.dispatch('tagsView/delView', this.$route).then(({ visitedViews }) => {
|
||||
//if (this.isActive(this.$route)) {
|
||||
this.$router.push({path: '/oa/todo'})
|
||||
//}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
getForm(id){
|
||||
getLeave(id).then(response => {
|
||||
this.form = response.data;
|
||||
});
|
||||
const data = {
|
||||
taskId : this.leaveApprove.taskId,
|
||||
businessKey: id,
|
||||
}
|
||||
taskSteps(data).then(response => {
|
||||
this.handleTask = response.data;
|
||||
|
||||
});
|
||||
},
|
||||
approveChange(){
|
||||
if (this.leaveApprove.approved === 1) {
|
||||
this.leaveApprove.comment = "同意"
|
||||
}
|
||||
if(this.leaveApprove.approved === 0){
|
||||
this.leaveApprove.comment = "不同意"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,137 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="任务处理">
|
||||
<el-form ref="form" :model="form" label-width="80px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-form-item label="申请人" >{{form.userId}}</el-form-item></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
{{ getDictDataLabel(DICT_TYPE.OA_LEAVE_TYPE, form.leaveType) }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6"><el-form-item label="原因" prop="reason">{{form.reason}}</el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-form-item label="开始时间" >{{ parseTime(form.startTime) }}</el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="结束时间" prop="endTime">{{ parseTime(form.endTime) }}</el-form-item></el-col>
|
||||
<el-form-item label="申请时间" prop="applyTime">{{ parseTime(form.applyTime) }}</el-form-item>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-button type="primary" @click="submitForm">确 定</el-button></el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="历史跟踪">
|
||||
<el-steps :active="stepActive" simple finish-status="success">
|
||||
<el-step :title="stepTitle(item)" icon="el-icon-edit" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
<br/>
|
||||
<el-steps direction="vertical" :active="stepActive" space="65px">
|
||||
<el-step :title="stepTitle(item)" :description="stepDes(item)" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="流程图">流程图-TODO</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLeave } from "@/api/oa/leave"
|
||||
import { completeTask,taskSteps } from "@/api/oa/todo";
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
export default {
|
||||
name: "ConfirmLeave",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
},
|
||||
handleTask: {
|
||||
historyTask:[]
|
||||
},
|
||||
leaveApprove: {
|
||||
variables: {},
|
||||
taskId: "",
|
||||
comment: ""
|
||||
},
|
||||
statusFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, row.status)
|
||||
},
|
||||
leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
|
||||
leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS)
|
||||
};
|
||||
},
|
||||
created() {
|
||||
const businessKey = this.$route.query.businessKey;
|
||||
const taskId = this.$route.query.taskId;
|
||||
this.leaveApprove.taskId = taskId;
|
||||
this.getForm(businessKey);
|
||||
},
|
||||
computed:{
|
||||
stepActive: function () {
|
||||
let idx = 0;
|
||||
for(let i=0; i<this.handleTask.historyTask.length; i++){
|
||||
if(this.handleTask.historyTask[i].status === 1){
|
||||
idx= idx+1;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
},
|
||||
stepTitle() {
|
||||
return function (item) {
|
||||
let name = item.stepName;
|
||||
if (item.status === 1) {
|
||||
name += '(已完成)'
|
||||
}
|
||||
if (item.status === 0) {
|
||||
name += '(进行中)'
|
||||
}
|
||||
return name;
|
||||
}
|
||||
},
|
||||
stepDes(){
|
||||
return function (item) {
|
||||
let desc = "";
|
||||
if (item.status === 1) {
|
||||
desc+="审批人:["+ item.assignee +"] 审批意见: [" + item.comment + "] 审批时间: " + this.parseTime(item.endTime);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
completeTask(this.leaveApprove).then(response => {
|
||||
this.msgSuccess("执行任务成功");
|
||||
this.$store.dispatch('tagsView/delView', this.$route).then(({ visitedViews }) => {
|
||||
//if (this.isActive(this.$route)) {
|
||||
this.$router.push({path: '/oa/todo'})
|
||||
//}
|
||||
})
|
||||
})
|
||||
},
|
||||
getForm(id){
|
||||
getLeave(id).then(response => {
|
||||
this.form = response.data;
|
||||
});
|
||||
const data = {
|
||||
taskId : this.leaveApprove.taskId,
|
||||
businessKey: id,
|
||||
}
|
||||
taskSteps(data).then(response => {
|
||||
this.handleTask = response.data;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,377 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="流程id" prop="processInstanceId">
|
||||
<el-input v-model="queryParams.processInstanceId" placeholder="请输入流程id" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态">
|
||||
<el-option
|
||||
v-for="dict in leaveStatusData"
|
||||
:key="parseInt(dict.value)"
|
||||
:label="dict.label"
|
||||
:value="parseInt(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始时间">
|
||||
<el-date-picker v-model="dateRangeStartTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间">
|
||||
<el-date-picker v-model="dateRangeEndTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
<el-select v-model="queryParams.leaveType" placeholder="请选择请假类型">
|
||||
<el-option
|
||||
v-for="dict in leaveTypeDictData"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="原因" prop="reason">
|
||||
<el-input v-model="queryParams.reason" placeholder="请输入原因" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请时间">
|
||||
<el-date-picker v-model="dateRangeApplyTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="请假表单主键" align="center" prop="id" />
|
||||
<el-table-column label="状态" align="center" prop="status" :formatter="statusFormat" />
|
||||
<el-table-column label="申请人id" align="center" prop="userId" />
|
||||
<el-table-column label="开始时间" align="center" prop="startTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.startTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束时间" align="center" prop="endTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.endTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="请假类型" align="center" prop="leaveType" :formatter="leaveTypeFormat" />
|
||||
<el-table-column label="原因" align="center" prop="reason" />
|
||||
<el-table-column label="申请时间" align="center" prop="applyTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.applyTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleStep(scope.row)">审批进度</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleDetail(scope.row)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="开始时间" prop="startTime">
|
||||
<el-date-picker clearable size="small" v-model="form.startTime" type="date" value-format="timestamp" placeholder="选择开始时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间" prop="endTime">
|
||||
<el-date-picker clearable size="small" v-model="form.endTime" type="date" value-format="timestamp" placeholder="选择结束时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
<el-select v-model="form.leaveType" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in leaveTypeDictData"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="原因" prop="reason">
|
||||
<el-input v-model="form.reason" placeholder="请输入原因" />
|
||||
</el-form-item>
|
||||
<el-form-item label="申请时间" prop="applyTime">
|
||||
<el-date-picker clearable size="small" v-model="form.applyTime" type="date" value-format="timestamp" placeholder="选择申请时间" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :title="title" :visible.sync="dialogDetailVisible" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" label-width="80px">
|
||||
<el-form-item label="状态" >
|
||||
{{ getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, form.status) }}
|
||||
</el-form-item>
|
||||
<el-form-item label="申请人id" >{{form.userId}}</el-form-item>
|
||||
<el-form-item label="开始时间" >{{ parseTime(form.startTime) }}</el-form-item>
|
||||
<el-form-item label="结束时间" prop="endTime">{{ parseTime(form.endTime) }}</el-form-item>
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
{{ getDictDataLabel(DICT_TYPE.OA_LEAVE_TYPE, form.leaveType) }}
|
||||
</el-form-item>
|
||||
<el-form-item label="原因" prop="reason">{{form.reason}}</el-form-item>
|
||||
<el-form-item label="申请时间" prop="applyTime">{{ parseTime(form.applyTime) }}</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="dialogDetailVisible = false">确 定</el-button>
|
||||
<el-button @click="dialogDetailVisible = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :title="title" :visible.sync="dialogStepsVisible" width="600px" append-to-body>
|
||||
<el-steps :active="stepActive" finish-status="success" >
|
||||
<el-step :title="stepTitle(item)" :description="' 办理人:' + item.assignee " icon="el-icon-edit" v-for="(item) in handleTask.historyTask"></el-step>
|
||||
</el-steps>
|
||||
<br/>
|
||||
<el-steps direction="vertical" :active="stepActive">
|
||||
<el-step :title="stepTitle(item)" :description="stepDes(item)" v-for="(item) in handleTask.historyTask"></el-step>
|
||||
</el-steps>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="dialogStepsVisible = false">确 定</el-button>
|
||||
<el-button @click="dialogStepsVisible = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createLeave, updateLeave, deleteLeave, getLeave, getLeavePage, exportLeaveExcel } from "@/api/oa/leave"
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
import { processHistorySteps } from '@/api/oa/todo'
|
||||
export default {
|
||||
name: "Leave",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 请假申请列表
|
||||
list: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
//进度弹出层
|
||||
dialogDetailVisible: false,
|
||||
//审批进度弹出层
|
||||
dialogStepsVisible: false,
|
||||
dateRangeStartTime: [],
|
||||
dateRangeEndTime: [],
|
||||
dateRangeApplyTime: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
processInstanceId: null,
|
||||
status: null,
|
||||
userId: null,
|
||||
leaveType: null,
|
||||
reason: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
handleTask: {
|
||||
historyTask:[],
|
||||
taskVariable: "",
|
||||
formObject: {}
|
||||
},
|
||||
steps:[{
|
||||
stepName:"步骤一"
|
||||
}],
|
||||
// 表单校验
|
||||
rules: {
|
||||
startTime: [{ required: true, message: "开始时间不能为空", trigger: "blur" }],
|
||||
endTime: [{ required: true, message: "结束时间不能为空", trigger: "blur" }],
|
||||
applyTime: [{ required: true, message: "申请时间不能为空", trigger: "blur" }],
|
||||
},
|
||||
statusFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, row.status)
|
||||
},
|
||||
leaveTypeFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.OA_LEAVE_TYPE, row.leaveType)
|
||||
},
|
||||
leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
|
||||
leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS)
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
computed: {
|
||||
stepActive: function () {
|
||||
let idx = 0;
|
||||
for (let i = 0; i < this.handleTask.historyTask.length; i++) {
|
||||
if (this.handleTask.historyTask[i].status === 1) {
|
||||
idx = idx + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
},
|
||||
stepTitle() {
|
||||
return function (item) {
|
||||
let name = item.stepName;
|
||||
if (item.status === 1) {
|
||||
name += '(已完成)'
|
||||
}
|
||||
if (item.status === 0) {
|
||||
name += '(进行中)'
|
||||
}
|
||||
return name;
|
||||
}
|
||||
},
|
||||
stepDes() {
|
||||
return function (item) {
|
||||
let desc = "";
|
||||
if (item.status === 1) {
|
||||
desc += "审批人:[" + item.assignee + "] 审批意见: [" + item.comment + "] 审批时间: " + this.parseTime(item.endTime);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
this.addBeginAndEndTime(params, this.dateRangeStartTime, 'startTime');
|
||||
this.addBeginAndEndTime(params, this.dateRangeEndTime, 'endTime');
|
||||
this.addBeginAndEndTime(params, this.dateRangeApplyTime, 'applyTime');
|
||||
// 执行查询
|
||||
getLeavePage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
processInstanceId: undefined,
|
||||
status: undefined,
|
||||
userId: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
leaveType: undefined,
|
||||
reason: undefined,
|
||||
applyTime: undefined,
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeStartTime = [];
|
||||
this.dateRangeEndTime = [];
|
||||
this.dateRangeApplyTime = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加请假申请";
|
||||
},
|
||||
/** 详情按钮操作 */
|
||||
handleDetail(row) {
|
||||
this.reset();
|
||||
const id = row.id;
|
||||
getLeave(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.dialogDetailVisible = true
|
||||
this.title = "请假详情";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 修改的提交
|
||||
if (this.form.id != null) {
|
||||
updateLeave(this.form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 添加的提交
|
||||
createLeave(this.form).then(response => {
|
||||
this.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 审批进度 */
|
||||
handleStep(row) {
|
||||
const id = row.processInstanceId;
|
||||
processHistorySteps(id).then(response => {
|
||||
this.handleTask.historyTask = response.data;
|
||||
this.dialogStepsVisible = true
|
||||
this.title = "审批进度";
|
||||
});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
params.pageNo = undefined;
|
||||
params.pageSize = undefined;
|
||||
this.addBeginAndEndTime(params, this.dateRangeStartTime, 'startTime');
|
||||
this.addBeginAndEndTime(params, this.dateRangeEndTime, 'endTime');
|
||||
this.addBeginAndEndTime(params, this.dateRangeApplyTime, 'applyTime');
|
||||
// 执行导出
|
||||
this.$confirm('是否确认导出所有请假申请数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return exportLeaveExcel(params);
|
||||
}).then(response => {
|
||||
this.downloadExcel(response, '请假申请.xls');
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,211 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="任务处理">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row>
|
||||
<el-col :span="15">
|
||||
<el-form-item label="是否调整申请" prop="reApply">
|
||||
<el-select v-model="reApplySelect" placeholder="是否调整申请" v-on:change="reApplyChange">
|
||||
<el-option
|
||||
v-for="dict in reApplyData"
|
||||
:key="parseInt(dict.value)"
|
||||
:label="dict.label"
|
||||
:value="parseInt(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" v-show="modifyShow">
|
||||
<el-col :span="8"><el-form-item label="申请人" >{{form.userId}}</el-form-item></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="申请时间" prop="applyTime">{{ parseTime(form.applyTime) }}</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" v-show="modifyShow">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="开始时间" prop="startTime">
|
||||
<el-date-picker clearable size="small" v-model="form.startTime" type="date" value-format="timestamp" placeholder="选择开始时间" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="结束时间" prop="endTime">
|
||||
<el-date-picker clearable size="small" v-model="form.endTime" type="date" value-format="timestamp" placeholder="选择结束时间" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-show="modifyShow" >
|
||||
<el-col :span="8">
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
<el-select v-model="form.leaveType" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in leaveTypeDictData"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-show="modifyShow">
|
||||
<el-col :span="15">
|
||||
<el-form-item label="原因" prop="reason">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
v-model="form.reason"
|
||||
placeholder="请输入原因" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="历史跟踪">
|
||||
<el-steps :active="stepActive" simple finish-status="success">
|
||||
<el-step :title="stepTitle(item)" icon="el-icon-edit" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
<br/>
|
||||
<el-steps direction="vertical" :active="stepActive" space="65px">
|
||||
<el-step :title="stepTitle(item)" :description="stepDes(item)" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="流程图">流程图-TODO</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLeave,updateLeave } from "@/api/oa/leave"
|
||||
import { taskSteps } from "@/api/oa/todo"
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
export default {
|
||||
name: "HrApproveLeave",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
},
|
||||
handleTask: {
|
||||
historyTask:[]
|
||||
},
|
||||
modifyShow: true,
|
||||
reApplySelect: 1,
|
||||
reApplyData: [
|
||||
{
|
||||
value: 0,
|
||||
label: '取消申请'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '继续申请'
|
||||
}
|
||||
],
|
||||
statusFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, row.status)
|
||||
},
|
||||
leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
|
||||
leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS)
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const businessKey = this.$route.query.businessKey;
|
||||
const taskId = this.$route.query.taskId;
|
||||
|
||||
this.getForm(businessKey,taskId);
|
||||
},
|
||||
computed:{
|
||||
stepActive: function () {
|
||||
let idx = 0;
|
||||
for(let i=0; i<this.handleTask.historyTask.length; i++){
|
||||
if(this.handleTask.historyTask[i].status === 1){
|
||||
idx= idx+1;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
},
|
||||
stepTitle() {
|
||||
return function (item) {
|
||||
let name = item.stepName;
|
||||
if (item.status === 1) {
|
||||
name += '(已完成)'
|
||||
}
|
||||
if (item.status === 0) {
|
||||
name += '(进行中)'
|
||||
}
|
||||
return name;
|
||||
}
|
||||
},
|
||||
stepDes(){
|
||||
return function (item) {
|
||||
let desc = "";
|
||||
if (item.status === 1) {
|
||||
desc+="审批人:["+ item.assignee +"] 审批意见: [" + item.comment + "] 审批时间: " + this.parseTime(item.endTime);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
if (this.reApplySelect === 1) {
|
||||
this.form.variables["reApply"] = true;
|
||||
this.form.comment = '调整请假申请';
|
||||
}
|
||||
if (this.reApplySelect === 0) {
|
||||
this.form.variables["reApply"] = false;
|
||||
this.form.comment = '取消请假申请';
|
||||
}
|
||||
updateLeave(this.form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.$store.dispatch('tagsView/delView', this.$route).then(({ visitedViews }) => {
|
||||
//if (this.isActive(this.$route)) {
|
||||
this.$router.push({path: '/oa/todo'})
|
||||
//}
|
||||
})
|
||||
});
|
||||
});
|
||||
},
|
||||
getForm(id, taskId){
|
||||
getLeave(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.form.taskId = taskId;
|
||||
this.form.variables = {};
|
||||
});
|
||||
const data = {
|
||||
taskId : taskId,
|
||||
businessKey: id,
|
||||
}
|
||||
taskSteps(data).then(response => {
|
||||
this.handleTask = response.data;
|
||||
|
||||
});
|
||||
},
|
||||
reApplyChange(){
|
||||
if (this.reApplySelect === 1) {
|
||||
this.modifyShow = true;
|
||||
}
|
||||
if (this.reApplySelect === 0) {
|
||||
this.modifyShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,303 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态">
|
||||
<el-option
|
||||
v-for="dict in leaveStatusData"
|
||||
:key="parseInt(dict.value)"
|
||||
:label="dict.label"
|
||||
:value="parseInt(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="任务Id" align="center" prop="id" />
|
||||
<el-table-column label="流程名称" align="center" prop="processName" />
|
||||
<el-table-column label="任务状态" align="center" :formatter="statusFormat" prop="status" />
|
||||
<!-- <el-table-column label="申请人id" align="center" prop="userId" />-->
|
||||
<!-- <el-table-column label="开始时间" align="center" prop="startTime" width="180">-->
|
||||
<!-- <template slot-scope="scope">-->
|
||||
<!-- <span>{{ parseTime(scope.row.startTime) }}</span>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- <el-table-column label="结束时间" align="center" prop="endTime" width="180">-->
|
||||
<!-- <template slot-scope="scope">-->
|
||||
<!-- <span>{{ parseTime(scope.row.endTime) }}</span>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- <el-table-column label="请假类型" align="center" prop="leaveType" />-->
|
||||
<!-- <el-table-column label="原因" align="center" prop="reason" />-->
|
||||
<!-- <el-table-column label="申请时间" align="center" prop="applyTime" width="180">-->
|
||||
<!-- <template slot-scope="scope">-->
|
||||
<!-- <span>{{ parseTime(scope.row.applyTime) }}</span>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.status == 1" @click="handleClaim(scope.row)">签收</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.status == 2" @click="getTaskFormKey(scope.row)">办理</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
|
||||
<el-tabs tab-position="left" style="height: 500px;">
|
||||
<el-tab-pane label="详情">
|
||||
<el-form ref="form" :model="handleTask.formObject" label-width="80px">
|
||||
<el-form-item label="状态" >
|
||||
{{ getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, handleTask.formObject.status) }}
|
||||
</el-form-item>
|
||||
<el-form-item label="申请人id" >{{handleTask.formObject.userId}}</el-form-item>
|
||||
<el-form-item label="开始时间" >{{ parseTime(handleTask.formObject.startTime) }}</el-form-item>
|
||||
<el-form-item label="结束时间" prop="endTime">{{ parseTime(handleTask.formObject.endTime) }}</el-form-item>
|
||||
<el-form-item label="请假类型" prop="leaveType">
|
||||
{{ getDictDataLabel(DICT_TYPE.OA_LEAVE_TYPE, handleTask.formObject.leaveType) }}
|
||||
</el-form-item>
|
||||
<el-form-item label="原因" prop="reason">{{handleTask.formObject.reason}}</el-form-item>
|
||||
<el-form-item label="申请时间" prop="applyTime">{{ parseTime(handleTask.formObject.applyTime) }}</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="任务处理">
|
||||
<el-steps :active="handleTask.historyTask.length-1" simple finish-status="success">
|
||||
<el-step :title="item.stepName" icon="el-icon-edit" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
<br/>
|
||||
<el-steps direction="vertical" :active="handleTask.historyTask.length-1" finish-status="success" space="60px">
|
||||
<el-step :title="item.stepName" :description="item.comment" v-for="(item) in handleTask.historyTask" ></el-step>
|
||||
</el-steps>
|
||||
<br/>
|
||||
<el-form ref="taskForm" :model="task" label-width="80px" v-show="handleTask.taskVariable !=''">
|
||||
<el-form-item label="处理意见" prop="approved">
|
||||
<el-select v-model="task.approved" placeholder="处理意见">
|
||||
<el-option
|
||||
v-for="dict in approvedData"
|
||||
:key="parseInt(dict.value)"
|
||||
:label="dict.label"
|
||||
:value="parseInt(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
v-model="task.comment">
|
||||
</el-input>
|
||||
</el-form>
|
||||
<br/>
|
||||
<el-button type="primary" @click="submitTask">提交</el-button>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { completeTask, taskSteps, getTaskFormKey,deleteLeave, getLeave, getTodoTaskPage, claimTask } from "@/api/oa/todo";
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
export default {
|
||||
name: "Todo",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 请假申请列表
|
||||
list: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
handleTask: {
|
||||
historyTask:[{
|
||||
stepName:"步骤一"
|
||||
}
|
||||
],
|
||||
taskVariable: "",
|
||||
formObject: {}
|
||||
},
|
||||
steps:[{
|
||||
stepName:"步骤一"
|
||||
}],
|
||||
task: {
|
||||
approved : 1,
|
||||
variables: {},
|
||||
taskId: undefined,
|
||||
comment: ""
|
||||
},
|
||||
rules: {
|
||||
},
|
||||
leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
|
||||
leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS),
|
||||
approvedData: [
|
||||
{
|
||||
value: 1,
|
||||
label: '同意'
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
label: '不同意'
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
// 执行查询
|
||||
getTodoTaskPage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
processInstanceId: undefined,
|
||||
status: undefined,
|
||||
userId: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
leaveType: undefined,
|
||||
reason: undefined,
|
||||
applyTime: undefined,
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
|
||||
statusFormat(row, column) {
|
||||
return row.status == 1 ? "未签收" : "已签收";
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeStartTime = [];
|
||||
this.dateRangeEndTime = [];
|
||||
this.dateRangeApplyTime = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
getTaskFormKey(row) {
|
||||
const taskId = row.id;
|
||||
const data = {
|
||||
taskId : taskId
|
||||
}
|
||||
getTaskFormKey(data).then(response => {
|
||||
const resp = response.data;
|
||||
const path = resp.formKey;
|
||||
const taskId = resp.id;
|
||||
const businessKey = resp.businessKey;
|
||||
const route = {
|
||||
path: path,
|
||||
query: {
|
||||
businessKey: businessKey,
|
||||
taskId:taskId
|
||||
}
|
||||
}
|
||||
this.$router.replace(route);
|
||||
});
|
||||
},
|
||||
handleLeaveApprove(row) {
|
||||
this.reset();
|
||||
const businessKey = row.businessKey;
|
||||
const taskId = row.id;
|
||||
const processKey = row.processKey;
|
||||
const data = {
|
||||
taskId : taskId,
|
||||
businessKey: businessKey,
|
||||
processKey: processKey
|
||||
}
|
||||
taskSteps(data).then(response => {
|
||||
this.form = {};
|
||||
this.handleTask = response.data;
|
||||
this.task.taskId = taskId;
|
||||
this.open = true;
|
||||
this.title = "任务办理";
|
||||
});
|
||||
},
|
||||
/** 任务签收操作 */
|
||||
handleClaim(row) {
|
||||
this.reset();
|
||||
const id = row.id;
|
||||
claimTask(id).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("签收成功");
|
||||
});
|
||||
},
|
||||
/** 提交任务 */
|
||||
submitTask() {
|
||||
const taskVariableName = this.handleTask.taskVariable;
|
||||
if (taskVariableName != "") {
|
||||
if (this.task.approved == 1) {
|
||||
this.task.variables[taskVariableName] = true;
|
||||
}
|
||||
if (this.task.approved == 0) {
|
||||
this.task.variables[taskVariableName] = false;
|
||||
}
|
||||
}
|
||||
completeTask(this.task).then(response => {
|
||||
this.msgSuccess("执行任务成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
})
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const id = row.id;
|
||||
this.$confirm('是否确认删除请假申请编号为"' + id + '"的数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return deleteLeave(id);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("删除成功");
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -25,8 +25,9 @@
|
||||
<el-table v-loading="loading" :data="deptList" row-key="id" default-expand-all
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
|
||||
<el-table-column prop="name" label="部门名称" width="260"></el-table-column>
|
||||
<el-table-column prop="status" label="负责人" :formatter="userNicknameFormat" width="120"/>
|
||||
<el-table-column prop="sort" label="排序" width="200"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" :formatter="statusFormat" width="100"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" :formatter="statusFormat" width="100"/>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="200">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
@@ -64,8 +65,10 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="负责人" prop="leader">
|
||||
<el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
|
||||
<el-form-item label="负责人" prop="leaderUserId">
|
||||
<el-select v-model="form.leaderUserId" placeholder="请输入负责人" clearable style="width: 100%">
|
||||
<el-option v-for="item in users" :key="parseInt(item.id)" :label="item.nickname" :value="parseInt(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -103,6 +106,7 @@ import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||
|
||||
import {SysCommonStatusEnum} from '@/utils/constants'
|
||||
import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
|
||||
import {listSimpleUsers} from "@/api/system/user";
|
||||
|
||||
export default {
|
||||
name: "Dept",
|
||||
@@ -117,6 +121,8 @@ export default {
|
||||
deptList: [],
|
||||
// 部门树选项
|
||||
deptOptions: [],
|
||||
// 用户下拉列表
|
||||
users: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
@@ -168,6 +174,10 @@ export default {
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
// 获得用户列表
|
||||
listSimpleUsers().then(response => {
|
||||
this.users = response.data;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
/** 查询部门列表 */
|
||||
@@ -193,6 +203,18 @@ export default {
|
||||
statusFormat(row, column) {
|
||||
return getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, row.status)
|
||||
},
|
||||
// 用户昵称展示
|
||||
userNicknameFormat(row, column) {
|
||||
if (!row.leaderUserId) {
|
||||
return '未设置';
|
||||
}
|
||||
for (const user of this.users) {
|
||||
if (row.leaderUserId === user.id) {
|
||||
return user.nickname;
|
||||
}
|
||||
}
|
||||
return '未知【' + row.leaderUserId + '】';
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
@@ -205,7 +227,7 @@ export default {
|
||||
parentId: undefined,
|
||||
name: undefined,
|
||||
sort: undefined,
|
||||
leader: undefined,
|
||||
leaderUserId: undefined,
|
||||
phone: undefined,
|
||||
email: undefined,
|
||||
status: SysCommonStatusEnum.ENABLE,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<el-table v-loading="loading" :data="menuList" row-key="id"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
|
||||
<el-table-column prop="name" label="菜单名称" :show-overflow-tooltip="true" width="200"></el-table-column>
|
||||
<el-table-column prop="name" label="菜单名称" :show-overflow-tooltip="true" width="250"></el-table-column>
|
||||
<el-table-column prop="icon" label="图标" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<svg-icon :icon-class="scope.row.icon" />
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="large" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['system:role:update']">修改</el-button>
|
||||
v-hasPermi="['system:user:update']">修改</el-button>
|
||||
<el-dropdown @command="(command) => handleCommand(command, scope.$index, scope.row)">
|
||||
<span class="el-dropdown-link">
|
||||
更多操作<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
|
||||
22
yudao-admin-ui/src/views/tool/build/App.vue
Normal file
22
yudao-admin-ui/src/views/tool/build/App.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
// 取消开始的loading动画
|
||||
const preLoader = document.querySelector('#pre-loader')
|
||||
preLoader.style.display = 'none'
|
||||
|
||||
// fix: firefox 下 拖拽 会新打卡一个选项卡
|
||||
// https://github.com/JakHuang/form-generator/issues/15
|
||||
document.body.ondrop = event => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -104,3 +104,7 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import render from '@/utils/generator/render'
|
||||
import render from '@/components/render/render'
|
||||
|
||||
const components = {
|
||||
itemBtns(h, element, index, parent) {
|
||||
itemBtns(h, currentItem, index, list) {
|
||||
const { copyItem, deleteItem } = this.$listeners
|
||||
return [
|
||||
<span class="drawing-item-copy" title="复制" onClick={event => {
|
||||
copyItem(element, parent); event.stopPropagation()
|
||||
copyItem(currentItem, list); event.stopPropagation()
|
||||
}}>
|
||||
<i class="el-icon-copy-document" />
|
||||
</span>,
|
||||
<span class="drawing-item-delete" title="删除" onClick={event => {
|
||||
deleteItem(index, parent); event.stopPropagation()
|
||||
deleteItem(index, list); event.stopPropagation()
|
||||
}}>
|
||||
<i class="el-icon-delete" />
|
||||
</span>
|
||||
@@ -20,60 +20,80 @@ const components = {
|
||||
}
|
||||
}
|
||||
const layouts = {
|
||||
colFormItem(h, element, index, parent) {
|
||||
colFormItem(h, currentItem, index, list) {
|
||||
const { activeItem } = this.$listeners
|
||||
let className = this.activeId === element.formId ? 'drawing-item active-from-item' : 'drawing-item'
|
||||
const config = currentItem.__config__
|
||||
const child = renderChildren.apply(this, arguments)
|
||||
let className = this.activeId === config.formId ? 'drawing-item active-from-item' : 'drawing-item'
|
||||
if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
|
||||
let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
|
||||
if (config.showLabel === false) labelWidth = '0'
|
||||
return (
|
||||
<el-col span={element.span} class={className}
|
||||
nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
|
||||
<el-form-item label-width={element.labelWidth ? `${element.labelWidth}px` : null}
|
||||
label={element.label} required={element.required}>
|
||||
<render key={element.renderKey} conf={element} onInput={ event => {
|
||||
this.$set(element, 'defaultValue', event)
|
||||
}} />
|
||||
<el-col span={config.span} class={className}
|
||||
nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
|
||||
<el-form-item label-width={labelWidth}
|
||||
label={config.showLabel ? config.label : ''} required={config.required}>
|
||||
<render key={config.renderKey} conf={currentItem} onInput={ event => {
|
||||
this.$set(config, 'defaultValue', event)
|
||||
}}>
|
||||
{child}
|
||||
</render>
|
||||
</el-form-item>
|
||||
{components.itemBtns.apply(this, arguments)}
|
||||
</el-col>
|
||||
)
|
||||
},
|
||||
rowFormItem(h, element, index, parent) {
|
||||
rowFormItem(h, currentItem, index, list) {
|
||||
const { activeItem } = this.$listeners
|
||||
const className = this.activeId === element.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item'
|
||||
const config = currentItem.__config__
|
||||
const className = this.activeId === config.formId
|
||||
? 'drawing-row-item active-from-item'
|
||||
: 'drawing-row-item'
|
||||
let child = renderChildren.apply(this, arguments)
|
||||
if (element.type === 'flex') {
|
||||
child = <el-row type={element.type} justify={element.justify} align={element.align}>
|
||||
if (currentItem.type === 'flex') {
|
||||
child = <el-row type={currentItem.type} justify={currentItem.justify} align={currentItem.align}>
|
||||
{child}
|
||||
</el-row>
|
||||
}
|
||||
return (
|
||||
<el-col span={element.span}>
|
||||
<el-row gutter={element.gutter} class={className}
|
||||
nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
|
||||
<span class="component-name">{element.componentName}</span>
|
||||
<draggable list={element.children} animation={340} group="componentsGroup" class="drag-wrapper">
|
||||
<el-col span={config.span}>
|
||||
<el-row gutter={config.gutter} class={className}
|
||||
nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
|
||||
<span class="component-name">{config.componentName}</span>
|
||||
<draggable list={config.children || []} animation={340}
|
||||
group="componentsGroup" class="drag-wrapper">
|
||||
{child}
|
||||
</draggable>
|
||||
{components.itemBtns.apply(this, arguments)}
|
||||
</el-row>
|
||||
</el-col>
|
||||
)
|
||||
},
|
||||
raw(h, currentItem, index, list) {
|
||||
const config = currentItem.__config__
|
||||
const child = renderChildren.apply(this, arguments)
|
||||
return <render key={config.renderKey} conf={currentItem} onInput={ event => {
|
||||
this.$set(config, 'defaultValue', event)
|
||||
}}>
|
||||
{child}
|
||||
</render>
|
||||
}
|
||||
}
|
||||
|
||||
function renderChildren(h, element, index, parent) {
|
||||
if (!Array.isArray(element.children)) return null
|
||||
return element.children.map((el, i) => {
|
||||
const layout = layouts[el.layout]
|
||||
function renderChildren(h, currentItem, index, list) {
|
||||
const config = currentItem.__config__
|
||||
if (!Array.isArray(config.children)) return null
|
||||
return config.children.map((el, i) => {
|
||||
const layout = layouts[el.__config__.layout]
|
||||
if (layout) {
|
||||
return layout.call(this, h, el, i, element.children)
|
||||
return layout.call(this, h, el, i, config.children)
|
||||
}
|
||||
return layoutIsNotFound()
|
||||
return layoutIsNotFound.call(this)
|
||||
})
|
||||
}
|
||||
|
||||
function layoutIsNotFound() {
|
||||
throw new Error(`没有与${this.element.layout}匹配的layout`)
|
||||
throw new Error(`没有与${this.currentItem.__config__.layout}匹配的layout`)
|
||||
}
|
||||
|
||||
export default {
|
||||
@@ -82,19 +102,19 @@ export default {
|
||||
draggable
|
||||
},
|
||||
props: [
|
||||
'element',
|
||||
'currentItem',
|
||||
'index',
|
||||
'drawingList',
|
||||
'activeId',
|
||||
'formConf'
|
||||
],
|
||||
render(h) {
|
||||
const layout = layouts[this.element.layout]
|
||||
const layout = layouts[this.currentItem.__config__.layout]
|
||||
|
||||
if (layout) {
|
||||
return layout.call(this, h, this.element, this.index, this.drawingList)
|
||||
return layout.call(this, h, this.currentItem, this.index, this.drawingList)
|
||||
}
|
||||
return layoutIsNotFound()
|
||||
return layoutIsNotFound.call(this)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
332
yudao-admin-ui/src/views/tool/build/FormDrawer.vue
Normal file
332
yudao-admin-ui/src/views/tool/build/FormDrawer.vue
Normal file
@@ -0,0 +1,332 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-bind="$attrs" v-on="$listeners" @opened="onOpen" @close="onClose">
|
||||
<div style="height:100%">
|
||||
<el-row style="height:100%;overflow:auto">
|
||||
<el-col :md="24" :lg="12" class="left-editor">
|
||||
<div class="setting" title="资源引用" @click="showResource">
|
||||
<el-badge :is-dot="!!resources.length" class="item">
|
||||
<i class="el-icon-setting" />
|
||||
</el-badge>
|
||||
</div>
|
||||
<el-tabs v-model="activeTab" type="card" class="editor-tabs">
|
||||
<el-tab-pane name="html">
|
||||
<span slot="label">
|
||||
<i v-if="activeTab==='html'" class="el-icon-edit" />
|
||||
<i v-else class="el-icon-document" />
|
||||
template
|
||||
</span>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="js">
|
||||
<span slot="label">
|
||||
<i v-if="activeTab==='js'" class="el-icon-edit" />
|
||||
<i v-else class="el-icon-document" />
|
||||
script
|
||||
</span>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="css">
|
||||
<span slot="label">
|
||||
<i v-if="activeTab==='css'" class="el-icon-edit" />
|
||||
<i v-else class="el-icon-document" />
|
||||
css
|
||||
</span>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div v-show="activeTab==='html'" id="editorHtml" class="tab-editor" />
|
||||
<div v-show="activeTab==='js'" id="editorJs" class="tab-editor" />
|
||||
<div v-show="activeTab==='css'" id="editorCss" class="tab-editor" />
|
||||
</el-col>
|
||||
<el-col :md="24" :lg="12" class="right-preview">
|
||||
<div class="action-bar" :style="{'text-align': 'left'}">
|
||||
<span class="bar-btn" @click="runCode">
|
||||
<i class="el-icon-refresh" />
|
||||
刷新
|
||||
</span>
|
||||
<span class="bar-btn" @click="exportFile">
|
||||
<i class="el-icon-download" />
|
||||
导出vue文件
|
||||
</span>
|
||||
<span ref="copyBtn" class="bar-btn copy-btn">
|
||||
<i class="el-icon-document-copy" />
|
||||
复制代码
|
||||
</span>
|
||||
<span class="bar-btn delete-btn" @click="$emit('update:visible', false)">
|
||||
<i class="el-icon-circle-close" />
|
||||
关闭
|
||||
</span>
|
||||
</div>
|
||||
<iframe
|
||||
v-show="isIframeLoaded"
|
||||
ref="previewPage"
|
||||
class="result-wrapper"
|
||||
frameborder="0"
|
||||
src="preview.html"
|
||||
@load="iframeLoad"
|
||||
/>
|
||||
<div v-show="!isIframeLoaded" v-loading="true" class="result-wrapper" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-drawer>
|
||||
<resource-dialog
|
||||
:visible.sync="resourceVisible"
|
||||
:origin-resource="resources"
|
||||
@save="setResource"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { parse } from '@babel/parser'
|
||||
import ClipboardJS from 'clipboard'
|
||||
import { saveAs } from 'file-saver'
|
||||
import {
|
||||
makeUpHtml, vueTemplate, vueScript, cssStyle
|
||||
} from '@/components/generator/html'
|
||||
import { makeUpJs } from '@/components/generator/js'
|
||||
import { makeUpCss } from '@/components/generator/css'
|
||||
import { exportDefault, beautifierConf, titleCase } from '@/utils/index'
|
||||
import ResourceDialog from './ResourceDialog'
|
||||
import loadMonaco from '@/utils/loadMonaco'
|
||||
import loadBeautifier from '@/utils/loadBeautifier'
|
||||
|
||||
const editorObj = {
|
||||
html: null,
|
||||
js: null,
|
||||
css: null
|
||||
}
|
||||
const mode = {
|
||||
html: 'html',
|
||||
js: 'javascript',
|
||||
css: 'css'
|
||||
}
|
||||
let beautifier
|
||||
let monaco
|
||||
|
||||
export default {
|
||||
components: { ResourceDialog },
|
||||
props: ['formData', 'generateConf'],
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'html',
|
||||
htmlCode: '',
|
||||
jsCode: '',
|
||||
cssCode: '',
|
||||
codeFrame: '',
|
||||
isIframeLoaded: false,
|
||||
isInitcode: false, // 保证open后两个异步只执行一次runcode
|
||||
isRefreshCode: false, // 每次打开都需要重新刷新代码
|
||||
resourceVisible: false,
|
||||
scripts: [],
|
||||
links: [],
|
||||
monaco: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
resources() {
|
||||
return this.scripts.concat(this.links)
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
created() {
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('keydown', this.preventDefaultSave)
|
||||
const clipboard = new ClipboardJS('.copy-btn', {
|
||||
text: trigger => {
|
||||
const codeStr = this.generateCode()
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '代码已复制到剪切板,可粘贴。',
|
||||
type: 'success'
|
||||
})
|
||||
return codeStr
|
||||
}
|
||||
})
|
||||
clipboard.on('error', e => {
|
||||
this.$message.error('代码复制失败')
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keydown', this.preventDefaultSave)
|
||||
},
|
||||
methods: {
|
||||
preventDefaultSave(e) {
|
||||
if (e.key === 's' && (e.metaKey || e.ctrlKey)) {
|
||||
e.preventDefault()
|
||||
}
|
||||
},
|
||||
onOpen() {
|
||||
const { type } = this.generateConf
|
||||
this.htmlCode = makeUpHtml(this.formData, type)
|
||||
this.jsCode = makeUpJs(this.formData, type)
|
||||
this.cssCode = makeUpCss(this.formData)
|
||||
|
||||
loadBeautifier(btf => {
|
||||
beautifier = btf
|
||||
this.htmlCode = beautifier.html(this.htmlCode, beautifierConf.html)
|
||||
this.jsCode = beautifier.js(this.jsCode, beautifierConf.js)
|
||||
this.cssCode = beautifier.css(this.cssCode, beautifierConf.html)
|
||||
|
||||
loadMonaco(val => {
|
||||
monaco = val
|
||||
this.setEditorValue('editorHtml', 'html', this.htmlCode)
|
||||
this.setEditorValue('editorJs', 'js', this.jsCode)
|
||||
this.setEditorValue('editorCss', 'css', this.cssCode)
|
||||
if (!this.isInitcode) {
|
||||
this.isRefreshCode = true
|
||||
this.isIframeLoaded && (this.isInitcode = true) && this.runCode()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
onClose() {
|
||||
this.isInitcode = false
|
||||
this.isRefreshCode = false
|
||||
},
|
||||
iframeLoad() {
|
||||
if (!this.isInitcode) {
|
||||
this.isIframeLoaded = true
|
||||
this.isRefreshCode && (this.isInitcode = true) && this.runCode()
|
||||
}
|
||||
},
|
||||
setEditorValue(id, type, codeStr) {
|
||||
if (editorObj[type]) {
|
||||
editorObj[type].setValue(codeStr)
|
||||
} else {
|
||||
editorObj[type] = monaco.editor.create(document.getElementById(id), {
|
||||
value: codeStr,
|
||||
theme: 'vs-dark',
|
||||
language: mode[type],
|
||||
automaticLayout: true
|
||||
})
|
||||
}
|
||||
// ctrl + s 刷新
|
||||
editorObj[type].onKeyDown(e => {
|
||||
if (e.keyCode === 49 && (e.metaKey || e.ctrlKey)) {
|
||||
this.runCode()
|
||||
}
|
||||
})
|
||||
},
|
||||
runCode() {
|
||||
const jsCodeStr = editorObj.js.getValue()
|
||||
try {
|
||||
const ast = parse(jsCodeStr, { sourceType: 'module' })
|
||||
const astBody = ast.program.body
|
||||
if (astBody.length > 1) {
|
||||
this.$confirm(
|
||||
'js格式不能识别,仅支持修改export default的对象内容',
|
||||
'提示',
|
||||
{
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
return
|
||||
}
|
||||
if (astBody[0].type === 'ExportDefaultDeclaration') {
|
||||
const postData = {
|
||||
type: 'refreshFrame',
|
||||
data: {
|
||||
generateConf: this.generateConf,
|
||||
html: editorObj.html.getValue(),
|
||||
js: jsCodeStr.replace(exportDefault, ''),
|
||||
css: editorObj.css.getValue(),
|
||||
scripts: this.scripts,
|
||||
links: this.links
|
||||
}
|
||||
}
|
||||
|
||||
this.$refs.previewPage.contentWindow.postMessage(
|
||||
postData,
|
||||
location.origin
|
||||
)
|
||||
} else {
|
||||
this.$message.error('请使用export default')
|
||||
}
|
||||
} catch (err) {
|
||||
this.$message.error(`js错误:${err}`)
|
||||
console.error(err)
|
||||
}
|
||||
},
|
||||
generateCode() {
|
||||
const html = vueTemplate(editorObj.html.getValue())
|
||||
const script = vueScript(editorObj.js.getValue())
|
||||
const css = cssStyle(editorObj.css.getValue())
|
||||
return beautifier.html(html + script + css, beautifierConf.html)
|
||||
},
|
||||
exportFile() {
|
||||
this.$prompt('文件名:', '导出文件', {
|
||||
inputValue: `${+new Date()}.vue`,
|
||||
closeOnClickModal: false,
|
||||
inputPlaceholder: '请输入文件名'
|
||||
}).then(({ value }) => {
|
||||
if (!value) value = `${+new Date()}.vue`
|
||||
const codeStr = this.generateCode()
|
||||
const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
|
||||
saveAs(blob, value)
|
||||
})
|
||||
},
|
||||
showResource() {
|
||||
this.resourceVisible = true
|
||||
},
|
||||
setResource(arr) {
|
||||
const scripts = []; const
|
||||
links = []
|
||||
if (Array.isArray(arr)) {
|
||||
arr.forEach(item => {
|
||||
if (item.endsWith('.css')) {
|
||||
links.push(item)
|
||||
} else {
|
||||
scripts.push(item)
|
||||
}
|
||||
})
|
||||
this.scripts = scripts
|
||||
this.links = links
|
||||
} else {
|
||||
this.scripts = []
|
||||
this.links = []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/mixin.scss';
|
||||
.tab-editor {
|
||||
position: absolute;
|
||||
top: 33px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
.left-editor {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
background: #1e1e1e;
|
||||
overflow: hidden;
|
||||
}
|
||||
.setting{
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 3px;
|
||||
color: #a9f122;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
z-index: 1;
|
||||
}
|
||||
.right-preview {
|
||||
height: 100%;
|
||||
.result-wrapper {
|
||||
height: calc(100vh - 33px);
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
@include action-bar;
|
||||
::v-deep .el-drawer__header {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -34,7 +34,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import iconList from '@/utils/generator/icon.json'
|
||||
import iconList from '@/utils/icon.json'
|
||||
|
||||
const originList = iconList.map(name => `el-icon-${name}`)
|
||||
|
||||
|
||||
144
yudao-admin-ui/src/views/tool/build/JsonDrawer.vue
Normal file
144
yudao-admin-ui/src/views/tool/build/JsonDrawer.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-bind="$attrs" v-on="$listeners" @opened="onOpen" @close="onClose">
|
||||
<div class="action-bar" :style="{'text-align': 'left'}">
|
||||
<span class="bar-btn" @click="refresh">
|
||||
<i class="el-icon-refresh" />
|
||||
刷新
|
||||
</span>
|
||||
<span ref="copyBtn" class="bar-btn copy-json-btn">
|
||||
<i class="el-icon-document-copy" />
|
||||
复制JSON
|
||||
</span>
|
||||
<span class="bar-btn" @click="exportJsonFile">
|
||||
<i class="el-icon-download" />
|
||||
导出JSON文件
|
||||
</span>
|
||||
<span class="bar-btn delete-btn" @click="$emit('update:visible', false)">
|
||||
<i class="el-icon-circle-close" />
|
||||
关闭
|
||||
</span>
|
||||
</div>
|
||||
<div id="editorJson" class="json-editor" />
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { beautifierConf } from '@/utils/index'
|
||||
import ClipboardJS from 'clipboard'
|
||||
import { saveAs } from 'file-saver'
|
||||
import loadMonaco from '@/utils/loadMonaco'
|
||||
import loadBeautifier from '@/utils/loadBeautifier'
|
||||
|
||||
let beautifier
|
||||
let monaco
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
jsonStr: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
window.addEventListener('keydown', this.preventDefaultSave)
|
||||
const clipboard = new ClipboardJS('.copy-json-btn', {
|
||||
text: trigger => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '代码已复制到剪切板,可粘贴。',
|
||||
type: 'success'
|
||||
})
|
||||
return this.beautifierJson
|
||||
}
|
||||
})
|
||||
clipboard.on('error', e => {
|
||||
this.$message.error('代码复制失败')
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keydown', this.preventDefaultSave)
|
||||
},
|
||||
methods: {
|
||||
preventDefaultSave(e) {
|
||||
if (e.key === 's' && (e.metaKey || e.ctrlKey)) {
|
||||
e.preventDefault()
|
||||
}
|
||||
},
|
||||
onOpen() {
|
||||
loadBeautifier(btf => {
|
||||
beautifier = btf
|
||||
this.beautifierJson = beautifier.js(this.jsonStr, beautifierConf.js)
|
||||
|
||||
loadMonaco(val => {
|
||||
monaco = val
|
||||
this.setEditorValue('editorJson', this.beautifierJson)
|
||||
})
|
||||
})
|
||||
},
|
||||
onClose() {},
|
||||
setEditorValue(id, codeStr) {
|
||||
if (this.jsonEditor) {
|
||||
this.jsonEditor.setValue(codeStr)
|
||||
} else {
|
||||
this.jsonEditor = monaco.editor.create(document.getElementById(id), {
|
||||
value: codeStr,
|
||||
theme: 'vs-dark',
|
||||
language: 'json',
|
||||
automaticLayout: true
|
||||
})
|
||||
// ctrl + s 刷新
|
||||
this.jsonEditor.onKeyDown(e => {
|
||||
if (e.keyCode === 49 && (e.metaKey || e.ctrlKey)) {
|
||||
this.refresh()
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
exportJsonFile() {
|
||||
this.$prompt('文件名:', '导出文件', {
|
||||
inputValue: `${+new Date()}.json`,
|
||||
closeOnClickModal: false,
|
||||
inputPlaceholder: '请输入文件名'
|
||||
}).then(({ value }) => {
|
||||
if (!value) value = `${+new Date()}.json`
|
||||
const codeStr = this.jsonEditor.getValue()
|
||||
const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
|
||||
saveAs(blob, value)
|
||||
})
|
||||
},
|
||||
refresh() {
|
||||
try {
|
||||
this.$emit('refresh', JSON.parse(this.jsonEditor.getValue()))
|
||||
} catch (error) {
|
||||
this.$notify({
|
||||
title: '错误',
|
||||
message: 'JSON格式错误,请检查',
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/mixin.scss';
|
||||
|
||||
::v-deep .el-drawer__header {
|
||||
display: none;
|
||||
}
|
||||
@include action-bar;
|
||||
|
||||
.json-editor{
|
||||
height: calc(100vh - 33px);
|
||||
}
|
||||
</style>
|
||||
1
yudao-admin-ui/src/views/tool/build/README.md
Normal file
1
yudao-admin-ui/src/views/tool/build/README.md
Normal file
@@ -0,0 +1 @@
|
||||
【add by 芋道源码】引自 https://github.com/JakHuang/form-generator/tree/dev/src/views/index 目录
|
||||
116
yudao-admin-ui/src/views/tool/build/ResourceDialog.vue
Normal file
116
yudao-admin-ui/src/views/tool/build/ResourceDialog.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-bind="$attrs"
|
||||
title="外部资源引用"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
v-on="$listeners"
|
||||
@open="onOpen"
|
||||
@close="onClose"
|
||||
>
|
||||
<el-input
|
||||
v-for="(item, index) in resources"
|
||||
:key="index"
|
||||
v-model="resources[index]"
|
||||
class="url-item"
|
||||
placeholder="请输入 css 或 js 资源路径"
|
||||
prefix-icon="el-icon-link"
|
||||
clearable
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-delete"
|
||||
@click="deleteOne(index)"
|
||||
/>
|
||||
</el-input>
|
||||
<el-button-group class="add-item">
|
||||
<el-button
|
||||
plain
|
||||
@click="addOne('https://lib.baomitu.com/jquery/1.8.3/jquery.min.js')"
|
||||
>
|
||||
jQuery1.8.3
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
@click="addOne('https://unpkg.com/http-vue-loader')"
|
||||
>
|
||||
http-vue-loader
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="el-icon-circle-plus-outline"
|
||||
plain
|
||||
@click="addOne('')"
|
||||
>
|
||||
添加其他
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
<div slot="footer">
|
||||
<el-button @click="close">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handelConfirm"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { deepClone } from '@/utils/index'
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
inheritAttrs: false,
|
||||
props: ['originResource'],
|
||||
data() {
|
||||
return {
|
||||
resources: null
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
onOpen() {
|
||||
this.resources = this.originResource.length ? deepClone(this.originResource) : ['']
|
||||
},
|
||||
onClose() {
|
||||
},
|
||||
close() {
|
||||
this.$emit('update:visible', false)
|
||||
},
|
||||
handelConfirm() {
|
||||
const results = this.resources.filter(item => !!item) || []
|
||||
this.$emit('save', results)
|
||||
this.close()
|
||||
if (results.length) {
|
||||
this.resources = results
|
||||
}
|
||||
},
|
||||
deleteOne(index) {
|
||||
this.resources.splice(index, 1)
|
||||
},
|
||||
addOne(url) {
|
||||
if (this.resources.indexOf(url) > -1) {
|
||||
this.$message('资源已存在')
|
||||
} else {
|
||||
this.resources.push(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.add-item{
|
||||
margin-top: 8px;
|
||||
}
|
||||
.url-item{
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -11,9 +11,9 @@
|
||||
<el-scrollbar class="right-scrollbar">
|
||||
<!-- 组件属性 -->
|
||||
<el-form v-show="currentTab==='field' && showField" size="small" label-width="90px">
|
||||
<el-form-item v-if="activeData.changeTag" label="组件类型">
|
||||
<el-form-item v-if="activeData.__config__.changeTag" label="组件类型">
|
||||
<el-select
|
||||
v-model="activeData.tagIcon"
|
||||
v-model="activeData.__config__.tagIcon"
|
||||
placeholder="请选择组件类型"
|
||||
:style="{width: '100%'}"
|
||||
@change="tagChange"
|
||||
@@ -21,27 +21,27 @@
|
||||
<el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
|
||||
<el-option
|
||||
v-for="item in group.options"
|
||||
:key="item.label"
|
||||
:label="item.label"
|
||||
:value="item.tagIcon"
|
||||
:key="item.__config__.label"
|
||||
:label="item.__config__.label"
|
||||
:value="item.__config__.tagIcon"
|
||||
>
|
||||
<svg-icon class="node-icon" :icon-class="item.tagIcon" />
|
||||
<span> {{ item.label }}</span>
|
||||
<svg-icon class="node-icon" :icon-class="item.__config__.tagIcon" />
|
||||
<span> {{ item.__config__.label }}</span>
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.vModel!==undefined" label="字段名">
|
||||
<el-input v-model="activeData.vModel" placeholder="请输入字段名(v-model)" />
|
||||
<el-form-item v-if="activeData.__vModel__!==undefined" label="字段名">
|
||||
<el-input v-model="activeData.__vModel__" placeholder="请输入字段名(v-model)" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.componentName!==undefined" label="组件名">
|
||||
{{ activeData.componentName }}
|
||||
<el-form-item v-if="activeData.__config__.componentName!==undefined" label="组件名">
|
||||
{{ activeData.__config__.componentName }}
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.label!==undefined" label="标题">
|
||||
<el-input v-model="activeData.label" placeholder="请输入标题" />
|
||||
<el-form-item v-if="activeData.__config__.label!==undefined" label="标题">
|
||||
<el-input v-model="activeData.__config__.label" placeholder="请输入标题" @input="changeRenderKey" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.placeholder!==undefined" label="占位提示">
|
||||
<el-input v-model="activeData.placeholder" placeholder="请输入占位提示" />
|
||||
<el-input v-model="activeData.placeholder" placeholder="请输入占位提示" @input="changeRenderKey" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['start-placeholder']!==undefined" label="开始占位">
|
||||
<el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" />
|
||||
@@ -49,13 +49,13 @@
|
||||
<el-form-item v-if="activeData['end-placeholder']!==undefined" label="结束占位">
|
||||
<el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.span!==undefined" label="表单栅格">
|
||||
<el-slider v-model="activeData.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
|
||||
<el-form-item v-if="activeData.__config__.span!==undefined" label="表单栅格">
|
||||
<el-slider v-model="activeData.__config__.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.layout==='rowFormItem'" label="栅格间隔">
|
||||
<el-form-item v-if="activeData.__config__.layout==='rowFormItem'&&activeData.gutter!==undefined" label="栅格间隔">
|
||||
<el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.layout==='rowFormItem'" label="布局模式">
|
||||
<el-form-item v-if="activeData.__config__.layout==='rowFormItem'&&activeData.type!==undefined" label="布局模式">
|
||||
<el-radio-group v-model="activeData.type">
|
||||
<el-radio-button label="default" />
|
||||
<el-radio-button label="flex" />
|
||||
@@ -78,20 +78,20 @@
|
||||
<el-radio-button label="bottom" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.labelWidth!==undefined" label="标签宽度">
|
||||
<el-input v-model.number="activeData.labelWidth" type="number" placeholder="请输入标签宽度" />
|
||||
<el-form-item v-if="activeData.__config__.labelWidth!==undefined" label="标签宽度">
|
||||
<el-input v-model.number="activeData.__config__.labelWidth" type="number" placeholder="请输入标签宽度" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.style&&activeData.style.width!==undefined" label="组件宽度">
|
||||
<el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.vModel!==undefined" label="默认值">
|
||||
<el-form-item v-if="activeData.__vModel__!==undefined" label="默认值">
|
||||
<el-input
|
||||
:value="setDefaultValue(activeData.defaultValue)"
|
||||
:value="setDefaultValue(activeData.__config__.defaultValue)"
|
||||
placeholder="请输入默认值"
|
||||
@input="onDefaultValueInput"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag==='el-checkbox-group'" label="至少应选">
|
||||
<el-form-item v-if="activeData.__config__.tag==='el-checkbox-group'" label="至少应选">
|
||||
<el-input-number
|
||||
:value="activeData.min"
|
||||
:min="0"
|
||||
@@ -99,7 +99,7 @@
|
||||
@input="$set(activeData, 'min', $event?$event:undefined)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag==='el-checkbox-group'" label="最多可选">
|
||||
<el-form-item v-if="activeData.__config__.tag==='el-checkbox-group'" label="最多可选">
|
||||
<el-input-number
|
||||
:value="activeData.max"
|
||||
:min="0"
|
||||
@@ -107,11 +107,11 @@
|
||||
@input="$set(activeData, 'max', $event?$event:undefined)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.prepend!==undefined" label="前缀">
|
||||
<el-input v-model="activeData.prepend" placeholder="请输入前缀" />
|
||||
<el-form-item v-if="activeData.__slot__&&activeData.__slot__.prepend!==undefined" label="前缀">
|
||||
<el-input v-model="activeData.__slot__.prepend" placeholder="请输入前缀" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.append!==undefined" label="后缀">
|
||||
<el-input v-model="activeData.append" placeholder="请输入后缀" />
|
||||
<el-form-item v-if="activeData.__slot__&&activeData.__slot__.append!==undefined" label="后缀">
|
||||
<el-input v-model="activeData.__slot__.append" placeholder="请输入后缀" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['prefix-icon']!==undefined" label="前图标">
|
||||
<el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称">
|
||||
@@ -127,7 +127,17 @@
|
||||
</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-cascader'" label="选项分隔符">
|
||||
<el-form-item
|
||||
v-if="activeData['icon']!==undefined && activeData.__config__.tag === 'el-button'"
|
||||
label="按钮图标"
|
||||
>
|
||||
<el-input v-model="activeData['icon']" placeholder="请输入按钮图标名称">
|
||||
<el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('icon')">
|
||||
选择
|
||||
</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="选项分隔符">
|
||||
<el-input v-model="activeData.separator" placeholder="请输入选项分隔符" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.autosize !== undefined" label="最小行数">
|
||||
@@ -136,19 +146,22 @@
|
||||
<el-form-item v-if="activeData.autosize !== undefined" label="最大行数">
|
||||
<el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.min !== undefined" label="最小值">
|
||||
<el-form-item v-if="isShowMin" label="最小值">
|
||||
<el-input-number v-model="activeData.min" placeholder="最小值" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.max !== undefined" label="最大值">
|
||||
<el-form-item v-if="isShowMax" label="最大值">
|
||||
<el-input-number v-model="activeData.max" placeholder="最大值" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.step !== undefined" label="步长">
|
||||
<el-form-item v-if="activeData.height!==undefined" label="组件高度">
|
||||
<el-input-number v-model="activeData.height" placeholder="高度" @input="changeRenderKey" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="isShowStep" label="步长">
|
||||
<el-input-number v-model="activeData.step" placeholder="步数" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-input-number'" label="精度">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="精度">
|
||||
<el-input-number v-model="activeData.precision" :min="0" placeholder="精度" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-input-number'" label="按钮位置">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="按钮位置">
|
||||
<el-radio-group v-model="activeData['controls-position']">
|
||||
<el-radio-button label="">
|
||||
默认
|
||||
@@ -186,7 +199,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag"
|
||||
v-if="activeData.type !== undefined && 'el-date-picker' === activeData.__config__.tag"
|
||||
label="时间类型"
|
||||
>
|
||||
<el-select
|
||||
@@ -222,9 +235,9 @@
|
||||
<el-option label="txt" value=".txt" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.fileSize !== undefined" label="文件大小">
|
||||
<el-input v-model.number="activeData.fileSize" placeholder="请输入文件大小">
|
||||
<el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }">
|
||||
<el-form-item v-if="activeData.__config__.fileSize !== undefined" label="文件大小">
|
||||
<el-input v-model.number="activeData.__config__.fileSize" placeholder="请输入文件大小">
|
||||
<el-select slot="append" v-model="activeData.__config__.sizeUnit" :style="{ width: '66px' }">
|
||||
<el-option label="KB" value="KB" />
|
||||
<el-option label="MB" value="MB" />
|
||||
<el-option label="GB" value="GB" />
|
||||
@@ -248,11 +261,30 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="activeData.buttonText !== undefined"
|
||||
v-if="activeData.type !== undefined && activeData.__config__.tag === 'el-button'"
|
||||
label="按钮类型"
|
||||
>
|
||||
<el-select v-model="activeData.type" :style="{ width: '100%' }">
|
||||
<el-option label="primary" value="primary" />
|
||||
<el-option label="success" value="success" />
|
||||
<el-option label="warning" value="warning" />
|
||||
<el-option label="danger" value="danger" />
|
||||
<el-option label="info" value="info" />
|
||||
<el-option label="text" value="text" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="activeData.__config__.buttonText !== undefined"
|
||||
v-show="'picture-card' !== activeData['list-type']"
|
||||
label="按钮文字"
|
||||
>
|
||||
<el-input v-model="activeData.buttonText" placeholder="请输入按钮文字" />
|
||||
<el-input v-model="activeData.__config__.buttonText" placeholder="请输入按钮文字" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="activeData.__config__.tag === 'el-button'"
|
||||
label="按钮文字"
|
||||
>
|
||||
<el-input v-model="activeData.__slot__.default" placeholder="请输入按钮文字" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符">
|
||||
<el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" />
|
||||
@@ -270,15 +302,15 @@
|
||||
@input="setTimeValue($event)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1">
|
||||
<template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.__config__.tag) > -1">
|
||||
<el-divider>选项</el-divider>
|
||||
<draggable
|
||||
:list="activeData.options"
|
||||
:list="activeData.__slot__.options"
|
||||
:animation="340"
|
||||
group="selectItem"
|
||||
handle=".option-drag"
|
||||
>
|
||||
<div v-for="(item, index) in activeData.options" :key="index" class="select-item">
|
||||
<div v-for="(item, index) in activeData.__slot__.options" :key="index" class="select-item">
|
||||
<div class="select-line-icon option-drag">
|
||||
<i class="el-icon-s-operation" />
|
||||
</div>
|
||||
@@ -289,7 +321,7 @@
|
||||
:value="item.value"
|
||||
@input="setOptionValue(item, $event)"
|
||||
/>
|
||||
<div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)">
|
||||
<div class="close-btn select-line-icon" @click="activeData.__slot__.options.splice(index, 1)">
|
||||
<i class="el-icon-remove-outline" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -307,10 +339,10 @@
|
||||
<el-divider />
|
||||
</template>
|
||||
|
||||
<template v-if="['el-cascader'].indexOf(activeData.tag) > -1">
|
||||
<template v-if="['el-cascader', 'el-table'].includes(activeData.__config__.tag)">
|
||||
<el-divider>选项</el-divider>
|
||||
<el-form-item label="数据类型">
|
||||
<el-radio-group v-model="activeData.dataType" size="small">
|
||||
<el-form-item v-if="activeData.__config__.dataType" label="数据类型">
|
||||
<el-radio-group v-model="activeData.__config__.dataType" size="small">
|
||||
<el-radio-button label="dynamic">
|
||||
动态数据
|
||||
</el-radio-button>
|
||||
@@ -320,27 +352,59 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="activeData.dataType === 'dynamic'">
|
||||
<el-form-item label="标签键名">
|
||||
<el-input v-model="activeData.labelKey" placeholder="请输入标签键名" />
|
||||
<template v-if="activeData.__config__.dataType === 'dynamic'">
|
||||
<el-form-item label="接口地址">
|
||||
<el-input
|
||||
v-model="activeData.__config__.url"
|
||||
:title="activeData.__config__.url"
|
||||
placeholder="请输入接口地址"
|
||||
clearable
|
||||
@blur="$emit('fetch-data', activeData)"
|
||||
>
|
||||
<el-select
|
||||
slot="prepend"
|
||||
v-model="activeData.__config__.method"
|
||||
:style="{width: '85px'}"
|
||||
@change="$emit('fetch-data', activeData)"
|
||||
>
|
||||
<el-option label="get" value="get" />
|
||||
<el-option label="post" value="post" />
|
||||
<el-option label="put" value="put" />
|
||||
<el-option label="delete" value="delete" />
|
||||
</el-select>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="值键名">
|
||||
<el-input v-model="activeData.valueKey" placeholder="请输入值键名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="子级键名">
|
||||
<el-input v-model="activeData.childrenKey" placeholder="请输入子级键名" />
|
||||
<el-form-item label="数据位置">
|
||||
<el-input
|
||||
v-model="activeData.__config__.dataPath"
|
||||
placeholder="请输入数据位置"
|
||||
@blur="$emit('fetch-data', activeData)"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="activeData.props && activeData.props.props">
|
||||
<el-form-item label="标签键名">
|
||||
<el-input v-model="activeData.props.props.label" placeholder="请输入标签键名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="值键名">
|
||||
<el-input v-model="activeData.props.props.value" placeholder="请输入值键名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="子级键名">
|
||||
<el-input v-model="activeData.props.props.children" placeholder="请输入子级键名" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- 级联选择静态树 -->
|
||||
<el-tree
|
||||
v-if="activeData.dataType === 'static'"
|
||||
v-if="activeData.__config__.dataType === 'static'"
|
||||
draggable
|
||||
:data="activeData.options"
|
||||
node-key="id"
|
||||
:expand-on-click-node="false"
|
||||
:render-content="renderContent"
|
||||
/>
|
||||
<div v-if="activeData.dataType === 'static'" style="margin-left: 20px">
|
||||
<div v-if="activeData.__config__.dataType === 'static'" style="margin-left: 20px">
|
||||
<el-button
|
||||
style="padding-bottom: 0"
|
||||
icon="el-icon-circle-plus-outline"
|
||||
@@ -353,8 +417,8 @@
|
||||
<el-divider />
|
||||
</template>
|
||||
|
||||
<el-form-item v-if="activeData.optionType !== undefined" label="选项样式">
|
||||
<el-radio-group v-model="activeData.optionType">
|
||||
<el-form-item v-if="activeData.__config__.optionType !== undefined" label="选项样式">
|
||||
<el-radio-group v-model="activeData.__config__.optionType">
|
||||
<el-radio-button label="default">
|
||||
默认
|
||||
</el-radio-button>
|
||||
@@ -370,6 +434,14 @@
|
||||
<el-color-picker v-model="activeData['inactive-color']" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="activeData.__config__.showLabel !== undefined
|
||||
&& activeData.__config__.labelWidth !== undefined" label="显示标签"
|
||||
>
|
||||
<el-switch v-model="activeData.__config__.showLabel" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.branding !== undefined" label="品牌烙印">
|
||||
<el-switch v-model="activeData.branding" @input="changeRenderKey" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选">
|
||||
<el-switch v-model="activeData['allow-half']" />
|
||||
</el-form-item>
|
||||
@@ -386,16 +458,17 @@
|
||||
<el-switch v-model="activeData.range" @change="rangeChange" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="activeData.border !== undefined && activeData.optionType === 'default'"
|
||||
v-if="activeData.__config__.border !== undefined && activeData.__config__.optionType === 'default'"
|
||||
label="是否带边框"
|
||||
>
|
||||
<el-switch v-model="activeData.border" />
|
||||
<el-switch v-model="activeData.__config__.border" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-color-picker'" label="颜色格式">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-color-picker'" label="颜色格式">
|
||||
<el-select
|
||||
v-model="activeData['color-format']"
|
||||
placeholder="请选择颜色格式"
|
||||
:style="{ width: '100%' }"
|
||||
clearable
|
||||
@change="colorFormatChange"
|
||||
>
|
||||
<el-option
|
||||
@@ -408,10 +481,11 @@
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="activeData.size !== undefined &&
|
||||
(activeData.optionType === 'button' ||
|
||||
activeData.border ||
|
||||
activeData.tag === 'el-color-picker')"
|
||||
label="选项尺寸"
|
||||
(activeData.__config__.optionType === 'button' ||
|
||||
activeData.__config__.border ||
|
||||
activeData.__config__.tag === 'el-color-picker' ||
|
||||
activeData.__config__.tag === 'el-button')"
|
||||
label="组件尺寸"
|
||||
>
|
||||
<el-radio-group v-model="activeData.size">
|
||||
<el-radio-button label="medium">
|
||||
@@ -428,25 +502,28 @@
|
||||
<el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计">
|
||||
<el-switch v-model="activeData['show-word-limit']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-input-number'" label="严格步数">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="严格步数">
|
||||
<el-switch v-model="activeData['step-strictly']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-cascader'" label="是否多选">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="任选层级">
|
||||
<el-switch v-model="activeData.props.props.checkStrictly" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="是否多选">
|
||||
<el-switch v-model="activeData.props.props.multiple" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-cascader'" label="展示全路径">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="展示全路径">
|
||||
<el-switch v-model="activeData['show-all-levels']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-cascader'" label="可否筛选">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="可否筛选">
|
||||
<el-switch v-model="activeData.filterable" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.clearable !== undefined" label="能否清空">
|
||||
<el-switch v-model="activeData.clearable" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.showTip !== undefined" label="显示提示">
|
||||
<el-switch v-model="activeData.showTip" />
|
||||
<el-form-item v-if="activeData.__config__.showTip !== undefined" label="显示提示">
|
||||
<el-switch v-model="activeData.__config__.showTip" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.multiple !== undefined" label="多选文件">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-upload'" label="多选文件">
|
||||
<el-switch v-model="activeData.multiple" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传">
|
||||
@@ -458,20 +535,20 @@
|
||||
<el-form-item v-if="activeData.disabled !== undefined" label="是否禁用">
|
||||
<el-switch v-model="activeData.disabled" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-select'" label="是否可搜索">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-select'" label="能否搜索">
|
||||
<el-switch v-model="activeData.filterable" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-select'" label="是否多选">
|
||||
<el-form-item v-if="activeData.__config__.tag === 'el-select'" label="是否多选">
|
||||
<el-switch v-model="activeData.multiple" @change="multipleChange" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.required !== undefined" label="是否必填">
|
||||
<el-switch v-model="activeData.required" />
|
||||
<el-form-item v-if="activeData.__config__.required !== undefined" label="是否必填">
|
||||
<el-switch v-model="activeData.__config__.required" />
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="activeData.layoutTree">
|
||||
<template v-if="activeData.__config__.layoutTree">
|
||||
<el-divider>布局结构树</el-divider>
|
||||
<el-tree
|
||||
:data="[activeData]"
|
||||
:data="[activeData.__config__]"
|
||||
:props="layoutTreeProps"
|
||||
node-key="renderKey"
|
||||
default-expand-all
|
||||
@@ -479,21 +556,21 @@
|
||||
>
|
||||
<span slot-scope="{ node, data }">
|
||||
<span class="node-label">
|
||||
<svg-icon class="node-icon" :icon-class="data.tagIcon" />
|
||||
<svg-icon class="node-icon" :icon-class="data.__config__?data.__config__.tagIcon:data.tagIcon" />
|
||||
{{ node.label }}
|
||||
</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</template>
|
||||
|
||||
<template v-if="activeData.layout === 'colFormItem'">
|
||||
<template v-if="Array.isArray(activeData.__config__.regList)">
|
||||
<el-divider>正则校验</el-divider>
|
||||
<div
|
||||
v-for="(item, index) in activeData.regList"
|
||||
v-for="(item, index) in activeData.__config__.regList"
|
||||
:key="index"
|
||||
class="reg-item"
|
||||
>
|
||||
<span class="close-btn" @click="activeData.regList.splice(index, 1)">
|
||||
<span class="close-btn" @click="activeData.__config__.regList.splice(index, 1)">
|
||||
<i class="el-icon-close" />
|
||||
</span>
|
||||
<el-form-item label="表达式">
|
||||
@@ -548,7 +625,7 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签宽度">
|
||||
<el-input-number v-model="formConf.labelWidth" placeholder="标签宽度" />
|
||||
<el-input v-model.number="formConf.labelWidth" type="number" placeholder="请输入标签宽度" />
|
||||
</el-form-item>
|
||||
<el-form-item label="栅格间隔">
|
||||
<el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" />
|
||||
@@ -577,10 +654,9 @@ import TreeNodeDialog from './TreeNodeDialog'
|
||||
import { isNumberStr } from '@/utils/index'
|
||||
import IconsDialog from './IconsDialog'
|
||||
import {
|
||||
inputComponents,
|
||||
selectComponents,
|
||||
layoutComponents
|
||||
} from '@/utils/generator/config'
|
||||
inputComponents, selectComponents, layoutComponents
|
||||
} from '@/components/generator/config'
|
||||
import { saveFormConf } from '@/utils/db'
|
||||
|
||||
const dateTimeFormat = {
|
||||
date: 'yyyy-MM-dd',
|
||||
@@ -593,6 +669,9 @@ const dateTimeFormat = {
|
||||
datetimerange: 'yyyy-MM-dd HH:mm:ss'
|
||||
}
|
||||
|
||||
// 使changeRenderKey在目标组件改变时可用
|
||||
const needRerenderList = ['tinymce']
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TreeNodeDialog,
|
||||
@@ -688,7 +767,8 @@ export default {
|
||||
],
|
||||
layoutTreeProps: {
|
||||
label(data, node) {
|
||||
return data.componentName || `${data.label}: ${data.vModel}`
|
||||
const config = data.__config__
|
||||
return data.componentName || `${config.label}: ${data.__vModel__}`
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -696,14 +776,14 @@ export default {
|
||||
computed: {
|
||||
documentLink() {
|
||||
return (
|
||||
this.activeData.document
|
||||
this.activeData.__config__.document
|
||||
|| 'https://element.eleme.cn/#/zh-CN/component/installation'
|
||||
)
|
||||
},
|
||||
dateOptions() {
|
||||
if (
|
||||
this.activeData.type !== undefined
|
||||
&& this.activeData.tag === 'el-date-picker'
|
||||
&& this.activeData.__config__.tag === 'el-date-picker'
|
||||
) {
|
||||
if (this.activeData['start-placeholder'] === undefined) {
|
||||
return this.dateTypeOptions
|
||||
@@ -723,17 +803,37 @@ export default {
|
||||
options: selectComponents
|
||||
}
|
||||
]
|
||||
},
|
||||
activeTag() {
|
||||
return this.activeData.__config__.tag
|
||||
},
|
||||
isShowMin() {
|
||||
return ['el-input-number', 'el-slider'].indexOf(this.activeTag) > -1
|
||||
},
|
||||
isShowMax() {
|
||||
return ['el-input-number', 'el-slider', 'el-rate'].indexOf(this.activeTag) > -1
|
||||
},
|
||||
isShowStep() {
|
||||
return ['el-input-number', 'el-slider'].indexOf(this.activeTag) > -1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
formConf: {
|
||||
handler(val) {
|
||||
saveFormConf(val)
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addReg() {
|
||||
this.activeData.regList.push({
|
||||
this.activeData.__config__.regList.push({
|
||||
pattern: '',
|
||||
message: ''
|
||||
})
|
||||
},
|
||||
addSelectItem() {
|
||||
this.activeData.options.push({
|
||||
this.activeData.__slot__.options.push({
|
||||
label: '',
|
||||
value: ''
|
||||
})
|
||||
@@ -768,6 +868,7 @@ export default {
|
||||
this.currentNode = data.children
|
||||
},
|
||||
remove(node, data) {
|
||||
this.activeData.__config__.defaultValue = [] // 避免删除时报错
|
||||
const { parent } = node
|
||||
const children = parent.data.children || parent.data
|
||||
const index = children.findIndex(d => d.id === data.id)
|
||||
@@ -783,29 +884,29 @@ export default {
|
||||
if (Array.isArray(val)) {
|
||||
return val.join(',')
|
||||
}
|
||||
if (['string', 'number'].indexOf(val) > -1) {
|
||||
return val
|
||||
}
|
||||
// if (['string', 'number'].indexOf(typeof val) > -1) {
|
||||
// return val
|
||||
// }
|
||||
if (typeof val === 'boolean') {
|
||||
return `${val}`
|
||||
}
|
||||
return val
|
||||
},
|
||||
onDefaultValueInput(str) {
|
||||
if (isArray(this.activeData.defaultValue)) {
|
||||
if (isArray(this.activeData.__config__.defaultValue)) {
|
||||
// 数组
|
||||
this.$set(
|
||||
this.activeData,
|
||||
this.activeData.__config__,
|
||||
'defaultValue',
|
||||
str.split(',').map(val => (isNumberStr(val) ? +val : val))
|
||||
)
|
||||
} else if (['true', 'false'].indexOf(str) > -1) {
|
||||
// 布尔
|
||||
this.$set(this.activeData, 'defaultValue', JSON.parse(str))
|
||||
this.$set(this.activeData.__config__, 'defaultValue', JSON.parse(str))
|
||||
} else {
|
||||
// 字符串和数字
|
||||
this.$set(
|
||||
this.activeData,
|
||||
this.activeData.__config__,
|
||||
'defaultValue',
|
||||
isNumberStr(str) ? +str : str
|
||||
)
|
||||
@@ -820,7 +921,7 @@ export default {
|
||||
},
|
||||
setTimeValue(val, type) {
|
||||
const valueFormat = type === 'week' ? dateTimeFormat.date : val
|
||||
this.$set(this.activeData, 'defaultValue', null)
|
||||
this.$set(this.activeData.__config__, 'defaultValue', null)
|
||||
this.$set(this.activeData, 'value-format', valueFormat)
|
||||
this.$set(this.activeData, 'format', val)
|
||||
},
|
||||
@@ -828,14 +929,14 @@ export default {
|
||||
this.formConf.span = val
|
||||
},
|
||||
multipleChange(val) {
|
||||
this.$set(this.activeData, 'defaultValue', val ? [] : '')
|
||||
this.$set(this.activeData.__config__, 'defaultValue', val ? [] : '')
|
||||
},
|
||||
dateTypeChange(val) {
|
||||
this.setTimeValue(dateTimeFormat[val], val)
|
||||
},
|
||||
rangeChange(val) {
|
||||
this.$set(
|
||||
this.activeData,
|
||||
this.activeData.__config__,
|
||||
'defaultValue',
|
||||
val ? [this.activeData.min, this.activeData.max] : this.activeData.min
|
||||
)
|
||||
@@ -847,9 +948,9 @@ export default {
|
||||
if (val) this.activeData['show-text'] = false
|
||||
},
|
||||
colorFormatChange(val) {
|
||||
this.activeData.defaultValue = null
|
||||
this.activeData.__config__.defaultValue = null
|
||||
this.activeData['show-alpha'] = val.indexOf('a') > -1
|
||||
this.activeData.renderKey = +new Date() // 更新renderKey,重新渲染该组件
|
||||
this.activeData.__config__.renderKey = +new Date() // 更新renderKey,重新渲染该组件
|
||||
},
|
||||
openIconsDialog(model) {
|
||||
this.iconsVisible = true
|
||||
@@ -859,9 +960,14 @@ export default {
|
||||
this.activeData[this.currentIconModel] = val
|
||||
},
|
||||
tagChange(tagIcon) {
|
||||
let target = inputComponents.find(item => item.tagIcon === tagIcon)
|
||||
if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon)
|
||||
let target = inputComponents.find(item => item.__config__.tagIcon === tagIcon)
|
||||
if (!target) target = selectComponents.find(item => item.__config__.tagIcon === tagIcon)
|
||||
this.$emit('tag-change', target)
|
||||
},
|
||||
changeRenderKey() {
|
||||
if (needRerenderList.includes(this.activeData.__config__.tag)) {
|
||||
this.activeData.__config__.renderKey = +new Date()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
</template>
|
||||
<script>
|
||||
import { isNumberStr } from '@/utils/index'
|
||||
import { getTreeNodeId, saveTreeNodeId } from '@/utils/db'
|
||||
|
||||
const id = getTreeNodeId()
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
@@ -79,7 +82,7 @@ export default {
|
||||
props: [],
|
||||
data() {
|
||||
return {
|
||||
id: 100,
|
||||
id,
|
||||
formData: {
|
||||
label: undefined,
|
||||
value: undefined
|
||||
@@ -118,6 +121,9 @@ export default {
|
||||
// eslint-disable-next-line func-names
|
||||
'formData.value': function (val) {
|
||||
this.dataType = isNumberStr(val) ? 'number' : 'string'
|
||||
},
|
||||
id(val) {
|
||||
saveTreeNodeId(val)
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
@@ -147,3 +153,6 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
|
||||
@@ -4,80 +4,52 @@
|
||||
<div class="logo-wrapper">
|
||||
<div class="logo">
|
||||
<img :src="logo" alt="logo"> Form Generator
|
||||
<a class="github" href="https://github.com/JakHuang/form-generator" target="_blank">
|
||||
<img src="https://github.githubassets.com/pinned-octocat.svg" alt>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<el-scrollbar class="left-scrollbar">
|
||||
<div class="components-list">
|
||||
<div class="components-title">
|
||||
<svg-icon icon-class="component" />输入型组件
|
||||
</div>
|
||||
<draggable
|
||||
class="components-draggable"
|
||||
:list="inputComponents"
|
||||
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
|
||||
:clone="cloneComponent"
|
||||
draggable=".components-item"
|
||||
:sort="false"
|
||||
@end="onEnd"
|
||||
>
|
||||
<div
|
||||
v-for="(element, index) in inputComponents" :key="index" class="components-item"
|
||||
@click="addComponent(element)"
|
||||
>
|
||||
<div class="components-body">
|
||||
<svg-icon :icon-class="element.tagIcon" />
|
||||
{{ element.label }}
|
||||
</div>
|
||||
<div v-for="(item, listIndex) in leftComponents" :key="listIndex">
|
||||
<div class="components-title">
|
||||
<svg-icon icon-class="component" />
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</draggable>
|
||||
<div class="components-title">
|
||||
<svg-icon icon-class="component" />选择型组件
|
||||
</div>
|
||||
<draggable
|
||||
class="components-draggable"
|
||||
:list="selectComponents"
|
||||
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
|
||||
:clone="cloneComponent"
|
||||
draggable=".components-item"
|
||||
:sort="false"
|
||||
@end="onEnd"
|
||||
>
|
||||
<div
|
||||
v-for="(element, index) in selectComponents"
|
||||
:key="index"
|
||||
class="components-item"
|
||||
@click="addComponent(element)"
|
||||
<draggable
|
||||
class="components-draggable"
|
||||
:list="item.list"
|
||||
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
|
||||
:clone="cloneComponent"
|
||||
draggable=".components-item"
|
||||
:sort="false"
|
||||
@end="onEnd"
|
||||
>
|
||||
<div class="components-body">
|
||||
<svg-icon :icon-class="element.tagIcon" />
|
||||
{{ element.label }}
|
||||
<div
|
||||
v-for="(element, index) in item.list"
|
||||
:key="index"
|
||||
class="components-item"
|
||||
@click="addComponent(element)"
|
||||
>
|
||||
<div class="components-body">
|
||||
<svg-icon :icon-class="element.__config__.tagIcon" />
|
||||
{{ element.__config__.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</draggable>
|
||||
<div class="components-title">
|
||||
<svg-icon icon-class="component" /> 布局型组件
|
||||
</draggable>
|
||||
</div>
|
||||
<draggable
|
||||
class="components-draggable" :list="layoutComponents"
|
||||
:group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
|
||||
draggable=".components-item" :sort="false" @end="onEnd"
|
||||
>
|
||||
<div
|
||||
v-for="(element, index) in layoutComponents" :key="index" class="components-item"
|
||||
@click="addComponent(element)"
|
||||
>
|
||||
<div class="components-body">
|
||||
<svg-icon :icon-class="element.tagIcon" />
|
||||
{{ element.label }}
|
||||
</div>
|
||||
</div>
|
||||
</draggable>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<div class="center-board">
|
||||
<div class="action-bar">
|
||||
<el-button icon="el-icon-video-play" type="text" @click="run">
|
||||
运行
|
||||
</el-button>
|
||||
<el-button icon="el-icon-view" type="text" @click="showJson">
|
||||
查看json
|
||||
</el-button>
|
||||
<el-button icon="el-icon-download" type="text" @click="download">
|
||||
导出vue文件
|
||||
</el-button>
|
||||
@@ -98,10 +70,10 @@
|
||||
>
|
||||
<draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
|
||||
<draggable-item
|
||||
v-for="(element, index) in drawingList"
|
||||
:key="element.renderKey"
|
||||
v-for="(item, index) in drawingList"
|
||||
:key="item.renderKey"
|
||||
:drawing-list="drawingList"
|
||||
:element="element"
|
||||
:current-item="item"
|
||||
:index="index"
|
||||
:active-id="activeId"
|
||||
:form-conf="formConf"
|
||||
@@ -123,8 +95,21 @@
|
||||
:form-conf="formConf"
|
||||
:show-field="!!drawingList.length"
|
||||
@tag-change="tagChange"
|
||||
@fetch-data="fetchData"
|
||||
/>
|
||||
|
||||
<form-drawer
|
||||
:visible.sync="drawerVisible"
|
||||
:form-data="formData"
|
||||
size="100%"
|
||||
:generate-conf="generateConf"
|
||||
/>
|
||||
<json-drawer
|
||||
size="60%"
|
||||
:visible.sync="jsonDrawerVisible"
|
||||
:json-str="JSON.stringify(formData)"
|
||||
@refresh="refreshJson"
|
||||
/>
|
||||
<code-type-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
title="选择生成类型"
|
||||
@@ -137,38 +122,47 @@
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import { debounce } from 'throttle-debounce'
|
||||
import { saveAs } from 'file-saver'
|
||||
import beautifier from 'js-beautify'
|
||||
import ClipboardJS from 'clipboard'
|
||||
import render from '@/utils/generator/render'
|
||||
import render from '@/components/render/render'
|
||||
import FormDrawer from './FormDrawer'
|
||||
import JsonDrawer from './JsonDrawer'
|
||||
import RightPanel from './RightPanel'
|
||||
import {
|
||||
inputComponents,
|
||||
selectComponents,
|
||||
layoutComponents,
|
||||
formConf
|
||||
} from '@/utils/generator/config'
|
||||
inputComponents, selectComponents, layoutComponents, formConf
|
||||
} from '@/components/generator/config'
|
||||
import {
|
||||
exportDefault, beautifierConf, isNumberStr, titleCase
|
||||
exportDefault, beautifierConf, isNumberStr, titleCase, deepClone, isObjectObject
|
||||
} from '@/utils/index'
|
||||
import {
|
||||
makeUpHtml, vueTemplate, vueScript, cssStyle
|
||||
} from '@/utils/generator/html'
|
||||
import { makeUpJs } from '@/utils/generator/js'
|
||||
import { makeUpCss } from '@/utils/generator/css'
|
||||
import drawingDefalut from '@/utils/generator/drawingDefalut'
|
||||
} from '@/components/generator/html'
|
||||
import { makeUpJs } from '@/components/generator/js'
|
||||
import { makeUpCss } from '@/components/generator/css'
|
||||
import drawingDefalut from '@/components/generator/drawingDefalut'
|
||||
import logo from '@/assets/logo/logo.png'
|
||||
import CodeTypeDialog from './CodeTypeDialog'
|
||||
import DraggableItem from './DraggableItem'
|
||||
import {
|
||||
getDrawingList, saveDrawingList, getIdGlobal, saveIdGlobal, getFormConf
|
||||
} from '@/utils/db'
|
||||
import loadBeautifier from '@/utils/loadBeautifier'
|
||||
|
||||
let beautifier
|
||||
const emptyActiveData = { style: {}, autosize: {} }
|
||||
let oldActiveId
|
||||
let tempActiveData
|
||||
const drawingListInDB = getDrawingList()
|
||||
const formConfInDB = getFormConf()
|
||||
const idGlobal = getIdGlobal()
|
||||
|
||||
export default {
|
||||
components: {
|
||||
draggable,
|
||||
render,
|
||||
FormDrawer,
|
||||
JsonDrawer,
|
||||
RightPanel,
|
||||
CodeTypeDialog,
|
||||
DraggableItem
|
||||
@@ -176,7 +170,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
logo,
|
||||
idGlobal: 100,
|
||||
idGlobal,
|
||||
formConf,
|
||||
inputComponents,
|
||||
selectComponents,
|
||||
@@ -188,19 +182,36 @@ export default {
|
||||
drawerVisible: false,
|
||||
formData: {},
|
||||
dialogVisible: false,
|
||||
jsonDrawerVisible: false,
|
||||
generateConf: null,
|
||||
showFileName: false,
|
||||
activeData: drawingDefalut[0]
|
||||
activeData: drawingDefalut[0],
|
||||
saveDrawingListDebounce: debounce(340, saveDrawingList),
|
||||
saveIdGlobalDebounce: debounce(340, saveIdGlobal),
|
||||
leftComponents: [
|
||||
{
|
||||
title: '输入型组件',
|
||||
list: inputComponents
|
||||
},
|
||||
{
|
||||
title: '选择型组件',
|
||||
list: selectComponents
|
||||
},
|
||||
{
|
||||
title: '布局型组件',
|
||||
list: layoutComponents
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
// eslint-disable-next-line func-names
|
||||
'activeData.label': function (val, oldVal) {
|
||||
'activeData.__config__.label': function (val, oldVal) {
|
||||
if (
|
||||
this.activeData.placeholder === undefined
|
||||
|| !this.activeData.tag
|
||||
|| !this.activeData.__config__.tag
|
||||
|| oldActiveId !== this.activeId
|
||||
) {
|
||||
return
|
||||
@@ -212,9 +223,34 @@ export default {
|
||||
oldActiveId = val
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
drawingList: {
|
||||
handler(val) {
|
||||
this.saveDrawingListDebounce(val)
|
||||
if (val.length === 0) this.idGlobal = 100
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
idGlobal: {
|
||||
handler(val) {
|
||||
this.saveIdGlobalDebounce(val)
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (Array.isArray(drawingListInDB) && drawingListInDB.length > 0) {
|
||||
this.drawingList = drawingListInDB
|
||||
} else {
|
||||
this.drawingList = drawingDefalut
|
||||
}
|
||||
this.activeFormItem(this.drawingList[0])
|
||||
if (formConfInDB) {
|
||||
this.formConf = formConfInDB
|
||||
}
|
||||
loadBeautifier(btf => {
|
||||
beautifier = btf
|
||||
})
|
||||
const clipboard = new ClipboardJS('#copyNode', {
|
||||
text: trigger => {
|
||||
const codeStr = this.generateCode()
|
||||
@@ -231,42 +267,95 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
activeFormItem(element) {
|
||||
this.activeData = element
|
||||
this.activeId = element.formId
|
||||
setObjectValueReduce(obj, strKeys, data) {
|
||||
const arr = strKeys.split('.')
|
||||
arr.reduce((pre, item, i) => {
|
||||
if (arr.length === i + 1) {
|
||||
pre[item] = data
|
||||
} else if (!isObjectObject(pre[item])) {
|
||||
pre[item] = {}
|
||||
}
|
||||
return pre[item]
|
||||
}, obj)
|
||||
},
|
||||
onEnd(obj, a) {
|
||||
setRespData(component, resp) {
|
||||
const { dataPath, renderKey, dataConsumer } = component.__config__
|
||||
if (!dataPath || !dataConsumer) return
|
||||
const respData = dataPath.split('.').reduce((pre, item) => pre[item], resp)
|
||||
|
||||
// 将请求回来的数据,赋值到指定属性。
|
||||
// 以el-tabel为例,根据Element文档,应该将数据赋值给el-tabel的data属性,所以dataConsumer的值应为'data';
|
||||
// 此时赋值代码可写成 component[dataConsumer] = respData;
|
||||
// 但为支持更深层级的赋值(如:dataConsumer的值为'options.data'),使用setObjectValueReduce
|
||||
this.setObjectValueReduce(component, dataConsumer, respData)
|
||||
const i = this.drawingList.findIndex(item => item.__config__.renderKey === renderKey)
|
||||
if (i > -1) this.$set(this.drawingList, i, component)
|
||||
},
|
||||
fetchData(component) {
|
||||
const { dataType, method, url } = component.__config__
|
||||
if (dataType === 'dynamic' && method && url) {
|
||||
this.setLoading(component, true)
|
||||
this.$axios({
|
||||
method,
|
||||
url
|
||||
}).then(resp => {
|
||||
this.setLoading(component, false)
|
||||
this.setRespData(component, resp.data)
|
||||
})
|
||||
}
|
||||
},
|
||||
setLoading(component, val) {
|
||||
const { directives } = component
|
||||
if (Array.isArray(directives)) {
|
||||
const t = directives.find(d => d.name === 'loading')
|
||||
if (t) t.value = val
|
||||
}
|
||||
},
|
||||
activeFormItem(currentItem) {
|
||||
this.activeData = currentItem
|
||||
this.activeId = currentItem.__config__.formId
|
||||
},
|
||||
onEnd(obj) {
|
||||
if (obj.from !== obj.to) {
|
||||
this.fetchData(tempActiveData)
|
||||
this.activeData = tempActiveData
|
||||
this.activeId = this.idGlobal
|
||||
}
|
||||
},
|
||||
addComponent(item) {
|
||||
const clone = this.cloneComponent(item)
|
||||
this.fetchData(clone)
|
||||
this.drawingList.push(clone)
|
||||
this.activeFormItem(clone)
|
||||
},
|
||||
cloneComponent(origin) {
|
||||
const clone = JSON.parse(JSON.stringify(origin))
|
||||
clone.formId = ++this.idGlobal
|
||||
clone.span = formConf.span
|
||||
clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
|
||||
if (!clone.layout) clone.layout = 'colFormItem'
|
||||
if (clone.layout === 'colFormItem') {
|
||||
clone.vModel = `field${this.idGlobal}`
|
||||
clone.placeholder !== undefined && (clone.placeholder += clone.label)
|
||||
tempActiveData = clone
|
||||
} else if (clone.layout === 'rowFormItem') {
|
||||
delete clone.label
|
||||
clone.componentName = `row${this.idGlobal}`
|
||||
clone.gutter = this.formConf.gutter
|
||||
tempActiveData = clone
|
||||
}
|
||||
const clone = deepClone(origin)
|
||||
const config = clone.__config__
|
||||
config.span = this.formConf.span // 生成代码时,会根据span做精简判断
|
||||
this.createIdAndKey(clone)
|
||||
clone.placeholder !== undefined && (clone.placeholder += config.label)
|
||||
tempActiveData = clone
|
||||
return tempActiveData
|
||||
},
|
||||
createIdAndKey(item) {
|
||||
const config = item.__config__
|
||||
config.formId = ++this.idGlobal
|
||||
config.renderKey = `${config.formId}${+new Date()}` // 改变renderKey后可以实现强制更新组件
|
||||
if (config.layout === 'colFormItem') {
|
||||
item.__vModel__ = `field${this.idGlobal}`
|
||||
} else if (config.layout === 'rowFormItem') {
|
||||
config.componentName = `row${this.idGlobal}`
|
||||
!Array.isArray(config.children) && (config.children = [])
|
||||
delete config.label // rowFormItem无需配置label属性
|
||||
}
|
||||
if (Array.isArray(config.children)) {
|
||||
config.children = config.children.map(childItem => this.createIdAndKey(childItem))
|
||||
}
|
||||
return item
|
||||
},
|
||||
AssembleFormData() {
|
||||
this.formData = {
|
||||
fields: JSON.parse(JSON.stringify(this.drawingList)),
|
||||
fields: deepClone(this.drawingList),
|
||||
...this.formConf
|
||||
}
|
||||
},
|
||||
@@ -291,30 +380,18 @@ export default {
|
||||
this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
|
||||
() => {
|
||||
this.drawingList = []
|
||||
this.idGlobal = 100
|
||||
}
|
||||
)
|
||||
},
|
||||
drawingItemCopy(item, parent) {
|
||||
let clone = JSON.parse(JSON.stringify(item))
|
||||
drawingItemCopy(item, list) {
|
||||
let clone = deepClone(item)
|
||||
clone = this.createIdAndKey(clone)
|
||||
parent.push(clone)
|
||||
list.push(clone)
|
||||
this.activeFormItem(clone)
|
||||
},
|
||||
createIdAndKey(item) {
|
||||
item.formId = ++this.idGlobal
|
||||
item.renderKey = +new Date()
|
||||
if (item.layout === 'colFormItem') {
|
||||
item.vModel = `field${this.idGlobal}`
|
||||
} else if (item.layout === 'rowFormItem') {
|
||||
item.componentName = `row${this.idGlobal}`
|
||||
}
|
||||
if (Array.isArray(item.children)) {
|
||||
item.children = item.children.map(childItem => this.createIdAndKey(childItem))
|
||||
}
|
||||
return item
|
||||
},
|
||||
drawingItemDelete(index, parent) {
|
||||
parent.splice(index, 1)
|
||||
drawingItemDelete(index, list) {
|
||||
list.splice(index, 1)
|
||||
this.$nextTick(() => {
|
||||
const len = this.drawingList.length
|
||||
if (len) {
|
||||
@@ -330,6 +407,10 @@ export default {
|
||||
const css = cssStyle(makeUpCss(this.formData))
|
||||
return beautifier.html(html + script + css, beautifierConf.html)
|
||||
},
|
||||
showJson() {
|
||||
this.AssembleFormData()
|
||||
this.jsonDrawerVisible = true
|
||||
},
|
||||
download() {
|
||||
this.dialogVisible = true
|
||||
this.showFileName = true
|
||||
@@ -347,15 +428,18 @@ export default {
|
||||
},
|
||||
tagChange(newTag) {
|
||||
newTag = this.cloneComponent(newTag)
|
||||
newTag.vModel = this.activeData.vModel
|
||||
newTag.formId = this.activeId
|
||||
newTag.span = this.activeData.span
|
||||
delete this.activeData.tag
|
||||
delete this.activeData.tagIcon
|
||||
delete this.activeData.document
|
||||
const config = newTag.__config__
|
||||
newTag.__vModel__ = this.activeData.__vModel__
|
||||
config.formId = this.activeId
|
||||
config.span = this.activeData.__config__.span
|
||||
this.activeData.__config__.tag = config.tag
|
||||
this.activeData.__config__.tagIcon = config.tagIcon
|
||||
this.activeData.__config__.document = config.document
|
||||
if (typeof this.activeData.__config__.defaultValue === typeof config.defaultValue) {
|
||||
config.defaultValue = this.activeData.__config__.defaultValue
|
||||
}
|
||||
Object.keys(newTag).forEach(key => {
|
||||
if (this.activeData[key] !== undefined
|
||||
&& typeof this.activeData[key] === typeof newTag[key]) {
|
||||
if (this.activeData[key] !== undefined) {
|
||||
newTag[key] = this.activeData[key]
|
||||
}
|
||||
})
|
||||
@@ -363,427 +447,24 @@ export default {
|
||||
this.updateDrawingList(newTag, this.drawingList)
|
||||
},
|
||||
updateDrawingList(newTag, list) {
|
||||
const index = list.findIndex(item => item.formId === this.activeId)
|
||||
const index = list.findIndex(item => item.__config__.formId === this.activeId)
|
||||
if (index > -1) {
|
||||
list.splice(index, 1, newTag)
|
||||
} else {
|
||||
list.forEach(item => {
|
||||
if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)
|
||||
if (Array.isArray(item.__config__.children)) this.updateDrawingList(newTag, item.__config__.children)
|
||||
})
|
||||
}
|
||||
},
|
||||
refreshJson(data) {
|
||||
this.drawingList = deepClone(data.fields)
|
||||
delete data.fields
|
||||
this.formConf = data
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
body, html{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #fff;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
|
||||
}
|
||||
|
||||
input, textarea{
|
||||
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
|
||||
}
|
||||
|
||||
.editor-tabs{
|
||||
background: #121315;
|
||||
.el-tabs__header{
|
||||
margin: 0;
|
||||
border-bottom-color: #121315;
|
||||
.el-tabs__nav{
|
||||
border-color: #121315;
|
||||
}
|
||||
}
|
||||
.el-tabs__item{
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
color: #888a8e;
|
||||
border-left: 1px solid #121315 !important;
|
||||
background: #363636;
|
||||
margin-right: 5px;
|
||||
user-select: none;
|
||||
}
|
||||
.el-tabs__item.is-active{
|
||||
background: #1e1e1e;
|
||||
border-bottom-color: #1e1e1e!important;
|
||||
color: #fff;
|
||||
}
|
||||
.el-icon-edit{
|
||||
color: #f1fa8c;
|
||||
}
|
||||
.el-icon-document{
|
||||
color: #a95812;
|
||||
}
|
||||
}
|
||||
|
||||
// home
|
||||
.right-scrollbar {
|
||||
.el-scrollbar__view {
|
||||
padding: 12px 18px 15px 15px;
|
||||
}
|
||||
}
|
||||
.left-scrollbar .el-scrollbar__wrap {
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.center-tabs{
|
||||
.el-tabs__header{
|
||||
margin-bottom: 0!important;
|
||||
}
|
||||
.el-tabs__item{
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
.el-tabs__nav{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.reg-item{
|
||||
padding: 12px 6px;
|
||||
background: #f8f8f8;
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
.close-btn{
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: -6px;
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
&:hover{
|
||||
background: rgba(210, 23, 23, 0.5)
|
||||
}
|
||||
}
|
||||
& + .reg-item{
|
||||
margin-top: 18px;
|
||||
}
|
||||
}
|
||||
.action-bar{
|
||||
& .el-button+.el-button {
|
||||
margin-left: 15px;
|
||||
}
|
||||
& i {
|
||||
font-size: 20px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-tree-node{
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
.node-operation{
|
||||
float: right;
|
||||
}
|
||||
i[class*="el-icon"] + i[class*="el-icon"]{
|
||||
margin-left: 6px;
|
||||
}
|
||||
.el-icon-plus{
|
||||
color: #409EFF;
|
||||
}
|
||||
.el-icon-delete{
|
||||
color: #157a0c;
|
||||
}
|
||||
}
|
||||
|
||||
.left-scrollbar .el-scrollbar__view{
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.el-rate{
|
||||
display: inline-block;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
.el-upload__tip{
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
$selectedColor: #f6f7ff;
|
||||
$lighterBlue: #409EFF;
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.components-list {
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
.components-item {
|
||||
display: inline-block;
|
||||
width: 48%;
|
||||
margin: 1%;
|
||||
transition: transform 0ms !important;
|
||||
}
|
||||
}
|
||||
.components-draggable{
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.components-title{
|
||||
font-size: 14px;
|
||||
color: #222;
|
||||
margin: 6px 2px;
|
||||
.svg-icon{
|
||||
color: #666;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.components-body {
|
||||
padding: 8px 10px;
|
||||
background: $selectedColor;
|
||||
font-size: 12px;
|
||||
cursor: move;
|
||||
border: 1px dashed $selectedColor;
|
||||
border-radius: 3px;
|
||||
.svg-icon{
|
||||
color: #777;
|
||||
font-size: 15px;
|
||||
}
|
||||
&:hover {
|
||||
border: 1px dashed #787be8;
|
||||
color: #787be8;
|
||||
.svg-icon {
|
||||
color: #787be8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left-board {
|
||||
width: 260px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
}
|
||||
.left-scrollbar{
|
||||
height: calc(100vh - 42px);
|
||||
overflow: hidden;
|
||||
}
|
||||
.center-scrollbar {
|
||||
height: calc(100vh - 42px);
|
||||
overflow: hidden;
|
||||
border-left: 1px solid #f1e8e8;
|
||||
border-right: 1px solid #f1e8e8;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.center-board {
|
||||
height: 100vh;
|
||||
width: auto;
|
||||
margin: 0 350px 0 260px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.empty-info{
|
||||
position: absolute;
|
||||
top: 46%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #ccb1ea;
|
||||
letter-spacing: 4px;
|
||||
}
|
||||
.action-bar{
|
||||
position: relative;
|
||||
height: 42px;
|
||||
text-align: right;
|
||||
padding: 0 15px;
|
||||
box-sizing: border-box;;
|
||||
border: 1px solid #f1e8e8;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
.delete-btn{
|
||||
color: #F56C6C;
|
||||
}
|
||||
}
|
||||
.logo-wrapper{
|
||||
position: relative;
|
||||
height: 42px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #f1e8e8;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.logo{
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 6px;
|
||||
line-height: 30px;
|
||||
color: #00afff;
|
||||
font-weight: 600;
|
||||
font-size: 17px;
|
||||
white-space: nowrap;
|
||||
> img{
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.github{
|
||||
display: inline-block;
|
||||
vertical-align: sub;
|
||||
margin-left: 15px;
|
||||
> img{
|
||||
height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center-board-row {
|
||||
padding: 12px 12px 15px 12px;
|
||||
box-sizing: border-box;
|
||||
& > .el-form {
|
||||
// 69 = 12+15+42
|
||||
height: calc(100vh - 69px);
|
||||
}
|
||||
}
|
||||
.drawing-board {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.components-body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0;
|
||||
}
|
||||
.sortable-ghost {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
&::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 3px;
|
||||
background: rgb(89, 89, 223);
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
.components-item.sortable-ghost {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background-color: $selectedColor;
|
||||
}
|
||||
.active-from-item {
|
||||
& > .el-form-item{
|
||||
background: $selectedColor;
|
||||
border-radius: 6px;
|
||||
}
|
||||
& > .drawing-item-copy, & > .drawing-item-delete{
|
||||
display: initial;
|
||||
}
|
||||
& > .component-name{
|
||||
color: $lighterBlue;
|
||||
}
|
||||
}
|
||||
.el-form-item{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
.drawing-item{
|
||||
position: relative;
|
||||
cursor: move;
|
||||
&.unfocus-bordered:not(.activeFromItem) > div:first-child {
|
||||
border: 1px dashed #ccc;
|
||||
}
|
||||
.el-form-item{
|
||||
padding: 12px 10px;
|
||||
}
|
||||
}
|
||||
.drawing-row-item{
|
||||
position: relative;
|
||||
cursor: move;
|
||||
box-sizing: border-box;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 3px;
|
||||
padding: 0 2px;
|
||||
margin-bottom: 15px;
|
||||
.drawing-row-item {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.el-col{
|
||||
margin-top: 22px;
|
||||
}
|
||||
.el-form-item{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.drag-wrapper{
|
||||
min-height: 80px;
|
||||
}
|
||||
&.active-from-item{
|
||||
border: 1px dashed $lighterBlue;
|
||||
}
|
||||
.component-name{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
font-size: 12px;
|
||||
color: #bbb;
|
||||
display: inline-block;
|
||||
padding: 0 6px;
|
||||
}
|
||||
}
|
||||
.drawing-item, .drawing-row-item{
|
||||
&:hover {
|
||||
& > .el-form-item{
|
||||
background: $selectedColor;
|
||||
border-radius: 6px;
|
||||
}
|
||||
& > .drawing-item-copy, & > .drawing-item-delete{
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
& > .drawing-item-copy, & > .drawing-item-delete{
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
font-size: 12px;
|
||||
border: 1px solid;
|
||||
cursor: pointer;
|
||||
z-index: 1;
|
||||
}
|
||||
& > .drawing-item-copy{
|
||||
right: 56px;
|
||||
border-color: $lighterBlue;
|
||||
color: $lighterBlue;
|
||||
background: #fff;
|
||||
&:hover{
|
||||
background: $lighterBlue;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
& > .drawing-item-delete{
|
||||
right: 24px;
|
||||
border-color: #F56C6C;
|
||||
color: #F56C6C;
|
||||
background: #fff;
|
||||
&:hover{
|
||||
background: #F56C6C;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@import '@/styles/home';
|
||||
</style>
|
||||
|
||||
17
yudao-admin-ui/src/views/tool/build/main.js
Normal file
17
yudao-admin-ui/src/views/tool/build/main.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from '@/router'
|
||||
import '@/styles/index.scss'
|
||||
import '@/icons'
|
||||
import axios from 'axios'
|
||||
import Tinymce from '@/components/tinymce/index.vue'
|
||||
|
||||
Vue.component('tinymce', Tinymce)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.prototype.$axios = axios
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
@@ -125,8 +125,6 @@ import importTable from "./importTable";
|
||||
// 代码高亮插件
|
||||
import hljs from "highlight.js/lib/highlight";
|
||||
import "highlight.js/styles/github-gist.css";
|
||||
import {SysCommonStatusEnum} from "@/utils/constants";
|
||||
import {createTestDemo, updateTestDemo} from "@/api/tool/testDemo";
|
||||
hljs.registerLanguage("java", require("highlight.js/lib/languages/java"));
|
||||
hljs.registerLanguage("xml", require("highlight.js/lib/languages/xml"));
|
||||
hljs.registerLanguage("html", require("highlight.js/lib/languages/xml"));
|
||||
|
||||
Reference in New Issue
Block a user