xy 1 year ago
parent 13a4d3117c
commit 46218e6bba

@ -19,6 +19,7 @@
"core-js": "3.6.5", "core-js": "3.6.5",
"echarts": "^5.0.0", "echarts": "^5.0.0",
"element-ui": "^2.15.14", "element-ui": "^2.15.14",
"exceljs": "^4.4.0",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"normalize.css": "7.0.0", "normalize.css": "7.0.0",
@ -29,7 +30,9 @@
"vue-jsonp": "^2.0.0", "vue-jsonp": "^2.0.0",
"vue-router": "3.0.6", "vue-router": "3.0.6",
"vuex": "3.1.0", "vuex": "3.1.0",
"vxe-table": "^3.8.22" "vxe-pc-ui": "^3.1.0",
"vxe-table": "^3.8.25",
"vxe-table-plugin-export-xlsx": "^3.3.4"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "4.4.4", "@vue/cli-plugin-babel": "4.4.4",

@ -53,6 +53,14 @@ export function deal(flow_id,data) {
}) })
} }
export function getNextNode(params,isLoading=false) {
return request({
method: 'get',
url: '/api/oa/flow/get-next-node',
params,
isLoading
})
}
export function checkIsThroughNode(params,isLoading=false) { export function checkIsThroughNode(params,isLoading=false) {
return request({ return request({
method: 'get', method: 'get',

@ -32,20 +32,19 @@ if (process.env.NODE_ENV === 'production') {
//Vue.use(ElementUI, { locale }) //Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui按如下方式声明 // 如果想要中文版 element-ui按如下方式声明
Vue.use(ElementUI) Vue.use(ElementUI)
// vxe-table
import { VxeUI, VxeUpload } from 'vxe-pc-ui'
import 'vxe-pc-ui/lib/style.css'
Vue.use(VxeUpload)
import VxeTable from 'vxe-table' import VxeTable from 'vxe-table'
//import { VxeButton, VxeIcon, VxeTable, VxeColumn, VxeColgroup, VxeModal, VxeToolbar, VxeTableEditModule, VxeTableValidatorModule, VxeTableExportModule } from "vxe-table";
import "vxe-table/styles/index.scss" import "vxe-table/styles/index.scss"
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'
import ExcelJS from 'exceljs'
VxeTable.use(VXETablePluginExportXLSX, {
ExcelJS
})
Vue.use(VxeTable) Vue.use(VxeTable)
// Vue.use(VxeTableEditModule);
// Vue.use(VxeTableValidatorModule);
// Vue.use(VxeTableExportModule);
// Vue.use(VxeIcon);
// Vue.use(VxeTable);
// Vue.use(VxeColumn);
// Vue.use(VxeColgroup);
// Vue.use(VxeModal);
// Vue.use(VxeToolbar);
// Vue.use(VxeButton);
Vue.config.productionTip = false Vue.config.productionTip = false

@ -3,6 +3,7 @@ import { CreateElement, VNode } from "vue";
import moment from "moment"; import moment from "moment";
import { getToken } from "@/utils/auth"; import { getToken } from "@/utils/auth";
import { deepCopy } from "@/utils/index"; import { deepCopy } from "@/utils/index";
import axios from 'axios'
import { flowList } from "@/api/flow" import { flowList } from "@/api/flow"
/** /**
* @param {String} device 'desktop' or 'mobile' * @param {String} device 'desktop' or 'mobile'
@ -248,7 +249,44 @@ export default function formBuilder(device, info, h, row, pWrite = false,pReadab
); );
break; break;
case "file": case "file":
formItem = h( formItem = row ?
h(
'vxe-upload',
{
props: {
value: row[info.name],
'progress-text': "{percent}%",
'more-config': {maxCount: 1, layout: 'horizontal'},
'show-button-text': false,
'limit-size': 20,
multiple: !!info.multiple,
readonly: pReadable,
'upload-method': ({ file }) => {
const formData = new FormData()
formData.append('file', file)
return axios.post(process.env.VUE_APP_UPLOAD_API, formData, {
headers: {
Authorization: `Bearer ${getToken()}`,
}
}).then((response) => {
if (response.status === 200 && !response.data.code) {
if (!(row[info.name] instanceof Array)) {
row[info.name] = []
}
row[info.name].push({
...response.data.data,
name: response.data.data.original_name,
url: response.data.data.url,
})
} else {
this.$message.error("上传失败")
}
})
}
}
}
) :
h(
formBuilderMap(device).get(info.type), formBuilderMap(device).get(info.type),
{ {
props: { props: {
@ -258,7 +296,7 @@ export default function formBuilder(device, info, h, row, pWrite = false,pReadab
}, },
accept: accept:
"application/msword,image/jpeg,application/pdf,image/png,application/vnd.ms-powerpoint,text/plain,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/msword,image/jpeg,application/pdf,image/png,application/vnd.ms-powerpoint,text/plain,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
multiple: true, multiple: !!info.multiple,
fileList: this.file[info.name], fileList: this.file[info.name],
beforeUpload: (file) => { beforeUpload: (file) => {
if (file.size / 1024 / 1024 > 20) { if (file.size / 1024 / 1024 > 20) {
@ -616,9 +654,19 @@ export default function formBuilder(device, info, h, row, pWrite = false,pReadab
h, h,
row, row,
info._writeable, info._writeable,
info._readable, false,
); );
}, },
[subField.type === 'file' ? 'default' : false]: ({ row }) => {
return formBuilder.bind(this)(
device,
subField,
h,
row,
info._writeable,
true,
);
}
}, },
}) })
), ),
@ -647,7 +695,7 @@ export default function formBuilder(device, info, h, row, pWrite = false,pReadab
color: "#333", color: "#333",
}, },
}, },
this.form[info.name] ? moment(this.form[info.name]).format("YYYY年MM月DD日 HH时mm分ss秒") : '' this.form[info.name] ? moment(this.form[info.name]).format("YYYY年MM月DD日 HH时mm分") : ''
); );
break; break;
case "select": case "select":

@ -198,3 +198,8 @@ export function parseMoney(money, precision = 2) {
if (isNaN(Number(money))) return Number(0).toFixed(precision) if (isNaN(Number(money))) return Number(0).toFixed(precision)
return Number(money).toFixed(precision).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') return Number(money).toFixed(precision).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
} }
export function generateRandomString() {
return Math.random().toString(36).substring(2, 34)+new Date().getTime();
}

@ -2,10 +2,18 @@ import store from '@/store'
/** /**
* @param{string} printJs 打印模版 * @param{string} printJs 打印模版
* @param{boolean} isLog 是否带审批 * @param{boolean} isLog 是否带审批
* @param{string} logContent 审批表格html * @param{object} form data数据
* @param{string} [logContent] 审批表格html
* @return{void} * @return{void}
**/ **/
export function print(printJs, isLog, logContent) { export function print(printJs, isLog, form, logContent) {
const staticMap = new Map([
['apply_name', () => `<span>${form.creator?.name}</span>`],
['apply_department_name', () => `<span>${form.creator_department?.name}</span>`],
['apply_sign', () => `<img src="${form.creator?.sign_file}" alt="${form.creator?.name}" style="max-height: 80px; ">`],
['created_at', () => `<span>${form.created_at}</span>`],
])
let printStr = printJs let printStr = printJs
const regexField = /<field[^>]*>(.*?)<\/field>/g; const regexField = /<field[^>]*>(.*?)<\/field>/g;
let fieldMaths = [] let fieldMaths = []
@ -16,11 +24,14 @@ export function print(printJs, isLog, logContent) {
} }
fieldMaths.forEach(fieldMath => { fieldMaths.forEach(fieldMath => {
const matchName = fieldMath.match(/name="([^"]+)"/); const matchName = fieldMath.match(/name="([^"]+)"/);
if (matchName) { if (matchName) {
const nameValue = matchName[1]; const nameValue = matchName[1];
if (Array.from(staticMap.keys()).indexOf(nameValue) !== -1) {
printStr = printStr.replace(fieldMath, staticMap.get(nameValue))
} else {
const value = store.getters.device === 'desktop' ? document.querySelector(`[for=${nameValue}]+div`).innerHTML : document.querySelector(`[for=${nameValue}] > div:nth-child(2)`).innerHTML const value = store.getters.device === 'desktop' ? document.querySelector(`[for=${nameValue}]+div`).innerHTML : document.querySelector(`[for=${nameValue}] > div:nth-child(2)`).innerHTML
printStr = printStr.replace(fieldMath,`<span>${value}</span>`) printStr = printStr.replace(fieldMath,`<span>${value}</span>`)
}
} else { } else {
console.log('未找到name属性'); console.log('未找到name属性');
} }

@ -20,7 +20,8 @@
:row-config="{ isHover: true }" :row-config="{ isHover: true }"
:header-cell-style="{ 'white-space': 'wrap' }" :header-cell-style="{ 'white-space': 'wrap' }"
:print-config="{}" :print-config="{}"
:export-config="{}" :export-config="{
}"
:column-config="{ resizable: true }" :column-config="{ resizable: true }"
:data="tableData.admins"> :data="tableData.admins">
<vxe-column type="seq" width="50" align="center" fixed="left"></vxe-column> <vxe-column type="seq" width="50" align="center" fixed="left"></vxe-column>
@ -54,6 +55,7 @@
</template> </template>
</vxe-column> </vxe-column>
</vxe-colgroup> </vxe-colgroup>
<vxe-column title="备注" min-width="200" header-align="center" align="left"></vxe-column>
</vxe-table> </vxe-table>
</card-container> </card-container>
</div> </div>
@ -70,7 +72,8 @@ export default {
}, },
tableData: { tableData: {
admins: [], admins: [],
dates: [] dates: [],
leave_types: []
} }
} }
}, },

@ -291,4 +291,7 @@ export default {
} }
::v-deep .el-form-item__content { ::v-deep .el-form-item__content {
} }
::v-deep .el-radio, .el-radio__input {
line-height: 1.5;
}
</style> </style>

@ -4,7 +4,7 @@
:value="visible" :value="visible"
show-footer show-footer
:z-index="zIndex" :z-index="zIndex"
title="" title="转"
show-zoom show-zoom
:fullscreen="$store.getters.device === 'mobile'" :fullscreen="$store.getters.device === 'mobile'"
show-confirm-button show-confirm-button
@ -106,7 +106,7 @@
</template> </template>
<script> <script>
import { getNextNodeUsers, assign, preShare } from "@/api/flow"; import { getNextNode, getNextNodeUsers, assign, preShare } from "@/api/flow";
import { PopupManager } from 'element-ui/lib/utils/popup' import { PopupManager } from 'element-ui/lib/utils/popup'
export default { export default {
@ -134,6 +134,7 @@ export default {
next_node_id: "", next_node_id: "",
}, },
node: {},
node2Users: new Map(), node2Users: new Map(),
pickUsers: [], pickUsers: [],
@ -174,6 +175,17 @@ export default {
} }
}, },
async getNextNode() {
try {
const res = await getNextNode({
id: this.result.id
})
this.node = res.currentNode || {}
} catch(err) {
console.error(err)
}
},
async getNextNodesUsers() { async getNextNodesUsers() {
try { try {
const nodeIds = this.node?.nextNodes?.map(node => node.id); const nodeIds = this.node?.nextNodes?.map(node => node.id);
@ -209,9 +221,6 @@ export default {
title() { title() {
return this.config?.customModel?.name + '流转' return this.config?.customModel?.name + '流转'
}, },
node() {
return this.config?.currentNode || {};
},
isLastNode() { isLastNode() {
return this.node?.category === 'end' return this.node?.category === 'end'
}, },
@ -220,13 +229,13 @@ export default {
} }
}, },
watch: { watch: {
visible(newVal) { async visible(newVal) {
if(newVal) { if(newVal) {
this.zIndex = PopupManager.nextZIndex() this.zIndex = PopupManager.nextZIndex()
await this.getNextNode()
if(this.node && this.node.nextNodes && this.node.nextNodes?.length > 0 && !this.isLastNode) { if(this.node && this.node.nextNodes && this.node.nextNodes?.length > 0 && !this.isLastNode) {
this.getNextNodesUsers() await this.getNextNodesUsers()
this.getPreShare() this.getPreShare()
} }
} }

@ -255,6 +255,7 @@ import MobileForm from "./MobileForm.vue";
import assign from "./components/assign.vue"; import assign from "./components/assign.vue";
import forward from "./components/forward.vue"; import forward from "./components/forward.vue";
import rollback from "./components/rollback.vue"; import rollback from "./components/rollback.vue";
import { generateRandomString } from '@/utils'
import { import {
create, create,
deal, deal,
@ -304,6 +305,7 @@ export default {
rules: {}, rules: {},
subRules: {}, subRules: {},
flows: [], flows: [],
csrf_token: '',
}; };
}, },
methods: { methods: {
@ -342,6 +344,7 @@ export default {
} }
}, },
async print(isLog=false) { async print(isLog=false) {
const _this = this
let customModelId = this.config.customModel.id || this.$route.query.module_id let customModelId = this.config.customModel.id || this.$route.query.module_id
const modelRes = await fieldConfig(customModelId,true) const modelRes = await fieldConfig(customModelId,true)
let pickTemplate = 0 let pickTemplate = 0
@ -418,13 +421,13 @@ export default {
type: 'html', type: 'html',
download: false download: false
}) })
print(printText, isLog, res.content) print(printText, isLog, _this.config.flow, res.content)
} else { } else {
print(printText, isLog) print(printText, isLog, _this.config.flow)
} }
}, },
generateForm(object, fields, relation = false, pname) { generateForm(object, fields, relation = false, pname, pFilelist = this.fileList) {
fields.forEach((field) => { fields.forEach((field) => {
if (field.rules && field.rules.length > 0 && this.writeableFields.find(i => i === field.id) && !relation) { if (field.rules && field.rules.length > 0 && this.writeableFields.find(i => i === field.id) && !relation) {
this.rules[field.name] = field.rules.map((rule) => { this.rules[field.name] = field.rules.map((rule) => {
@ -482,23 +485,28 @@ export default {
}); });
} }
if (field.type === "file") { if (field.type === "file") {
this.fileList[field.name] = []; pFilelist[field.name] = relation ? [[]] : [];
} }
if (field.type === "relation") { if (field.type === "relation") {
this.subRules[`${field.name}_rules`] = {} this.subRules[`${field.name}_rules`] = {}
object[field.name] = [{}]; object[field.name] = [{}];
pFilelist[field.name] = {}
this.generateForm( this.generateForm(
object[field.name][0], object[field.name][0],
this.subConfig.get(field.sub_custom_model_id)?.customModel?.fields, this.subConfig.get(field.sub_custom_model_id)?.customModel?.fields,
true, true,
field.name field.name,
pFilelist[field.name]
); );
} else { } else {
object[field.name] = field.default_value ? field.default_value : ""; if (/\/detail/.test(this.$route.path) && this.$route.query.flow_id) {
object[field.name] = "";
} else {
object[field.name] = (this.writeableFields.indexOf(field.id) !== -1 && field.default_value) ? field.default_value : "";
}
} }
}); });
console.log(345, this.rules)
this.form['flow_title'] = this.config?.flow?.title ?? `${this.config.customModel.name}${this.$store.getters.name} ${this.$moment().format('YYYY-MM-DD HH:mm')}` this.form['flow_title'] = this.config?.flow?.title ?? `${this.config.customModel.name}${this.$store.getters.name} ${this.$moment().format('YYYY-MM-DD HH:mm')}`
}, },
formatTime(time) { formatTime(time) {
@ -553,6 +561,7 @@ export default {
this.config = res; this.config = res;
this.generateForm(this.form, fields); this.generateForm(this.form, fields);
this.form = Object.assign({}, this.form); this.form = Object.assign({}, this.form);
this.fileList = Object.assign({}, this.fileList);
const { data } = res?.flow; const { data } = res?.flow;
for (let key in data) { for (let key in data) {
try { try {
@ -581,7 +590,9 @@ export default {
loading.close(); loading.close();
} }
} else if (!this.$route.query.flow_id) { } else if (!this.$route.query.flow_id) {
//
try { try {
this.csrf_token = generateRandomString()
const res = await preConfig(this.$route.query.module_id); const res = await preConfig(this.$route.query.module_id);
const { fields } = res?.customModel; const { fields } = res?.customModel;
let subFormRequest = []; let subFormRequest = [];
@ -603,6 +614,7 @@ export default {
this.generateForm(this.form, fields); this.generateForm(this.form, fields);
this.handleDefaultJSON(); this.handleDefaultJSON();
this.form = Object.assign({}, this.form); this.form = Object.assign({}, this.form);
this.fileList = Object.assign({}, this.fileList);
loading.close(); loading.close();
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@ -716,6 +728,7 @@ export default {
callback = () => this.$router.push("/flow/list/todo"); callback = () => this.$router.push("/flow/list/todo");
} }
} else { } else {
copyForm['csrf_token'] = this.csrf_token
this.result = await create(this.$route.query.module_id, copyForm); this.result = await create(this.$route.query.module_id, copyForm);
} }
callback(); callback();

@ -68,6 +68,8 @@
</template> </template>
<script> <script>
import { getToken } from '@/utils/auth'
import { isExternal } from '@/utils/validate'
import { flow } from "@/api/flow" import { flow } from "@/api/flow"
export default { export default {
data() { data() {
@ -87,8 +89,12 @@ export default {
}, },
toCreate(flow,cate) { toCreate(flow,cate) {
if(flow.url) { if(isExternal(flow.url)) {
window.open(flow.url,'_blank') if (/\?.+/.test(flow.url)) {
window.open(flow.url + `&auth_token=${getToken()}`,'_blank')
} else {
window.open(flow.url + `?auth_token=${getToken()}`,'_blank')
}
} else { } else {
this.$router.push({ this.$router.push({
path: '/flow/create', path: '/flow/create',

Loading…
Cancel
Save