master
weizong song 4 months ago
parent 32535a7705
commit d20e7f971e

@ -3,7 +3,8 @@ ENV = 'development'
# base api
#VUE_APP_BASE_API='http://192.167.20.118:8080/'
VUE_APP_BASE_API='https://cz-hjjc-test.115.langye.net'
VUE_APP_BASE_API='http://czemc.localhost'
VUE_APP_UPLOAD_API='https://cz-hjjc-test.115.langye.net/api/upload-file'
VUE_APP_PREVIEW=//view.langye.net/preview/onlinePreview
VUE_APP_MODULE_NAME=oa
VUE_APP_OUTPUT_DIR='../backend/public/oa/'

@ -6,3 +6,4 @@ VUE_APP_BASE_API=''
VUE_APP_UPLOAD_API='/api/upload-file'
VUE_APP_PREVIEW=//view.langye.net/preview/onlinePreview
VUE_APP_MODULE_NAME=oa
VUE_APP_OUTPUT_DIR='../backend/public/oa/'

@ -33,7 +33,7 @@
"vue-router": "3.0.6",
"vuex": "3.1.0",
"vxe-pc-ui": "^3.1.0",
"vxe-table": "^3.8.25",
"vxe-table": "3.8.25",
"vxe-table-plugin-export-xlsx": "^3.3.4",
"xlsx": "^0.18.5"
},

