xy 1 year ago
parent 13a4d3117c
commit 46218e6bba

@ -19,6 +19,7 @@
"core-js": "3.6.5",
"echarts": "^5.0.0",
"element-ui": "^2.15.14",
"exceljs": "^4.4.0",
"js-cookie": "2.2.0",
"moment": "^2.29.4",
"normalize.css": "7.0.0",
@ -29,7 +30,9 @@
"vue-jsonp": "^2.0.0",
"vue-router": "3.0.6",
"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": {
"@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) {
return request({
method: 'get',

@ -32,20 +32,19 @@ if (process.env.NODE_ENV === 'production') {
//Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui按如下方式声明
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 { VxeButton, VxeIcon, VxeTable, VxeColumn, VxeColgroup, VxeModal, VxeToolbar, VxeTableEditModule, VxeTableValidatorModule, VxeTableExportModule } from "vxe-table";
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(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

@ -3,6 +3,7 @@ import { CreateElement, VNode } from "vue";
import moment from "moment";
import { getToken } from "@/utils/auth";
import { deepCopy } from "@/utils/index";
import axios from 'axios'
import { flowList } from "@/api/flow"
/**
* @param {String} device 'desktop' or 'mobile'
@ -248,7 +249,44 @@ export default function formBuilder(device, info, h, row, pWrite = false,pReadab
);
break;
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),
{
props: {
@ -258,7 +296,7 @@ export default function formBuilder(device, info, h, row, pWrite = false,pReadab
},
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",
multiple: true,
multiple: !!info.multiple,
fileList: this.file[info.name],
beforeUpload: (file) => {
if (file.size / 1024 / 1024 > 20) {
@ -616,9 +654,19 @@ export default function formBuilder(device, info, h, row, pWrite = false,pReadab
h,
row,
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",
},
},
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;
case "select":

@ -198,3 +198,8 @@ export function parseMoney(money, precision = 2) {
if (isNaN(Number(money))) return Number(0).toFixed(precision)
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{boolean} isLog 是否带审批
* @param{string} logContent 审批表格html
* @param{object} form data数据
* @param{string} [logContent] 审批表格html
* @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
const regexField = /<field[^>]*>(.*?)<\/field>/g;
let fieldMaths = []
@ -16,11 +24,14 @@ export function print(printJs, isLog, logContent) {
}
fieldMaths.forEach(fieldMath => {
const matchName = fieldMath.match(/name="([^"]+)"/);
if (matchName) {
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
printStr = printStr.replace(fieldMath,`<span>${value}</span>`)
}
} else {
console.log('未找到name属性');
}

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

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

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

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

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

Loading…
Cancel
Save