流转,列表等

master
xy 1 year ago
parent 3ca29b6aa1
commit 349e0becd3

@ -8,7 +8,7 @@ export function flow(isLoading=false) {
isLoading
})
}
//创建配置
export function preConfig(custom_model_id,isLoading=false) {
return request({
method: 'get',
@ -16,7 +16,7 @@ export function preConfig(custom_model_id,isLoading=false) {
isLoading
})
}
//获取表单字段(主要子表单)
export function fieldConfig(custom_model_id,isLoading=false) {
return request({
method: 'get',
@ -36,7 +36,7 @@ export function create(custom_model_id, data) {
// },
})
}
//处理
export function preDeal(flow_id,params,isLoading=false) {
return request({
method: 'get',
@ -45,7 +45,6 @@ export function preDeal(flow_id,params,isLoading=false) {
isLoading
})
}
export function deal(flow_id,data) {
return request({
method: 'post',
@ -99,6 +98,7 @@ export function view(flow_id) {
})
}
//抄送
export function preShare(flow_id, params,isLoading = true) {
return request({
method: 'get',
@ -107,6 +107,14 @@ export function preShare(flow_id, params,isLoading = true) {
isLoading
})
}
export function share(flow_id, data, isLoading = true) {
return request({
method: 'post',
url: `/api/oa/flow/share/${flow_id}`,
data,
isLoading
})
}
//收藏
export function toggleFav(data,isLoading=true) {
@ -139,3 +147,41 @@ export async function destroy(data,isLoading=true) {
isLoading
})
}
//转办
export function preForward(params,isLoading=true) {
return request({
method: 'get',
url: '/api/oa/flow/forward-pre',
params,
isLoading
})
}
export async function forward(data,isLoading=true) {
await MessageBox.confirm("确认转办?","提示")
return request({
method: 'post',
url: '/api/oa/flow/forward',
data,
isLoading
})
}
//退回节点
export async function rollback(data,isLoading=true) {
await MessageBox.confirm("确认退回?","提示")
return request({
method: 'post',
url: '/api/oa/flow/rollback',
data,
isLoading
})
}
export function flowLogs(params,isLoading=false) {
return request({
method: 'get',
url: '/api/oa/flow/flow-logs',
params,
isLoading
})
}

@ -72,19 +72,19 @@ export const constantRoutes = [
component: () => import('@/views/flow/list.vue'),
},{
path: 'list/created-by-me',
name: 'flowList',
name: 'created-by-me',
meta: { title: '流程监管', icon: 'table' }
},{
path: 'list/fav',
name: 'flowList',
name: 'fav',
meta: { title: '我收藏的', icon: 'fav' }
},{
path: 'list/todo',
name: 'flowList',
name: 'todo',
meta: { title: '待办流程', icon: 'todo' }
},{
path: 'list/handled',
name: 'flowList',
name: 'handled',
meta: { title: '办理过的', icon: 'flow-through-me' }
},{
path: 'create',

@ -774,7 +774,9 @@ export default function formBuilder(device, info, h, row, pWrite = false) {
},
on: {
input: (e) => {
this.$set(this.form, info.name, e);
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
});
@ -794,7 +796,9 @@ export default function formBuilder(device, info, h, row, pWrite = false) {
},
on: {
input: (e) => {
this.$set(this.form, info.name, e);
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
});
@ -872,17 +876,18 @@ export default function formBuilder(device, info, h, row, pWrite = false) {
"div",
this.form[info.name].map((sForm, sIndex) =>
h(
"van-cell",
"van-cell-group",
{
props: {
"arrow-direction": "down",
title: info.label + "-" + (sIndex + 1),
"title-style": {
"margin-left": "10px",
},
},
inset: false
}
},
[
h("van-cell", {
props: {
title: info.label + "-" + (sIndex + 1)
}
}),
h(
"van-form",
{

@ -1,13 +1,15 @@
<template>
<div>
<el-dialog
:close-on-click-modal="false"
:title="title"
width="920px"
:visible.sync="visible"
:fullscreen="$store.getters.device === 'mobile'"
append-to-body
:show-close="false"
<vxe-modal
:value="visible"
show-footer
:z-index="zIndex"
title="转办"
show-zoom
show-confirm-button
:width="640"
:height="540"
@input="e => $emit('update:visible',e)"
>
<div>
<div class="steps">
@ -60,12 +62,13 @@
>{{ isLastNode ? '结束流程' : '确 定'}}</el-button
>
</span>
</el-dialog>
</vxe-modal>
</div>
</template>
<script>
import { getNextNodeUsers, assign } from "@/api/flow";
import { PopupManager } from 'element-ui/lib/utils/popup'
export default {
props: {
@ -82,6 +85,7 @@ export default {
},
data() {
return {
zIndex: PopupManager.nextZIndex(),
form: {
cc_users: [],
user_id: "",
@ -136,6 +140,9 @@ export default {
watch: {
visible(newVal) {
if(newVal) {
this.zIndex = PopupManager.nextZIndex()
if(this.node && this.node.nextNodes && this.node.nextNodes?.length > 0 && !this.isLastNode) {
this.getNextNodesUsers()
}

@ -0,0 +1,116 @@
<template>
<div>
<vxe-modal :value="isShow"
show-footer
:z-index="zIndex"
title="转办"
show-zoom
show-confirm-button
:width="760"
:height="540"
@input="e => $emit('update:isShow',e)">
<div>
<div>
<h4>本部门</h4>
<el-radio-group v-model="form.user_id">
<el-radio v-for="(user, index) in config.users" :key="user.id" :label="user.id">{{ user.name }}</el-radio>
</el-radio-group>
</div>
<div v-for="(group, index) in config.groups" :key="group.id">
<h4>{{ group.name }}</h4>
<el-radio-group v-model="form.user_id">
<el-radio v-for="(user, index1) in group.users" :key="user.id" :label="user.id">{{ user.name }}</el-radio>
</el-radio-group>
</div>
<el-divider></el-divider>
<div>
<h4>转办意见</h4>
<el-input v-model="form.forwarded_comment" type="textarea" :autosize="{ minRows: 2 }"></el-input>
</div>
</div>
<template #footer>
<div style="margin-top: 20px;display: flex;justify-content: center;">
<el-button type="primary" size="small" @click="submit"> <i class="el-icon-arrow-right"></i> </el-button>
</div>
</template>
</vxe-modal>
</div>
</template>
<script>
import { preForward, forward } from '@/api/flow'
import { PopupManager } from 'element-ui/lib/utils/popup'
export default {
props: {
isShow: {
type: Boolean,
default: false,
required: true
},
flow: Object
},
data() {
return {
zIndex: PopupManager.nextZIndex(),
form: {
id: "",
user_id: "",
forwarded_comment: "",
},
config: {
users: [],
groups: []
}
}
},
methods: {
async getConfig() {
try {
const res = await preForward({
id: this.flow.id
})
this.config = res;
} catch (err) {
console.error(err)
}
},
async submit() {
try {
this.form.id = this.flow.id;
const res = await forward(this.form)
this.$message({
message: res,
duration: 2000,
type: 'success'
})
setTimeout(() => {
this.$router.go(-1)
},2000)
} catch (err) {
console.error(err)
}
}
},
computed: {},
watch: {
isShow(newVal) {
if (newVal) {
this.zIndex = PopupManager.nextZIndex()
if(this.flow.id) {
this.getConfig()
}
}
}
}
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,118 @@
<template>
<div>
<vxe-modal :value="isShow"
show-footer
:z-index="zIndex"
title="退回"
show-zoom
show-confirm-button
:width="760"
:height="540"
@input="e => $emit('update:isShow',e)">
<div>
<h4>请选择退回步骤</h4>
<el-radio-group v-model="form.flow_log_id">
<el-radio v-for="flowLog in config.flowLogs" :key="flowLog.id" :label="flowLog.id">
<span style="font-weight: 600;font-size: 15px;">{{ flowLog.node ? flowLog.node.name : "" }}</span>
<div class="flow-label">
主办{{ flowLog.user ? flowLog.user.name : '' }}
</div>
<div class="flow-label">
办结{{ $moment(flowLog.created_at).format('YYYY年MM月DD日 HH时mm分ss秒') }}
</div>
</el-radio>
</el-radio-group>
<h4>请输入退回原因</h4>
<el-input v-model="form.reason" type="textarea" :autosize="{ minRows: 2 }"></el-input>
</div>
<template #footer>
<div style="margin-top: 20px;display: flex;justify-content: center;">
<el-button type="primary" size="small" @click="submit">退 <i class="el-icon-arrow-right"></i> </el-button>
</div>
</template>
</vxe-modal>
</div>
</template>
<script>
import { flowLogs, rollback } from '@/api/flow'
import { PopupManager } from 'element-ui/lib/utils/popup'
export default {
props: {
isShow: {
type: Boolean,
default: false,
required: true
},
flow: Object
},
data() {
return {
zIndex: PopupManager.nextZIndex(),
form: {
id: "",
flow_log_id: "",
reason: "",
},
config: {
flowLogs: [],
}
}
},
methods: {
async getConfig() {
try {
const res = await flowLogs({
id: this.flow.id
})
this.config = res;
} catch (err) {
console.error(err)
}
},
async submit() {
if(!this.form.flow_log_id) {
this.$message.warning("请选择退回步骤!")
return
}
try {
this.form.id = this.flow.id;
const res = await rollback(this.form)
this.$message({
message: res,
duration: 2000,
type: 'success'
})
setTimeout(() => {
this.$router.go(-1)
},2000)
} catch (err) {
console.error(err)
}
}
},
computed: {},
watch: {
isShow(newVal) {
if (newVal) {
this.zIndex = PopupManager.nextZIndex()
if(this.flow.id) {
this.getConfig()
}
}
}
}
}
</script>
<style scoped lang="scss">
.flow-label {
line-height: 1.5;
}
</style>

@ -0,0 +1,108 @@
<template>
<div>
<vxe-modal :value="isShow"
show-footer
:z-index="zIndex"
title="抄送"
show-zoom
show-confirm-button
:width="800"
:height="600"
@input="e => $emit('update:isShow',e)">
<div>
<el-tag effect="dark">{{ flow.custom_model ? flow.custom_model.name : ''}}流水号{{ flow.id }}抄送</el-tag>
<el-checkbox-group v-model="form.cc_users">
<div v-for="(ccUser, index) in config.cc_users" :key="ccUser.id">
<h4>{{ ccUser.name }}</h4>
<div>
<el-checkbox v-for="(user, index1) in ccUser.users"
:key="user.id"
:disabled="(config.flow && config.flow.ccs) ? (!!config.flow.ccs.find(j => j.user_id === user.id)) : false"
:label="user.id">{{ user.name }}({{ user.position }})</el-checkbox>
</div>
</div>
</el-checkbox-group>
</div>
<template #footer>
<div style="margin-top: 20px;display: flex;justify-content: center;">
<el-button type="primary" size="small" @click="submit"> <i class="el-icon-arrow-right"></i> </el-button>
</div>
</template>
</vxe-modal>
</div>
</template>
<script>
import { preShare, share } from '@/api/flow'
import { PopupManager } from 'element-ui/lib/utils/popup'
export default {
props: {
isShow: {
type: Boolean,
default: false,
required: true
},
flow: Object
},
data() {
return {
zIndex: PopupManager.nextZIndex(),
config: {
cc_users: []
},
form: {
cc_users: []
}
}
},
methods: {
async getConfig() {
try {
const res = await preShare(this.flow.id)
this.config = res;
this.form.cc_users = res.exists_users;
} catch (err) {
console.error(err)
}
},
async submit() {
try {
const res = await share(this.flow.id,this.form)
this.$message({
message: res,
duration: 2000,
type: 'success'
})
this.$emit('update:isShow',false)
} catch (err) {
console.error(err)
}
}
},
computed: {},
watch: {
isShow(newVal) {
if (newVal) {
this.zIndex = PopupManager.nextZIndex()
if(this.flow.id) {
this.getConfig()
}
} else {
this.form.cc_users = []
}
}
}
}
</script>
<style scoped lang="scss">
::v-deep .el-checkbox-group {
font-size: inherit;
}
</style>

@ -1,6 +1,12 @@
<template>
<div class="container">
<el-card shadow="always" class="card">
<el-card :shadow="device === 'desktop' ? 'always' : 'never'"
class="card"
:style="{
border: device === 'desktop' ? '' : 'none',
background: device === 'desktop' ? '' : '#f7f8fa',
'min-height': device === 'desktop' ? '' : '100vh',
}">
<template #header>
<p>{{ config.customModel ? config.customModel.name : "办理" }}</p>
</template>
@ -60,24 +66,44 @@
<div v-if="/\/detail/.test($route.path)" style="margin-top: 10px">
<div>流转记录</div>
<vxe-table
show-footer
ref="table"
stripe
class="log-table-scroll"
keep-source
show-overflow
:column-config="{ resizable: true }"
:print-config="{}"
:export-config="{}"
:custom-config="{ mode: 'popup' }"
:footer-data="footerData"
:data="config.logs || []"
>
<vxe-column type="seq" width="58" align="center" title="编号"/>
<vxe-column title="节点名称" align="center" field="node.name"></vxe-column>
<vxe-column title="办理状态" field="status_label"></vxe-column>
<vxe-column title="承办人员" field="user.name"></vxe-column>
<vxe-column title="流转时间" field="created_at"></vxe-column>
<vxe-column title="退回原因" field="reason"></vxe-column>
<vxe-column title="办理时间" field="updated_at"></vxe-column>
<vxe-column title="耗时"></vxe-column>
<vxe-column type="seq" width="62" align="center" field="seq" title="编号"/>
<vxe-column width="140" title="节点名称" align="center" field="node.name" :formatter="({ cellValue }) => (cellValue || '节点已调整')"></vxe-column>
<vxe-column width="80" align="center" title="办理状态" field="status" :formatter="({ cellValue }) => (myStatus.get(cellValue))">
<template #default="{ row }">
<el-tag
size="mini"
:type="statusColor.get(row.status)"
effect="dark"
>{{ myStatus.get(row.status) }}</el-tag
>
</template>
</vxe-column>
<vxe-column align="center" width="80" title="承办人员" field="user.name"></vxe-column>
<vxe-column align="center" width="200" title="流转时间" field="created_at" :formatter="({ cellValue }) => $moment(cellValue).format('YYYY年MM月DD日 HH:mm:ss')"></vxe-column>
<vxe-column min-width="200" header-align="center" title="退回原因" field="reason"></vxe-column>
<vxe-column align="center" width="200" title="办理时间" field="updated_at">
<template #default="{ row }">
<span :style="{ 'color': (row.deadline && row.updated_at && $moment(row.updated_at).isAfter($moment(row.deadline).endOf('day')) ? 'red' : '') }">{{ $moment(row.updated_at).format('YYYY年MM月DD日 HH:mm:ss') }}</span>
</template>
</vxe-column>
<vxe-column align="center" title="耗时" field="use_time" width="120">
<template #default="{ row }">
<span>{{ diffTime(row.updated_at, row.created_at) }}</span>
</template>
</vxe-column>
</vxe-table>
</div>
@ -88,7 +114,7 @@
icon="el-icon-arrow-left"
type="danger"
size="small"
@click=""
@click="isShowRollback = true"
>退回</el-button
>
<el-button
@ -97,7 +123,7 @@
type="primary"
plain
size="small"
@click=""
@click="isShowForward = true"
>部门内转办</el-button
>
<el-button
@ -152,6 +178,15 @@
:result="result"
></assign>
<forward
ref="forward"
:is-show.sync="isShowForward"
:flow="config.flow"></forward>
<rollback ref="rollback"
:is-show.sync="isShowRollback"
:flow="config.flow"></rollback>
<el-backtop></el-backtop>
</div>
</template>
@ -160,6 +195,8 @@
import DesktopForm from "./DesktopForm.vue";
import MobileForm from "./MobileForm.vue";
import assign from "./components/assign.vue";
import forward from "./components/forward.vue";
import rollback from "./components/rollback.vue";
import { create, deal, fieldConfig, preConfig, preDeal, view } from "@/api/flow";
import { deepCopy } from "@/utils";
@ -168,13 +205,29 @@ export default {
DesktopForm,
MobileForm,
assign,
forward,
rollback,
},
data() {
return {
isShowRollback: false,
isShowForward: false,
isShowAssign: false,
info: [],
config: {},
subConfig: new Map(),
myStatus: new Map([
[-2,'会签退回'],
[-1,'退回'],
[0, "办理中"],
[1, "已完成"],
]),
statusColor: new Map([
[-2, "warning"],
[-1, "warning"],
[0, ""],
[1, "success"],
]),
form: {},
result: {},
@ -199,6 +252,14 @@ export default {
}
});
},
formatTime(time) {
const days = parseInt(time / (1000 * 60 * 60 * 24));
const hours = parseInt((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = parseInt((time % (1000 * 60 * 60)) / (1000 * 60));
const seconds = (time % (1000 * 60)) / 1000;
return `${days > 0 ? (days) + '天' : ''}${hours > 0 ? (hours) + '时' : ''}${minutes}${seconds}`;
},
async getConfig() {
const loading = this.$loading({
lock: true,
@ -409,6 +470,21 @@ export default {
return this.config?.customModel?.js;
}
},
diffTime() {
return function (end,start) {
const diff = this.$moment(end).diff(this.$moment(start))
return this.formatTime(diff)
}
},
footerData() {
const diff = this.$moment(this.config?.logs?.at(-1)?.updated_at).diff(this.$moment(this.config?.logs?.at(0)?.created_at));
return [
{
seq: "总耗时",
'use_time': this.formatTime(diff),
}
]
},
},
created() {
this.getConfig();
@ -439,7 +515,14 @@ export default {
}
@media (max-width: 768px) {
.container {
padding: 10px;
padding: 0;
}
}
</style>
<style lang="scss">
.log-table-scroll {
::-webkit-scrollbar {
height: 0;
}
}
</style>

@ -195,7 +195,11 @@
>
<template #default="{ row }">
<template v-if="$route.params.type !== 'created-by-me'">
<el-button v-if="row.my_log" type="primary" size="mini" @click="handle(row)"
<el-button
v-if="row.my_log"
type="primary"
size="mini"
@click="handle(row)"
>办理</el-button
>
<el-button
@ -211,7 +215,7 @@
type="danger"
size="mini"
@click="recall(row)"
>撤回</el-button
>撤回</el-button
>
<el-button
v-if="row.can_delete"
@ -254,13 +258,19 @@
</div>
</template>
</el-card>
<share ref="share" :is-show.sync="isShowShare" :flow="pickedFlow"></share>
</div>
</template>
<script>
import { flowList, toggleFav, destroy, recall } from "@/api/flow";
import moment from "moment/moment";
import share from "./components/share.vue";
export default {
components: {
share
},
data() {
return {
myStatus: new Map([
@ -360,6 +370,9 @@ export default {
label: "经办时间",
},
],
isShowShare: false,
pickedFlow: {},
};
},
methods: {
@ -374,6 +387,10 @@ export default {
`/flow/detail?module_id=${row.custom_model.id}&flow_id=${row.id}`
);
},
copyTo(row) {
this.pickedFlow = row;
this.isShowShare = true;
},
async toggleFav(row) {
try {
@ -385,15 +402,14 @@ export default {
},
async recall(row) {
try {
await recall({ id: row.id })
await this.getList()
await recall({ id: row.id });
await this.getList();
} catch (err) {}
},
async copyTo(row) {},
async destroy(row) {
try {
await destroy({ id: row.id })
await this.getList()
await destroy({ id: row.id });
await this.getList();
} catch (err) {}
},

Loading…
Cancel
Save