@ -0,0 +1,45 @@
import request from "@/utils/request";
export function index(params) {
return request({
method: 'get',
url: '/api/oa/meeting-minutes/index',
params
})
}
export function show(params) {
return request({
method: 'get',
url: '/api/oa/meeting-minutes/show',
params
})
}
export function save(data, isLoading = true) {
return request({
method: 'post',
url: '/api/oa/meeting-minutes/save',
data,
isLoading
})
}
export function destroy(params, isLoading = true) {
return request({
method: 'get',
url: '/api/oa/meeting-minutes/destroy',
params,
isLoading
})
}
export function getFlows(params, isLoading = true) {
return request({
method: 'get',
url: '/api/oa/meeting-minutes/get-flows',
params,
isLoading
})
}

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:width="defaultModalSize.width"
:height="defaultModalSize.height"
show-zoom
@ -34,6 +35,8 @@ export default {
data() {
return {
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `online-file-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
zIndex: PopupManager.nextZIndex(),
showModal:false,
codeUri: "",

@ -33,12 +33,14 @@ if (process.env.NODE_ENV === 'production') {
// 如果想要中文版 element-ui按如下方式声明
Vue.use(ElementUI)
// vxe-table
import { VxeUI, VxeUpload, VxeDatePicker,VxeNumberInput } from 'vxe-pc-ui'
// vxe-table / vxe-pc-ui
// 注意vxe-pc-ui 的部分组件(如 vxe-modal需要显式 Vue.use 注册,否则会退化成“未知标签”,其内容会直接渲染在页面里
import { VxeUI, VxeUpload, VxeDatePicker, VxeNumberInput, VxeModal } from 'vxe-pc-ui'
import 'vxe-pc-ui/lib/style.css'
Vue.use(VxeUpload)
Vue.use(VxeDatePicker)
Vue.use(VxeNumberInput)
Vue.use(VxeModal)
import VxeTable from 'vxe-table'
import "vxe-table/styles/index.scss"
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'

@ -90,6 +90,21 @@ export const constantRoutes = [
}
],
},
{
path: "/meeting-minutes",
component: Layout,
redirect: "/meeting-minutes/index",
hidden: true, // 隐藏硬编码的菜单,由后端配置的菜单控制显示
meta: { title: "会议纪要管理", icon: "el-icon-document" },
children: [
{
path: "index",
name: "MeetingMinutes",
component: () => import("@/views/MeetingMinutes/index"),
meta: { title: "会议纪要管理", icon: "el-icon-document" },
},
],
},
// 404 page must be placed at the end !!!
//{ path: '*', redirect: '/404', hidden: true }

@ -760,6 +760,10 @@ export default function formBuilder(
const $table = this.$refs[`subForm-${info.name}`];
if ($table) {
const record = {};
// 确保子表数据为数组,避免空值时调用 unshift 报错
if (!Array.isArray(this.form[info.name])) {
this.$set(this.form, info.name, []);
}
this.form[info.name].unshift(record);
// 临时数据不好验证长度
// const { row: newRow } = await $table.insert(

@ -2,6 +2,7 @@
<div>
<vxe-modal
:z-index="zIndex"
:id="modalId"
:value="isShow"
show-footer
title="公共文件柜栏目"
@ -76,6 +77,8 @@ export default {
return {
defaultModalSize,
zIndex: PopupManager.nextZIndex(),
// vxe-ui v3.5+ modal.id
modalId: `document-menu-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
loading: false,
form: {
pid: 0,

@ -0,0 +1,520 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="isShow"
show-footer
:z-index="zIndex"
:title="type === 'add' ? '新增会议纪要' : type === 'edit' ? '编辑会议纪要' : '查看会议纪要'"
:show-confirm-button="type !== 'view'"
:width="defaultModalSize.width"
:height="defaultModalSize.height"
esc-closable
transfer
show-zoom
resize
:fullscreen="$store.getters.device === 'mobile'"
@input="(e) => $emit('update:isShow', e)"
>
<el-form
ref="elForm"
:model="form"
:rules="rules"
label-position="top"
label-width="100"
>
<el-form-item label="会议纪要标题" prop="title">
<el-input v-model="form.title" :disabled="true" placeholder="上传附件后自动填充文件名" />
</el-form-item>
<el-form-item label="关联上会审议流程" prop="flow_ids">
<el-select
v-model="form.flow_ids"
multiple
filterable
placeholder="请选择要关联的上会审议流程"
style="width: 100%;"
:disabled="type === 'view'"
@focus="loadFlows"
>
<el-option
v-for="flow in availableFlows"
:key="flow.id"
:label="(flow.title || flow.no || ('流程' + flow.id)) + ' (' + (flow.no || '') + ')'"
:value="flow.id"
>
<span style="float: left">{{ flow.title || flow.no || ('流程' + flow.id) }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ flow.no || '' }}</span>
</el-option>
</el-select>
<div style="margin-top: 8px; color: #909399; font-size: 12px;">
提示可以关联多个上会审议审批流程
</div>
</el-form-item>
<el-form-item label="附件上传" prop="files" v-if="type !== 'view'">
<el-upload
:action="action"
:headers="{
Authorization: `Bearer ${getToken()}`,
}"
:before-upload="beforeUpload"
:on-success="uploadSuccess"
:on-remove="uploadRemove"
:on-error="uploadError"
:on-progress="uploadProgress"
:limit="1"
:file-list="fileList"
>
<el-button size="small" type="primary" :disabled="uploadingFile">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
<span v-if="uploadingFile" style="color: #409EFF;">...</span>
<span v-else>10Mb</span>
</div>
</el-upload>
</el-form-item>
<el-form-item label="附件" v-if="type === 'view' && fileList.length > 0">
<div v-for="(file, index) in fileList" :key="index" style="margin-bottom: 8px;">
<el-link
type="primary"
style="margin-right: 10px; cursor: pointer;"
@click="previewFile(file)"
>
<i class="el-icon-view"></i> {{ file.name }}
</el-link>
<el-link
type="primary"
style="cursor: pointer;"
@click="downloadFile(file)"
>
<i class="el-icon-download"></i> 下载
</el-link>
</div>
</el-form-item>
<el-form-item label="内容清单" prop="items">
<div v-for="(item, index) in form.items" :key="index" style="margin-bottom: 15px; padding: 15px; border: 1px solid #e4e7ed; border-radius: 4px;">
<el-row :gutter="20">
<el-col :span="6">
<el-select
v-model="item.type"
placeholder="请选择类型"
style="width: 100%;"
:disabled="type === 'view'"
>
<el-option label="&ldquo;三重一大&rdquo;事项" value="&ldquo;三重一大&rdquo;事项"></el-option>
<el-option label="资金申请" value="资金申请"></el-option>
<el-option label="资金支付" value="资金支付"></el-option>
<el-option label="其他" value="其他"></el-option>
</el-select>
</el-col>
<el-col :span="16">
<el-input
v-model="item.content"
type="textarea"
:autosize="{ minRows: 2 }"
placeholder="请输入内容"
:disabled="type === 'view'"
/>
</el-col>
<el-col :span="2" v-if="type !== 'view'">
<el-button
type="danger"
icon="el-icon-delete"
size="small"
@click="removeItem(index)"
:disabled="form.items.length <= 1"
></el-button>
</el-col>
</el-row>
</div>
<el-button
v-if="type !== 'view'"
type="primary"
icon="el-icon-plus"
size="small"
@click="addItem"
>添加内容项</el-button>
</el-form-item>
</el-form>
<template #footer v-if="type !== 'view'">
<el-button type="primary" :loading="loading" @click="submit"
>确认</el-button
>
<el-button @click="$emit('update:isShow', false)">取消</el-button>
</template>
<template #footer v-else>
<el-button @click="$emit('update:isShow', false)">关闭</el-button>
</template>
</vxe-modal>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import { save, show, getFlows } from "@/api/meetingMinutes";
import { PopupManager } from "element-ui/lib/utils/popup";
import { defaultModalSize, uploadSize } from "@/settings";
import { formatFileSize } from "@/utils"
export default {
props: {
type: {
type: String,
default: 'add',
required: true
},
isShow: {
type: Boolean,
default: false,
required: true,
}
},
data() {
return {
uploadSize,
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `meeting-minutes-add-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
zIndex: PopupManager.nextZIndex(),
loading: false,
form: {
id: "",
title: "",
files: [],
flow_ids: [],
items: [
{
type: "",
content: ""
}
]
},
uploadingFile: false, //
action: process.env.VUE_APP_UPLOAD_API,
fileList: [],
availableFlows: [],
rules: {
files: [
{ validator: this.validateFiles, trigger: 'change' }
],
},
};
},
computed: {},
watch: {
isShow(newVal) {
if(newVal) {
this.zIndex = PopupManager.nextZIndex()
if (this.type === 'add') {
this.resetForm()
}
} else {
this.fileList = []
this.availableFlows = []
}
}
},
created() {
this.loadFlows()
},
methods: {
formatFileSize,
resetForm() {
this.form = {
id: "",
title: "",
files: [],
flow_ids: [],
items: [
{
type: "",
content: ""
}
]
}
this.fileList = []
this.uploadingFile = false
if (this.$refs.elForm) {
this.$refs.elForm.resetFields()
}
},
validateFiles(rule, value, callback) {
//
if (this.uploadingFile || window.$_uploading) {
callback(new Error('文件正在上传中,请稍候...'))
return
}
//
const uploadedFiles = this.fileList.filter(file => {
// response.data.id url
return (file.response && file.response.data && file.response.data.id) || file.url
})
if (uploadedFiles.length === 0) {
callback(new Error('必须上传一个附件'))
} else if (uploadedFiles.length > 1) {
callback(new Error('只能上传一个附件'))
} else {
callback() //
}
},
addItem() {
this.form.items.push({
type: "",
content: ""
})
},
removeItem(index) {
if (this.form.items.length > 1) {
this.form.items.splice(index, 1)
}
},
async loadFlows() {
if (this.availableFlows.length > 0) {
return //
}
try {
const params = {}
// ID
if (this.type === 'edit' && this.form.id) {
params.meeting_minute_id = this.form.id
}
const res = await getFlows(params)
this.availableFlows = res || []
} catch (err) {
console.error('加载流程列表失败:', err)
}
},
getDetail (data) {
this.resetForm()
for (let key in this.form) {
if (data[key] !== undefined && key !== 'items') {
this.form[key] = data[key]
}
}
//
if (data.flows && data.flows instanceof Array) {
this.form.flow_ids = data.flows.map(i => i.id)
}
//
this.fileList = (data['files_details'] && data['files_details'] instanceof Array)
? data['files_details'].map(i => ({
name: i.original_name,
url: i.url,
response: {
data: i
}
}))
: []
//
if (data.items && data.items instanceof Array && data.items.length > 0) {
this.form.items = data.items.map(i => ({
type: i.type || "",
content: i.content || ""
}))
} else {
this.form.items = [{
type: "",
content: ""
}]
}
//
if (this.type === 'edit' && this.form.id) {
this.availableFlows = [] //
this.loadFlows()
}
},
uploadRemove(file, fileList) {
this.fileList = fileList
//
if (fileList.length === 0) {
this.form.title = ""
}
//
this.$nextTick(() => {
if (this.$refs.elForm) {
this.$refs.elForm.validateField('files')
}
})
},
beforeUpload(file) {
const isLt = file.size < uploadSize
if (!isLt) {
this.$message.error(`上传文件大小不能超过${formatFileSize(uploadSize)}!`)
return false
}
//
this.uploadingFile = true
window.$_uploading = true
//
this.$nextTick(() => {
if (this.$refs.elForm) {
this.$refs.elForm.validateField('files')
}
})
return true
},
uploadProgress(event, file, fileList) {
//
this.uploadingFile = true
},
uploadSuccess(response, file, fileList) {
this.uploadingFile = false
window.$_uploading = false
if (response.code) {
//
const index = fileList.indexOf(file)
if (index > -1) {
fileList.splice(index, 1)
}
this.$message.warning(response.msg)
this.fileList = fileList
//
this.$nextTick(() => {
if (this.$refs.elForm) {
this.$refs.elForm.validateField('files')
}
})
} else {
//
this.fileList = fileList
//
if (fileList.length === 1 && fileList[0].response && fileList[0].response.data) {
const fileName = fileList[0].response.data.original_name || fileList[0].name
this.form.title = fileName
}
//
if (fileList.length > 1) {
this.$message.warning('只能上传一个附件,已自动移除之前的附件')
this.fileList = [fileList[fileList.length - 1]]
//
if (this.fileList[0].response && this.fileList[0].response.data) {
const fileName = this.fileList[0].response.data.original_name || this.fileList[0].name
this.form.title = fileName
}
}
//
this.$nextTick(() => {
if (this.$refs.elForm) {
this.$refs.elForm.validateField('files')
}
})
}
},
uploadError(err, file, fileList) {
this.uploadingFile = false
window.$_uploading = false
this.$message.error('文件上传失败,请重试')
//
const index = fileList.indexOf(file)
if (index > -1) {
fileList.splice(index, 1)
}
this.fileList = fileList
//
this.$nextTick(() => {
if (this.$refs.elForm) {
this.$refs.elForm.validateField('files')
}
})
},
getToken,
previewFile(file) {
let fileUrl = null;
if (file.url) {
fileUrl = file.url;
} else if (file.response && file.response.data && file.response.data.url) {
fileUrl = file.response.data.url;
}
if (!fileUrl) return;
//
if (this.type === 'view') {
const previewUrl = `${window.location.origin}/admin/#/preview?url=${encodeURIComponent(fileUrl)}`;
window.open(previewUrl, '_blank');
} else {
// 使
this.$bus.$emit("online-file", fileUrl);
}
},
downloadFile(file) {
//
let fileId = null;
if (file.id) {
fileId = file.id;
} else if (file.response && file.response.data && file.response.data.id) {
fileId = file.response.data.id;
}
if (fileId) {
this.$bus.$emit("online-download", fileId);
}
},
submit() {
//
if (this.uploadingFile || window.$_uploading) {
this.$message.warning("文件正在上传中,请稍候...")
return
}
//
const uploadedFiles = this.fileList.filter(file => {
return (file.response && file.response.data && file.response.data.id) || file.url
})
if (uploadedFiles.length === 0) {
this.$message.error('必须上传一个附件')
//
this.$nextTick(() => {
if (this.$refs.elForm) {
this.$refs.elForm.validateField('files')
}
})
return
}
if (uploadedFiles.length > 1) {
this.$message.error('只能上传一个附件')
return
}
this.$refs["elForm"].validate(async (valid) => {
if (valid) {
this.loading = true;
try {
// 使ID
this.form.files = uploadedFiles.map(i => {
if (i.response && i.response.data && i.response.data.id) {
return i.response.data.id
} else if (i.url && i.id) {
return i.id
}
return null
}).filter(i => !!i)
//
this.form.items = this.form.items.filter(item => item.type && item.content)
if (this.form.items.length === 0) {
this.$message.error('至少需要添加一个内容清单项')
this.loading = false;
return
}
await save(this.form);
this.$message.success(this.form.id ? "更新成功" : "新增成功");
this.$emit("refresh");
this.$emit("update:isShow", false);
this.loading = false;
this.resetForm()
} catch (err) {
this.loading = false;
}
}
});
},
},
};
</script>
<style scoped lang="scss"></style>

@ -0,0 +1,380 @@
<template>
<div>
<card-container>
<vxe-toolbar export print ref="toolbar">
<template #buttons>
<el-button
icon="el-icon-plus"
type="primary"
size="small"
@click="isShowAdd = true"
>新增</el-button
>
<el-button
icon="el-icon-search"
type="primary"
plain
size="small"
@click="getList"
>搜索</el-button
>
</template>
</vxe-toolbar>
<vxe-table
ref="table"
stripe
style="margin-top: 10px"
:loading="loading"
keep-source
show-overflow
:column-config="{ resizable: true }"
:edit-rules="validRules"
:edit-config="{
trigger: 'manual',
mode: 'row',
showStatus: true,
isHover: true,
autoClear: false,
}"
:align="allAlign"
:data="tableData"
>
<vxe-column type="seq" width="58" align="center" />
<vxe-column
field="title"
width="200"
title="会议纪要标题"
:edit-render="{ name: 'input', attrs: { type: 'text' } }"
/>
<vxe-column
field="items"
min-width="250"
title="内容清单"
:formatter="({ cellValue }) => {
if (cellValue && cellValue instanceof Array && cellValue.length > 0) {
return cellValue.map(i => (i.type || '') + '' + (i.content || '')).join('')
}
return '无'
}"
/>
<vxe-column
field="flows"
width="200"
title="关联流程"
:formatter="({ cellValue }) => {
if (cellValue && cellValue instanceof Array && cellValue.length > 0) {
return cellValue.map(i => i.title || i.no || ('流程' + i.id)).join('、')
}
return '未关联'
}"
/>
<vxe-column field="files_details" title="附件" min-width="220" header-align="center" align="left" :edit-render="{}">
<template #default="{ row }">
<div v-if="row.files_details && row.files_details.length > 0">
<div v-for="(file, index) in row.files_details" :key="index" style="margin-bottom: 4px;">
<el-link
type="primary"
style="margin-right: 10px; cursor: pointer;"
@click="previewFile(file)"
>
<i class="el-icon-view"></i> {{ file.original_name || file.name }}
</el-link>
<el-link
type="primary"
style="cursor: pointer;"
@click="downloadFile(file)"
>
<i class="el-icon-download"></i> 下载
</el-link>
</div>
</div>
<span v-else style="color: #909399;">无附件</span>
</template>
<template #edit="{ row }">
<vxe-upload
v-model="row.files_details"
name-field="original_name"
progress-text="{percent}%"
:more-config="{ maxCount: 1, layout: 'horizontal' }"
:limit-size="uploadSize / 1024 / 1024"
:show-button-text="false"
:upload-method="({file}) => uploadMethod(file, row)"
/>
</template>
</vxe-column>
<vxe-column field="admin" title="创建人" width="100" :formatter="({ cellValue }) => (cellValue && cellValue.name) || ''" />
<vxe-column field="operate" title="操作" min-width="220" fixed="right">
<template #default="{ row }">
<template v-if="isActiveStatus(row)">
<el-button size="small" type="primary" @click="saveRowEvent(row)"
>保存</el-button
>
<el-button
size="small"
type="primary"
plain
@click="cancelRowEvent(row)"
>取消</el-button
>
</template>
<template v-else>
<el-button size="small" type="primary" @click="viewRowEvent(row)"
>查看</el-button
>
<el-button size="small" type="warning" @click="editRowEvent(row)"
>编辑</el-button
>
<el-button
size="small"
type="danger"
@click="destroyRowEvent(row)"
>删除</el-button
>
</template>
</template>
</vxe-column>
</vxe-table>
<el-pagination
style="margin-top: 10px"
:current-page.sync="select.page"
:page-sizes="[20, 30, 40, 50]"
:page-size.sync="select.page_size"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="
(e) => {
select.page_size = e;
select.page = 1;
getList();
}
"
@current-change="
(e) => {
select.page = e;
getList();
}
"
/>
</card-container>
<add-meeting-minutes
ref="AddMeetingMinutes"
:type="isShowType"
:is-show.sync="isShowAdd"
@refresh="getList"
/>
</div>
</template>
<script>
import { deepCopy } from "@/utils";
import { destroy, index, save, show } from "@/api/meetingMinutes";
import AddMeetingMinutes from "./components/AddMeetingMinutes.vue";
import axios from "axios";
import { getToken } from "@/utils/auth";
import { uploadSize } from '@/settings';
import { formatFileSize } from '@/utils'
export default {
components: {
AddMeetingMinutes
},
data() {
return {
uploadSize,
isShowAdd: false,
isShowType: 'add',
loading: false,
select: {
page: 1,
page_size: 20,
show_relation: ['admin', 'flows', 'items']
},
total: 0,
allAlign: null,
tableData: [],
validRules: {},
form: {
id: "",
title: "",
meeting_time: "",
files: [],
flow_ids: [],
files_details: [],
items: []
},
};
},
computed: {
isActiveStatus() {
return function (row) {
if (this.$refs["table"]) {
return this.$refs["table"].isEditByRow(row);
}
};
},
},
created() {
this.getList();
},
mounted() {
this.bindToolbar()
},
methods: {
formatFileSize,
previewFile(file) {
//
if (file.url) {
this.$bus.$emit("online-file", file.url);
} else if (file.response && file.response.data && file.response.data.url) {
this.$bus.$emit("online-file", file.response.data.url);
}
},
downloadFile(file) {
//
let fileId = null;
if (file.id) {
fileId = file.id;
} else if (file.response && file.response.data && file.response.data.id) {
fileId = file.response.data.id;
}
if (fileId) {
this.$bus.$emit("online-download", fileId);
}
},
uploadMethod(file, row) {
const formData = new FormData()
formData.append('file', file)
window.$_uploading = true
return axios.post(process.env.VUE_APP_UPLOAD_API, formData, {
headers: {
Authorization: `Bearer ${getToken()}`,
}
}).then((response) => {
window.$_uploading = false
if (response.status === 200 && !response.data.code) {
if (!(row.files_details instanceof Array)) {
row.files_details = []
}
row.files_details.push({
response: response.data.data,
name: response.data.data.original_name,
url: response.data.data.url
})
} else {
this.$message.error("上传失败")
}
}).catch(err => {
window.$_uploading = false
})
},
bindToolbar() {
this.$nextTick(() => {
if (this.$refs["table"] && this.$refs["toolbar"]) {
this.$refs["table"].connect(this.$refs["toolbar"]);
}
});
},
editRowEvent(row) {
this.isShowType = 'edit'
this.$refs['AddMeetingMinutes'].getDetail(row)
this.isShowAdd = true
},
viewRowEvent(row) {
this.isShowType = 'view'
this.$refs['AddMeetingMinutes'].getDetail(row)
this.isShowAdd = true
},
cancelRowEvent(row) {
if (this.$refs["table"]) {
this.$refs["table"].clearEdit().then(() => {
//
this.$refs["table"].revertData(row);
});
}
},
async getList() {
this.loading = true;
try {
const res = await index(this.select);
this.tableData = res.data;
this.total = res.total;
this.loading = false;
} catch (err) {
console.error(err);
this.loading = false;
}
},
async saveRowEvent(row) {
if (window.$_uploading) {
this.$message.warning("文件正在上传中")
return
}
try {
const errMap = await this.$refs["table"].validate();
if (errMap) {
throw new Error(errMap);
}
await this.$confirm("确认保存?", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
});
await this.$refs["table"].clearEdit();
const form = deepCopy(this.form);
for (const key in form) {
form[key] = row[key];
}
this.loading = true;
form['files'] = (row.files_details && row.files_details instanceof Array)
? row.files_details.map(i => (i.response && i.response.id) || i.id).filter(i => !!i)
: []
await save(form);
await this.getList();
this.loading = false;
this.$message.success("保存成功");
} catch (err) {
this.loading = false;
}
},
async destroyRowEvent(row) {
try {
await this.$confirm("确认删除?", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
});
this.loading = true;
if (row.id) {
await destroy({
id: row.id,
});
await this.getList();
this.$message.success("删除成功");
} else {
this.tableData.splice(
this.tableData.findIndex((i) => i._X_ROW_KEY === row._X_ROW_KEY),
1
);
}
this.loading = false;
} catch (err) {
this.loading = false;
}
},
},
};
</script>
<style scoped lang="scss">
.total {
color: #666;
text-align: right;
line-height: 3;
}
::v-deep .el-tag + .el-tag {
margin-left: 4px;
}
</style>

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="isShow"
show-footer
transfer
@ -49,6 +50,8 @@ export default {
defaultModalSize,
loading: false,
zIndex: PopupManager.nextZIndex(),
// vxe-ui v3.5+ modal.id
modalId: `meeting-room-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
form: {
name: '',
myindex: 0

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="isShow"
show-footer
title="特殊日期"
@ -55,6 +56,8 @@ export default {
return {
defaultModalSize,
zIndex: PopupManager.nextZIndex(),
// vxe-ui v3.5+ modal.id
modalId: `special-days-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
loading: false,
form: {
date: '',

@ -2,6 +2,7 @@
<div>
<vxe-modal
:z-index="zIndex"
:id="modalId"
:value="isShow"
show-footer
title="车辆证照管理"
@ -92,6 +93,8 @@ export default {
action: process.env.VUE_APP_UPLOAD_API,
defaultModalSize,
zIndex: PopupManager.nextZIndex(),
// vxe-ui v3.5+ modal.id
modalId: `vehicle-certificate-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
loading: false,
form: {

@ -2,6 +2,7 @@
<div>
<vxe-modal
:z-index="zIndex"
:id="modalId"
:value="isShow"
show-footer
title="补卡"
@ -69,6 +70,8 @@ export default {
return {
zIndex: PopupManager.nextZIndex(),
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `attendance-addsign-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
loading: false,
form: {
user_id: '',

@ -26,6 +26,7 @@
</el-calendar>
<vxe-modal
:id="modalId"
v-model="isShow"
show-footer
:z-index="zIndex"
@ -130,6 +131,8 @@ export default {
isShow: false,
defaultModalSize,
zIndex: PopupManager.nextZIndex(),
// vxe-ui v3.5+ modal.id
modalId: `attendance-month-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
day: new Date(),
selectDay: '',

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="isShow"
show-footer
title="年休假"
@ -58,6 +59,8 @@ export default {
data() {
return {
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `year-holiday-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
action: process.env.VUE_APP_UPLOAD_API,
fileList: [],
loading: false,

@ -53,6 +53,7 @@
</CardContainer>
<vxe-modal
:id="modalId"
v-model="isShow"
show-footer
:z-index="zIndex"
@ -109,6 +110,8 @@ export default {
isShow: false,
defaultModalSize,
zIndex: PopupManager.nextZIndex(),
// vxe-ui v3.5+ modal.id
modalId: `attendance-outsign-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
imageId: '',
remark: '',
// end

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="isShow"
show-footer
title="特殊日期"
@ -48,6 +49,8 @@ export default {
data() {
return {
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `config-add-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
loading: false,
form: {
name: '',

@ -278,6 +278,7 @@
<!-- 办理-->
<vxe-modal
:id="dealModalId"
v-model="isShowModal"
:z-index="zIndex"
transfer
@ -298,6 +299,7 @@
</vxe-modal>
<!-- 编辑菜单 -->
<vxe-modal
:id="quickModalId"
v-model="isShowQuick"
:z-index="zIndex"
transfer
@ -363,6 +365,9 @@ export default {
data() {
return {
defaultModalSize,
// vxe-ui v3.5+ modal.id
dealModalId: `dashboard-deal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
quickModalId: `dashboard-quick-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
modalUrl: "",
zIndex: PopupManager.nextZIndex(),
isShowModal: false,

@ -2,6 +2,7 @@
<div>
<vxe-modal
:z-index="zIndex"
:id="modalId"
:value="isShow"
show-footer
title="公共文件柜"
@ -91,6 +92,8 @@ export default {
defaultModalSize,
zIndex: PopupManager.nextZIndex(),
// vxe-ui v3.5+ modal.id
modalId: `document-add-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
loading: false,
form: {
document_menu_id: '',

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:z-index="zIndex"
:value="isShow"
show-footer
@ -67,6 +68,8 @@ export default {
return {
zIndex: PopupManager.nextZIndex(),
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `flow-field-export-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
loading: false,
config: {
fields: []

@ -2,6 +2,7 @@
<div>
<vxe-modal
title="批量审批"
:id="modalId"
:z-index="zIndex"
:value="isShow"
@input="e => $emit('update:isShow', e)"
@ -168,6 +169,8 @@ export default {
data() {
return {
loading: false,
// vxe-ui v3.5+ modal.id
modalId: `flow-multideal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
defaultModalSize,
zIndex: PopupManager.nextZIndex(),

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="visible"
show-footer
:z-index="zIndex"
@ -141,6 +142,8 @@ export default {
},
data() {
return {
// vxe-ui v3.5+ modal.id/
modalId: `flow-assign-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
isIndeterminate: false,
checkAll: false,

@ -1,6 +1,6 @@
<template>
<div>
<vxe-modal :value="isShow"
<vxe-modal :id="modalId" :value="isShow"
show-footer
:z-index="zIndex"
title="转办"
@ -62,6 +62,8 @@ export default {
data() {
return {
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `flow-forward-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
zIndex: PopupManager.nextZIndex(),
form: {
id: "",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
<template>
<div>
<vxe-modal :value="isShow"
<vxe-modal :id="modalId" :value="isShow"
show-footer
:z-index="zIndex"
title="退回"
@ -56,6 +56,8 @@ export default {
data() {
return {
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `flow-rollback-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
zIndex: PopupManager.nextZIndex(),
form: {
id: "",

@ -1,6 +1,6 @@
<template>
<div>
<vxe-modal :value="isShow"
<vxe-modal :id="modalId" :value="isShow"
show-footer
:z-index="zIndex"
title="抄送"
@ -54,6 +54,8 @@ export default {
data() {
return {
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `flow-share-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
zIndex: PopupManager.nextZIndex(),
config: {
cc_users: []

@ -1,5 +1,5 @@
<template>
<div class="container">
<div class="container" :class="{ 'is-single-page': isSinglePage }">
<el-card
:shadow="device === 'desktop' ? 'always' : 'never'"
class="card"
@ -303,6 +303,7 @@
</el-dialog>
<!-- 打开支出 详情 -->
<vxe-modal
:id="contractModalId"
v-model="isShowModal"
:z-index="999999"
transfer
@ -346,7 +347,7 @@ import { deepCopy } from "@/utils";
import { validation, validationName } from "@/utils/validate";
import { print } from "@/utils/print";
import JSONBigint from 'json-bigint'
import { getToken } from "@/utils/auth";
import { getToken, setToken } from "@/utils/auth";
export default {
components: {
Steps,
@ -358,6 +359,8 @@ export default {
},
data() {
return {
// vxe-ui v3.5+ modal.id
contractModalId: `flow-contract-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
isShowModal:false,
contractUrl:'',
printKey: 0,
@ -420,7 +423,13 @@ export default {
console.log("123")
this.form['form_canal'] = 'oa'
try {
if(!this.$route.query?.default_json) return
if(!this.$route.query?.default_json) {
// 使default_jsonform_canal
if(this.$route.query?.form_canal) {
this.form['form_canal'] = this.$route.query.form_canal
}
return
}
const res = JSON.parse(this.$route.query?.default_json)
for (let key in this.$route.query) {
if(/^out_(.*)_id/.test(key)) {
@ -939,10 +948,37 @@ export default {
} else {
copyForm['csrf_token'] = this.csrf_token
this.result = await create(this.$route.query.module_id, copyForm);
// iframepostMessage
if (this.result && this.result.id && window.self !== window.top) {
try {
window.parent.postMessage({
type: 'OA_FLOW_CREATED',
flowId: this.result.id,
success: true,
message: '流程创建成功'
}, '*')
} catch (error) {
console.error('发送postMessage失败:', error)
}
}
}
callback();
} catch (err) {
console.error(err);
// iframepostMessage
if (window.self !== window.top) {
try {
window.parent.postMessage({
type: 'OA_FLOW_CREATED',
flowId: null,
success: false,
message: err.message || '流程创建失败'
}, '*')
} catch (postError) {
console.error('发送postMessage失败:', postError)
}
}
}
},
@ -1050,12 +1086,29 @@ export default {
},
isFirstNode() {
return this.config?.logs?.length === 0 || this.config?.currentNode?.category === 'start'
},
isSinglePage() {
return this.$route.query.isSinglePage === '1' || this.$route.query.isSinglePage === 1 || window.self !== window.top
}
},
created() {
this.getConfig();
// iframe
if (this.isSinglePage && window.self !== window.top) {
document.body.style.margin = '0'
document.body.style.padding = '0'
}
},
mounted() {
// iframe
if (this.isSinglePage && window.self !== window.top) {
const container = this.$el
if (container) {
container.style.margin = '0'
container.style.padding = '0'
}
}
},
mounted() {},
};
</script>
@ -1074,8 +1127,7 @@ export default {
::v-deep .el-step.is-center .el-step__line {
top: 50%;
}
::v-deep .el-card__header {
}
.container {
padding: 20px;
@ -1088,9 +1140,23 @@ export default {
margin-top: 10px;
flex-wrap: wrap;
}
//
&.is-single-page {
padding: 0;
margin: 0;
height: 100vh;
overflow-y: auto;
.card {
border: none;
box-shadow: none;
min-height: 100vh;
background: #f7f8fa;
}
}
}
.form-container {
}
@media (max-width: 768px) {
.container {
padding: 0;

@ -853,6 +853,7 @@
<payMx ref="payMx" :is-show.sync="isShowPay"></payMx>
<vxe-modal
:id="modalId"
v-model="isShowModal"
:z-index="zIndex"
transfer
@ -1047,6 +1048,8 @@ export default {
},
data() {
return {
// vxe-ui v3.5+ modal.id/
modalId: `flow-paylist-view-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
isShowModal: false,
modalUrl: "",
zIndex: PopupManager.nextZIndex(),

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="isShow"
show-footer
:z-index="zIndex"
@ -148,6 +149,8 @@ export default {
uploadSize,
users: [],
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `meeting-add-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
zIndex: PopupManager.nextZIndex(),
loading: false,
form: {

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="isShow"
show-footer
:z-index="zIndex"
@ -129,6 +130,8 @@ export default {
id: '',
users: [],
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `notice-add-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
zIndex: PopupManager.nextZIndex(),
loading: false,
form: {

@ -1,6 +1,7 @@
<template>
<div>
<vxe-modal
:id="modalId"
:value="isShow"
show-footer
title="车船管理"
@ -103,6 +104,8 @@ export default {
data() {
return {
defaultModalSize,
// vxe-ui v3.5+ modal.id
modalId: `vehicle-add-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
action: process.env.VUE_APP_UPLOAD_API,
fileList: [],
loading: false,

@ -25,7 +25,7 @@ module.exports = {
* Detail: https://cli.vuejs.org/config/#publicpath
*/
publicPath: `/${process.env.VUE_APP_MODULE_NAME}`,
outputDir: `../cz_hjjc/public/${process.env.VUE_APP_MODULE_NAME}`,
outputDir: process.env.VUE_APP_OUTPUT_DIR || `../cz_hjjc/public/${process.env.VUE_APP_MODULE_NAME}`,
assetsDir: 'static',
lintOnSave: process.env.NODE_ENV === 'development',
productionSourceMap: false,

Loading…
Cancel
Save