xy 1 year ago
parent cb3b7b5126
commit 78df620162

@ -14,6 +14,7 @@
"test:ci": "npm run lint && npm run test:unit"
},
"dependencies": {
"@riophae/vue-treeselect": "^0.4.0",
"axios": "0.18.1",
"core-js": "3.6.5",
"element-ui": "2.13.2",

@ -45,9 +45,15 @@ export default {
}
},
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
}
},
created() {
window.toggleSideBar = this.toggleSideBar
}
}
</script>

@ -56,6 +56,11 @@ Vue.use(Vant)
import domZIndex from 'dom-zindex'
domZIndex.setCurrent(2000)
// treeselect
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import Treeselect from '@riophae/vue-treeselect'
Vue.component('Treeselect', Treeselect)
import CardContainer from '@/layout/CardContainer.vue'
Vue.component('CardContainer', CardContainer)
//moment

@ -67,3 +67,14 @@ p {
// main-container global css
.main-container {
}
.vue-treeselect__multi-value-item,.vue-treeselect__value-remove {
color: var(--theme-color) !important;
}
.vue-treeselect__checkbox--checked {
background-color: var(--theme-color) !important;
border-color: var(--theme-color) !important;
}
.vxe-loading--default-icon,.vxe-loading--text {
color: var(--theme-color) !important;;
}

@ -762,8 +762,8 @@ export default function formBuilder(device, info, h, row, pWrite = false,pReadab
style: {
"grid-column-start": info.gs_x + 1,
"grid-column-end": info.gs_x + 1 + info.gs_width,
"grid-row-start": info.gs_y + 1,
"grid-row-end": info.gs_y + 1 + info.gs_height,
"grid-row-start": info.gs_y + 1 + (info.name === 'flow_title' ? 0 : 1),
"grid-row-end": info.gs_y + 1 + (info.name === 'flow_title' ? 0 : 1) + info.gs_height,
},
},
[formItem]

@ -0,0 +1,139 @@
<template>
<div>
<vxe-modal
:z-index="zIndex"
:value="isShow"
show-footer
title="公共文件柜栏目"
show-confirm-button
:width="600"
:height="400"
:fullscreen="$store.getters.device === 'mobile'"
esc-closable
@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="pid" required>
<Treeselect
v-model="form.pid"
:options="formatList"
no-children-text="无子菜单"
:normalizer="node => ({
id: node.id,
label: node.name,
children: node.children,
isDefaultExpanded: true
})"
/>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="授权人员" prop="update_children_ids">
<el-select
style="width: 100%;"
multiple
popper-append-to-body
:value="form.update_children_ids ? form.update_children_ids.split(',').map(i => Number(i)) : []"
@input="e => form.update_children_ids = e.toString()"
>
<el-option v-for="user in users" :key="user.id" :value="user.id" :label="user.name" />
</el-select>
</el-form-item>
<el-form-item label="排序" prop="myindex">
<el-input-number v-model="form.myindex" :controls="false" :precision="0" />
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" :loading="loading" @click="submit"></el-button>
</template>
</vxe-modal>
</div>
</template>
<script>
import { menuSave } from '@/api/document'
import { PopupManager } from "element-ui/lib/utils/popup";
export default {
props: {
list: {
type: Array,
default: () => []
},
isShow: {
type: Boolean,
default: false,
required: true
},
users: {
type: Array,
default: () => []
}
},
data() {
return {
zIndex: PopupManager.nextZIndex(),
loading: false,
form: {
pid: 0,
name: '',
update_children_ids: '',
myindex: ''
},
rules: {
pid: [
{ required: true, message: '请选择上级目录' }
],
name: [
{ required: true, message: '请输入名称' }
]
}
}
},
computed: {
formatList() {
return [
{
name: '#根目录',
id: 0
},
...this.list
]
}
},
watch: {
isShow(newVal) {
if(newVal) {
this.zIndex = PopupManager.nextZIndex()
}
}
},
methods: {
setPid(pid) {
this.form.pid = pid
},
submit() {
this.$refs['elForm'].validate(async valid => {
if (valid) {
this.loading = true
try {
await menuSave(this.form)
this.$message.success('新增成功')
this.$emit('refresh')
this.$emit('update:isShow', false)
this.loading = false
this.$refs['elForm'].resetFields()
} catch (err) {
this.loading = false
}
}
})
}
}
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,203 @@
<template>
<div>
<card-container>
<vxe-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"
style="margin-top: 10px;"
:loading="loading"
keep-source
:row-config="{ useKey: 'id', isHover: true }"
:column-config="{ resizable: true }"
:edit-rules="validRules"
:edit-config="{ trigger: 'manual', mode: 'row', showStatus: true, autoClear: false, expandALl: true }"
:tree-config="{ rowField: 'id', parentField: 'pid' }"
:data="tableData"
>
<vxe-column type="seq" width="58" align="center" />
<vxe-column tree-node field="name" width="170" title="名称" :edit-render="{ name: 'input', attrs: { type: 'text' } }" />
<vxe-column field="update_children" title="授权人员" min-width="160" :edit-render="{}">
<template #edit="{ row }">
<el-select
collapse-tags
style="width: 100%;"
multiple
filterable
:value="row.update_children_ids ? row.update_children_ids.split(',').map(i => Number(i)) : []"
@input="e => row.update_children_ids = e.toString()"
>
<el-option v-for="user in users" :key="user.id" :value="user.id" :label="user.name" />
</el-select>
</template>
</vxe-column>
<vxe-column field="myindex" width="180" title="排序" align="center" :edit-render="{ name: 'input', attrs: { type: 'number' } }" />
<vxe-column field="operate" title="操作" min-width="220">
<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="success" @click="$refs['AddDocumentMenu'].setPid(row.id),isShowAdd = true">子栏目</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>
</card-container>
<add-document-menu ref="AddDocumentMenu" :users="users" :list="tableData" :is-show.sync="isShowAdd" @refresh="getList" />
</div>
</template>
<script>
import { deepCopy } from '@/utils'
import { menuSave, menuIndex, menuDestroy } from '@/api/document'
import { index as userIndex } from '@/api/user'
import AddDocumentMenu from './components/AddDocumentMenu.vue'
export default {
components: {
AddDocumentMenu
},
data() {
return {
users: [],
isShowAdd: false,
loading: false,
select: {
page: 1,
page_size: 20
},
allAlign: null,
tableData: [],
validRules: {
name: [
{ required: true, message: '请输入角色' }
]
},
form: {
id: '',
pid: '',
name: '',
myindex: '',
update_children_ids: ''
}
}
},
computed: {
isActiveStatus() {
return function(row) {
if (this.$refs['table']) {
return this.$refs['table'].isEditByRow(row)
}
}
}
},
created() {
this.getUsers()
this.getList()
},
methods: {
editRowEvent(row) {
if (this.$refs['table']) {
this.$refs['table'].setEditRow(row)
}
},
cancelRowEvent(row) {
if (this.$refs['table']) {
this.$refs['table'].clearEdit().then(() => {
//
this.$refs['table'].revertData(row)
})
}
},
async getUsers() {
try {
const res = await userIndex({
rows: 999
})
this.users = res.data
} catch (err) {
console.error(err)
}
},
async getList() {
this.loading = true
try {
const res = await menuIndex(this.select)
this.tableData = res
this.loading = false
this.$nextTick(() => {
this.$refs['table'].setAllTreeExpand(true)
})
} catch (err) {
console.error(err)
this.loading = false
}
},
async saveRowEvent(row) {
try {
await this.$confirm('确认保存?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消'
})
await this.$refs['table'].clearEdit()
const form = deepCopy(this.form)
for (const key in form) {
form[key] = row[key]
}
if (!form.password) {
delete form.password
}
this.loading = true
await menuSave(form)
await this.getList()
this.loading = false
} catch (err) {
this.loading = false
}
},
async destroyRowEvent(row) {
try {
await this.$confirm('确认删除?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消'
})
this.loading = true
if (row.id) {
await menuDestroy({
id: row.id
})
await this.getList()
} else {
console.log(row)
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>

@ -325,6 +325,15 @@ export default {
computed: {
...mapGetters(["name"]),
},
watch: {
isShowModal(newVal) {
if(newVal) {
this.zIndex = PopupManager.nextZIndex()
} else {
this.modalUrl = ''
}
}
},
methods: {
getTodayAttendance(date) {
return this.attendanceData.attendances.find((i) => i.date === date)

@ -0,0 +1,121 @@
<template>
<div class="container">
<el-card shadow="always">
<el-input
v-model="filterText"
clearable
size="small"
placeholder="输入关键字进行过滤"
/>
<el-tree
ref="tree"
:indent="10"
style="margin-top: 8px;"
class="filter-tree"
:data="types"
:props="{
label: 'name',
}"
default-expand-all
:filter-node-method="filterNode"
/>
</el-card>
<card-container>
<vxe-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 }"
:data="tableData"
>
<vxe-column type="seq" width="64" align="center" />
</vxe-table>
</card-container>
</div>
</template>
<script>
import { menuIndex, index } from '@/api/document'
export default {
data() {
return {
filterText: '',
isShowAdd: false,
loading: false,
validRules: {
},
tableData: [],
types: []
}
},
computed: {},
watch: {
filterText(val) {
this.$refs.tree.filter(val)
}
},
created() {
this.getTypes()
this.getList()
},
methods: {
filterNode(value, data) {
if (!value) return true
return data.name.indexOf(value) !== -1
},
async getList() {
try {
const res = await index()
} catch (err) {
console.error(err)
}
},
async getTypes() {
try {
const res = await menuIndex()
this.types = res
} catch (err) {
console.error(err)
}
}
}
}
</script>
<style scoped lang="scss">
.container {
display: flex;
justify-content: space-between;
& > div:nth-child(1) {
flex-basis: 20%;
}
& > div:nth-child(2) {
flex-basis: 78%;
}
}
@media (max-width: 768px) {
.container {
display: initial;
& > div:nth-child(2) {
margin-top: 10px;
}
}
}
</style>

@ -1,8 +1,13 @@
<script>
import { deepCopy } from "@/utils"
import formBuilder from '@/utils/formBuilder'
import { PopupManager } from "element-ui/lib/utils/popup";
export default {
props: {
isFirstNode: {
type: Boolean,
default: true
},
readable: {
type: Array,
default: () => [],
@ -45,6 +50,11 @@ export default {
},
data() {
return {
zIndex: PopupManager.nextZIndex(),
isShowModal: false,
modalRender: () => {},
action: process.env.VUE_APP_BASE_API,
form: {},
file: {},
}
@ -82,6 +92,11 @@ export default {
console.error(err)
}
}
},
isShowModal(newVal) {
if(newVal) {
this.zIndex = PopupManager.nextZIndex()
}
}
},
render(h) {
@ -90,17 +105,47 @@ export default {
_readable: this.readable.indexOf(field.id) !== -1,
_writeable: this.writeable.indexOf(field.id) !== -1,
}))
return h('el-form', {
ref: 'elForm',
class: 'form',
props: {
model: this.form,
'label-position': 'right',
'label-width': '100px',
rules: this.rules,
'inline-message': true
}
},authFields.map(field => formBuilder.bind(this)(this.device, field, h)))
authFields.unshift({
name: 'flow_title',
label: '工作名称',
type: 'text',
gs_x: 0,
gs_y: 0,
gs_width: 12,
gs_height: 1,
_readable: !this.isFirstNode,
_writeable: this.isFirstNode
})
return h('div',[
h('el-form', {
ref: 'elForm',
class: 'form',
props: {
model: this.form,
'label-position': 'right',
'label-width': '100px',
rules: this.rules,
'inline-message': true
}
},authFields.map(field => formBuilder.bind(this)(this.device, field, h))),
//
h('vxe-modal',{
props: {
zIndex: this.zIndex,
value: this.isShowModal,
height: 640,
width: 860,
'esc-closable': true
},
on: {
input: e => {
this.isShowModal = e
}
}
}, [
this.modalRender.bind(this)(h)
])
])
},
created() {}
}
@ -110,7 +155,6 @@ export default {
.form {
display: grid;
grid-template-columns: repeat(12, 1fr);
//grid-gap: 20px;
}
::v-deep .el-form-item {
border: 1px solid #dee2e6;

@ -2,8 +2,13 @@
import formBuilder from '@/utils/formBuilder'
import moment from "moment/moment";
import {deepCopy} from "@/utils";
import {PopupManager} from "element-ui/lib/utils/popup";
export default {
props: {
isFirstNode: {
type: Boolean,
default: true
},
readable: {
type: Array,
default: () => [],
@ -43,6 +48,10 @@ export default {
},
data() {
return {
isShowModal: false,
modalRender: () => {},
zIndex: PopupManager.nextZIndex(),
form: {},
file: {
ggg: []
@ -89,6 +98,11 @@ export default {
console.error(err)
}
}
},
isShowModal(newVal) {
if(newVal) {
this.zIndex = PopupManager.nextZIndex()
}
}
},
render(h) {
@ -194,6 +208,22 @@ export default {
}
})
]) : '',
//
h('vxe-modal',{
props: {
zIndex: this.zIndex,
value: this.isShowModal,
fullscreen: true
},
on: {
input: e => {
this.isShowModal = e
}
}
}, [
this.modalRender.bind(this)(h)
])
])
}
}

@ -6,6 +6,7 @@
:z-index="zIndex"
title="转办"
show-zoom
:fullscreen="$store.getters.device === 'mobile'"
show-confirm-button
:width="640"
:height="540"

@ -5,6 +5,7 @@
:z-index="zIndex"
title="转办"
show-zoom
:fullscreen="$store.getters.device === 'mobile'"
show-confirm-button
:width="760"
:height="540"

@ -5,6 +5,7 @@
:z-index="zIndex"
title="退回"
show-zoom
:fullscreen="$store.getters.device === 'mobile'"
show-confirm-button
:width="760"
:height="540"

@ -16,6 +16,13 @@
<template>
<div class="steps" v-if="!/\/detail/.test($route.path)">
<el-steps :space="120" finish-status="success" align-center>
<template v-if="!isFirstNode">
<el-step
v-for="step in config.logs"
:title="step.node.name"
:status="step.status !== -1 ? 'success' : 'error'"
></el-step>
</template>
<el-step
:title="node.name"
status="finish"
@ -38,6 +45,7 @@
<DesktopForm
:device="device"
ref="desktopForm"
:is-first-node="isFirstNode"
:sub-form="subConfig"
:fields="fields"
:original-form="form"
@ -52,6 +60,7 @@
<MobileForm
:device="device"
ref="mobileForm"
:is-first-node="isFirstNode"
:sub-form="subConfig"
:fields="fields"
:original-form="form"
@ -378,6 +387,8 @@ export default {
object[field.name] = field.default_value ? field.default_value : "";
}
});
this.form['flow_title'] = this.config?.flow?.title ?? ''
},
formatTime(time) {
const days = parseInt(time / (1000 * 60 * 60 * 24));
@ -633,6 +644,9 @@ export default {
},
];
},
isFirstNode() {
return this.config?.logs?.length === 0 || this.config?.currentNode?.category === 'start'
}
},
created() {
this.getConfig();
@ -642,6 +656,19 @@ export default {
</script>
<style scoped lang="scss">
::v-deep .el-step__title {
font-size: 14px;
line-height: 1.5;
}
::v-deep .el-step__icon.is-icon {
border-radius: 100%;
box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
width: 40px;
height: 40px;
}
::v-deep .el-step.is-center .el-step__line {
top: 50%;
}
::v-deep .el-card__header {
}
.container {

Loading…
Cancel
Save