You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
648 lines
21 KiB
648 lines
21 KiB
<template>
|
|
<div>
|
|
<div ref="contractList" style="padding: 0 20px">
|
|
<lx-header
|
|
icon="md-apps"
|
|
style="margin-bottom: 10px; border: 0px; margin-top: 15px"
|
|
text="出差管理"
|
|
>
|
|
<slot>
|
|
<div class="selects">
|
|
<div>
|
|
<span style="padding: 0 6px; word-break: keep-all">关键字</span>
|
|
<span>
|
|
<Input
|
|
v-model="select.keyword"
|
|
clearable
|
|
placeholder="关键字搜索"
|
|
style="width: 200px"
|
|
/>
|
|
</span>
|
|
</div>
|
|
|
|
<div>
|
|
<span>开始时间</span>
|
|
<span>
|
|
<DatePicker
|
|
:value="select.start_year"
|
|
placeholder="选择开始时间"
|
|
placement="bottom"
|
|
format="yyyy-MM-dd"
|
|
style="width: 120px"
|
|
@on-change="(e) => (select.start_year = $moment(e).format('YYYY-MM-DD'))"
|
|
></DatePicker>
|
|
</span>
|
|
</div>
|
|
|
|
<div>
|
|
<span>结束时间</span>
|
|
<span>
|
|
<DatePicker
|
|
:value="select.end_year"
|
|
placeholder="选择结束时间"
|
|
placement="bottom"
|
|
format="yyyy-MM-dd"
|
|
style="width: 120px"
|
|
@on-change="(e) => (select.end_year = $moment(e).format('YYYY-MM-DD'))"
|
|
></DatePicker>
|
|
</span>
|
|
</div>
|
|
|
|
<div>
|
|
<Button
|
|
type="primary"
|
|
@click="$router.push('/contract/away/addAway')">新增</Button>
|
|
</div>
|
|
<div>
|
|
<Button type="primary" @click="getList">查询</Button>
|
|
</div>
|
|
<div>
|
|
<Button
|
|
type="primary"
|
|
@click="goExpense()"
|
|
>出差报销
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</slot>
|
|
</lx-header>
|
|
|
|
<xy-table
|
|
ref="xyTable"
|
|
:list="list"
|
|
:table-item="table"
|
|
@editor=""
|
|
>
|
|
<template v-slot:btns>
|
|
<el-table-column
|
|
fixed="right"
|
|
header-align="center"
|
|
label="操作"
|
|
width="220"
|
|
>
|
|
<template #default="{ row }" v-if="!/Finance/g.test($route.path)">
|
|
<Button style="margin: 2px;" size="small" type="primary" @click="printFlow(row)">打印流程</Button>
|
|
<template v-if="row.away_status === 1 && row.expense_status === 1">
|
|
<Poptip
|
|
v-if="isAuthEdit(row)"
|
|
:transfer="true"
|
|
confirm
|
|
placement="bottom"
|
|
title="确认要删除吗"
|
|
@on-ok="() => deleteAway(row.id)"
|
|
>
|
|
<Button
|
|
style="margin: 2px;"
|
|
ghost
|
|
size="small"
|
|
type="error"
|
|
>删除
|
|
</Button>
|
|
</Poptip>
|
|
<Button
|
|
style="margin: 2px;"
|
|
size="small"
|
|
type="primary"
|
|
@click="$refs['addAway'].setType('editor'),$refs['addAway'].setId(row.id),$refs['addAway'].show()"
|
|
>编辑
|
|
</Button>
|
|
</template>
|
|
|
|
<template v-if="row.FLOWSTATUS.useCar.isEnabled()">
|
|
<Button
|
|
style="margin: 2px;"
|
|
size="small"
|
|
type="primary"
|
|
@click="goUseCar(row)"
|
|
>用车审核
|
|
</Button>
|
|
</template>
|
|
<template v-if="row.FLOWSTATUS.subsidize.isEnabled()">
|
|
<Button
|
|
style="margin: 2px;"
|
|
size="small"
|
|
type="primary"
|
|
@click="goSubsidize(row)"
|
|
>市内补助审核
|
|
</Button>
|
|
</template>
|
|
<template v-if="row.FLOWSTATUS.away.isEnabled()">
|
|
<Button
|
|
style="margin: 2px;"
|
|
size="small"
|
|
type="primary"
|
|
@click="goAway(row)"
|
|
>出差审核
|
|
</Button>
|
|
</template>
|
|
<template v-if="row.FLOWSTATUS.expense.isEnabled()">
|
|
<Button
|
|
style="margin: 2px;"
|
|
size="small"
|
|
type="primary"
|
|
@click="goExpense(row)"
|
|
>出差报销
|
|
</Button>
|
|
</template>
|
|
</template>
|
|
<template v-else #default="{ row }">
|
|
<template v-if="row.FLOWSTATUS.expense.getStatus() === 3">
|
|
<Button
|
|
v-if="row.FLOWSTATUS.financial.getStatus() !== 2"
|
|
style="margin: 2px;"
|
|
size="small"
|
|
type="primary"
|
|
@click="$refs['examineAway'].getContract(row);$refs['examineAway'].isShowPaymentRegistration=true;"
|
|
ghost
|
|
>审核确认
|
|
</Button>
|
|
</template>
|
|
<template v-if="/Finance/g.test($route.path)">
|
|
<Button
|
|
v-if="isAuthCanExpense(row)"
|
|
style="margin: 2px;"
|
|
size="small"
|
|
type="primary"
|
|
@click="canExpense(row,1)"
|
|
>开启报销
|
|
</Button>
|
|
<Button
|
|
v-else
|
|
style="margin: 2px;"
|
|
size="small"
|
|
type="primary"
|
|
ghost
|
|
@click="canExpense(row,0)"
|
|
>关闭报销
|
|
</Button>
|
|
</template>
|
|
</template>
|
|
</el-table-column>
|
|
</template>
|
|
</xy-table>
|
|
|
|
<div style="display: flex; justify-content: flex-end;padding: 10px 6px;">
|
|
<Page
|
|
:total="total"
|
|
show-elevator
|
|
@on-change="e => {
|
|
select.page = e;
|
|
getList();
|
|
}"
|
|
show-sizer
|
|
@on-page-size-change="e => {
|
|
select.page = 1;
|
|
select.page_size = e;
|
|
getList();
|
|
}"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<addAway ref="addAway" @refresh="getList"></addAway>
|
|
<examineAway ref="examineAway" @refresh="getList"></examineAway>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import examineAway from "@/views/away/component/examineAway.vue";
|
|
import addAway from "@/views/away/component/addAway.vue"
|
|
import { index, destroy, save } from "@/api/away";
|
|
import {getToken} from "@/utils/auth";
|
|
|
|
export default {
|
|
components: {
|
|
addAway,
|
|
examineAway
|
|
},
|
|
data() {
|
|
return {
|
|
expenseUser: ["admin","panjiajia","huyangcui","wanghui"],
|
|
window: {
|
|
width: 0,
|
|
height: 0,
|
|
top: 0,
|
|
left: 0,
|
|
},
|
|
select: {
|
|
keyword: '',
|
|
start_year: "",
|
|
end_year: "",
|
|
page: 1,
|
|
page_size: 10
|
|
},
|
|
total: 0,
|
|
list: [],
|
|
flowStatus: new Map([
|
|
[0, "-"],
|
|
[1, "待申请"],
|
|
[2, "流转中"],
|
|
[3, "已办结"]
|
|
]),
|
|
flowStatusColor: new Map([
|
|
[0, "rgb(140, 140, 140)"],
|
|
[1, "rgb(96, 109, 241)"],
|
|
[2, "rgb(219, 122, 122)"],
|
|
[3, "rgb(147, 201, 134)"]
|
|
]),
|
|
table: [
|
|
{
|
|
type: 'selection',
|
|
width: 54,
|
|
reserveSelection: true,
|
|
selectable: row => row.away_flow_id && row.away_status === 3 && !row.expense_flow_id,
|
|
fixed: "left"
|
|
},
|
|
{
|
|
label: "出差事由",
|
|
prop: "title",
|
|
width: 200,
|
|
align: "left",
|
|
fixed: "left"
|
|
},
|
|
{
|
|
label: "开始时间",
|
|
prop: "start_date",
|
|
width: 120
|
|
},
|
|
{
|
|
label: "结束时间",
|
|
prop: "end_date",
|
|
width: 120
|
|
},
|
|
{
|
|
label: "是否用车",
|
|
prop: "use_car",
|
|
formatter: (cell, data, value) => {
|
|
return value? "是" : "否";
|
|
},
|
|
},
|
|
{
|
|
label: "是否市内补助",
|
|
prop: "is_subsidize",
|
|
formatter: (cell, data, value) => {
|
|
return value? "是" : "否";
|
|
},
|
|
width: 140
|
|
},
|
|
{
|
|
label: "流程状态",
|
|
multiHd: [
|
|
// {
|
|
// width: 100,
|
|
// label: "用车",
|
|
// customFn:row => {
|
|
// if (!row.use_car) {
|
|
// return (
|
|
// <span style="color: rgb(140, 140, 140);">-</span>
|
|
// )
|
|
// }
|
|
// return (
|
|
// <div>
|
|
// <span style={{ 'color': this.flowStatusColor.get(row.FLOWSTATUS.useCar.getStatus()) }}>{ this.flowStatus.get(row.FLOWSTATUS.useCar.getStatus()) || '待申请' }</span>
|
|
// <br/>
|
|
// {
|
|
// (row.FLOWSTATUS.useCar.getStatus() > 1) ? <a style="color: #333" on={{['click']:()=>{
|
|
// this.toOaDetail('useCar',row,)
|
|
// }}}>查看</a> : ''
|
|
// }
|
|
// </div>
|
|
// )
|
|
// }
|
|
// },
|
|
// {
|
|
// width: 100,
|
|
// label: "市内补助",
|
|
// customFn:row => {
|
|
// if (!row.is_subsidize) {
|
|
// return (
|
|
// <span style="color: rgb(140, 140, 140);">-</span>
|
|
// )
|
|
// }
|
|
// return (
|
|
// <div>
|
|
// <span style={{ 'color': this.flowStatusColor.get(row.FLOWSTATUS.subsidize.getStatus()) }}>{ this.flowStatus.get(row.FLOWSTATUS.subsidize.getStatus()) || '待申请' }</span>
|
|
// <br/>
|
|
// {
|
|
// (row.FLOWSTATUS.subsidize.getStatus() > 1) ? <a style="color: #333" on={{['click']:()=>{
|
|
// this.toOaDetail('subsidize',row)
|
|
// }}}>查看</a> : ''
|
|
// }
|
|
// </div>
|
|
// )
|
|
// }
|
|
//
|
|
// },
|
|
{
|
|
width: 100,
|
|
label: "出差审批",
|
|
customFn:row => {
|
|
return (
|
|
<div>
|
|
<span style={{ 'color': this.flowStatusColor.get(row.FLOWSTATUS.away.getStatus()) }}>{ this.flowStatus.get(row.FLOWSTATUS.away.getStatus()) || '待申请' }</span>
|
|
<br/>
|
|
{
|
|
(row.FLOWSTATUS.away.getStatus() > 1) ? <a style="color: #333" on={{['click']:()=>{
|
|
this.toOaDetail('away',row)
|
|
}}}>查看</a> : ''
|
|
}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
},
|
|
{
|
|
label: "出差报销",
|
|
width: 100,
|
|
customFn:row => {
|
|
return (
|
|
<div>
|
|
{
|
|
((this.$moment().diff(this.$moment(row.end_date),"days") <= 30) || (row.FLOWSTATUS.expense.getStatus() > 1)) ?
|
|
(<span style={{ 'color': this.flowStatusColor.get(row.FLOWSTATUS.expense.getStatus()) }}>{ this.flowStatus.get(row.FLOWSTATUS.expense.getStatus()) || '待申请' }</span>) :
|
|
(<span style="color: red">超时未办理</span>)
|
|
}
|
|
<br/>
|
|
{
|
|
(row.FLOWSTATUS.expense.getStatus() > 1) ? <a style="color: #333" on={{['click']:()=>{
|
|
this.toOaDetail('expense',row)
|
|
}}}>查看</a> : ''
|
|
}
|
|
</div>
|
|
)
|
|
}
|
|
},
|
|
{
|
|
width: 100,
|
|
label: "财务审核",
|
|
customFn:row => {
|
|
return (row.FLOWSTATUS.financial.getStatus() === 2) ?
|
|
(<span style="color: green;">已确认</span>) :
|
|
(<span style="color: #666;">待审核</span>)
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
label: "创建日期",
|
|
width: 160,
|
|
prop: "created_at",
|
|
formatter: (cell, data, value) => {
|
|
return this.$moment(value).format("YYYY-MM-DD HH:mm");
|
|
},
|
|
},
|
|
{
|
|
label: "业务科室",
|
|
width: 140,
|
|
prop: "department.name",
|
|
},
|
|
{
|
|
label: "经办人",
|
|
width: 140,
|
|
prop: "admin.name",
|
|
},
|
|
]
|
|
}
|
|
},
|
|
methods: {
|
|
printFlow (row) {
|
|
let id;
|
|
if (row.away_flow_id) {
|
|
id = row.away_flow_id;
|
|
} else if (row.expense_flow_id) {
|
|
id = row.expense_flow_id
|
|
} else {}
|
|
if (!id) {
|
|
this.$message.warning("未找到流程");
|
|
return
|
|
}
|
|
window.open(`${process.env.VUE_APP_OUT_URL}/flow/print-relate-flow?id=${id}&except_self=0&auth_token=${this.$store.getters.oa_token}`,"_blank")
|
|
},
|
|
|
|
async toOaDetail (tbname,row) {
|
|
let url = `${process.env.VUE_APP_OUT_URL}/#/flow/detail?auth_token=${window.encodeURIComponent(getToken())}&isSinglePage=1&flow_id=`
|
|
switch (tbname) {
|
|
case "away":
|
|
url += row.away_flow_id
|
|
break;
|
|
case 'expense':
|
|
url += row.expense_flow_id
|
|
break;
|
|
default:
|
|
url = `${process.env.VUE_APP_OUT_URL}/flow/list/todo`
|
|
}
|
|
this.oaUrl = url
|
|
this.isShowOaModal = true
|
|
},
|
|
goUseCar (row) {
|
|
const baseInfo = {
|
|
"flow_title": row.title,
|
|
"65802fc31dc8f": row.start_date,
|
|
"65f7e6e45ab4f": row.end_date,
|
|
"657be2e1bbda8": row.title
|
|
};
|
|
let url = `${process.env.VUE_APP_OUT_OLD}/flow/create/3?auth_token=${this.$store.getters.oa_token}&out_away_id=${
|
|
row.id
|
|
}&default_json=${JSON.stringify(baseInfo)}`;
|
|
window.open(
|
|
url,
|
|
"buyProcess",
|
|
`top=${this.window.top},left=${this.window.left},width=${this.window.width},height=${this.window.height},location=0`
|
|
);
|
|
},
|
|
goSubsidize (row) {
|
|
const baseInfo = {
|
|
"flow_title": row.title,
|
|
"6584041d45cd9": row.title
|
|
};
|
|
let url = `${process.env.VUE_APP_OUT_OLD}/flow/create/24?auth_token=${this.$store.getters.oa_token}&out_away_id=${
|
|
row.id
|
|
}&default_json=${JSON.stringify(baseInfo)}`;
|
|
window.open(
|
|
url,
|
|
"buyProcess",
|
|
`top=${this.window.top},left=${this.window.left},width=${this.window.width},height=${this.window.height},location=0`
|
|
);
|
|
},
|
|
goAway (row) {
|
|
// 70
|
|
const baseInfo = {
|
|
"flow_title": row.title,
|
|
"kaishi": row.start_date,
|
|
"jieshu": row.end_date,
|
|
"chuchaishiyou": row.title,
|
|
};
|
|
let url = `${process.env.VUE_APP_OUT_OLD}/#/flow/create?auth_token=${window.encodeURIComponent(getToken())}&module_name=oa&isSinglePage=1&module_id=70&out_away_id=${row.id}&default_json=${JSON.stringify(baseInfo)}`;
|
|
console.log('url',url)
|
|
this.oaUrl = url
|
|
this.isShowOaModal = true
|
|
},
|
|
goExpense (row) {
|
|
let url;
|
|
if (row) {
|
|
const baseInfo = {
|
|
"flow_title": row.title,
|
|
"totalAmt": row.expense,
|
|
"chuchaishiyou": row.title,
|
|
"65af398d89e75": row.away_flow_id,
|
|
};
|
|
url = `${process.env.VUE_APP_OUT_OLD}/#/flow/create?auth_token=${window.encodeURIComponent(getToken())}&module_name=oa&isSinglePage=1&module_id=78&out_away_id=${row.id}&default_json=${JSON.stringify(baseInfo)}`;
|
|
} else {
|
|
let rows = this.$refs['xyTable'].getSelection()
|
|
const baseInfo = {
|
|
"flow_title": rows.map(row => row.title).toString() ,
|
|
"totalAmt": row.reduce((pre, cur) => pre + Number(row.expense??0),0),
|
|
"chuchaishiyou": rows.map(row => row.title).toString(),
|
|
"65af398d89e75": rows.map(row => row.away_flow_id).toString(),
|
|
};
|
|
url = `${process.env.VUE_APP_OUT_OLD}/#/flow/create?auth_token=${window.encodeURIComponent(getToken())}&module_name=oa&isSinglePage=1&module_id=78&out_away_id=${rows.map(i => i.id)?.toString()}&default_json=${JSON.stringify(baseInfo)}`;
|
|
}
|
|
console.log('url',url)
|
|
this.oaUrl = url
|
|
this.isShowOaModal = true
|
|
},
|
|
|
|
async getList (isFirst) {
|
|
class Flow {
|
|
status = 0
|
|
executable = false
|
|
constructor(status=0, executable=false) {
|
|
this.status = status
|
|
this.executable = executable
|
|
}
|
|
setStatus (status) {
|
|
this.status = status
|
|
}
|
|
setExecutable (executable) {
|
|
if (typeof executable === 'boolean') {
|
|
this.executable = executable
|
|
}
|
|
}
|
|
getStatus () {
|
|
return this.status
|
|
}
|
|
getExecutable () {
|
|
return this.executable
|
|
}
|
|
isEnabled () {
|
|
return this.executable && this.status === 1
|
|
}
|
|
}
|
|
const res = await index(this.select,!isFirst);
|
|
delete this.select.id;
|
|
this.total = res.total;
|
|
this.list = res.data;
|
|
this.list.forEach(item => {
|
|
let flowStatus = {
|
|
"useCar": new Flow(),
|
|
"subsidize": new Flow(),
|
|
"away": new Flow(),
|
|
"expense": new Flow(),
|
|
"financial": new Flow()
|
|
}
|
|
// if (item.use_car) {
|
|
// flowStatus.useCar.setStatus(item.use_car_status)
|
|
// if (item.use_car_status === 1) {
|
|
// flowStatus.useCar.setExecutable(true)
|
|
// }
|
|
// }
|
|
// if (item.is_subsidize) {
|
|
// flowStatus.subsidize.setStatus(item.subsidize_status)
|
|
// if (item.subsidize_status === 1) {
|
|
// flowStatus.subsidize.setExecutable(true)
|
|
// }
|
|
// }
|
|
flowStatus.away.setStatus(item.away_status)
|
|
if (item.away_status === 1) {
|
|
flowStatus.away.setExecutable(true)
|
|
}
|
|
flowStatus.expense.setStatus(item.expense_status)
|
|
// if ((!item.is_subsidize || item.subsidize_status === 3) && (!item.use_car || item.use_car_status === 3) && item.away_status === 3 && (!item.expense_status || item.expense_status === 1) && (this.$moment().diff(this.$moment(item.end_date),"days") <= 30 || item.can_expenses)) {
|
|
// flowStatus.expense.setExecutable(true)
|
|
// }
|
|
if (item.away_status === 3 && (!item.expense_status || item.expense_status === 1) && (this.$moment().diff(this.$moment(item.end_date),"days") <= 30 || item.can_expenses)) {
|
|
flowStatus.expense.setExecutable(true)
|
|
}
|
|
|
|
flowStatus.financial.setStatus(item.financial_status)
|
|
if (item.expense_status === 3) {
|
|
flowStatus.financial.setExecutable(true)
|
|
}
|
|
item.FLOWSTATUS = flowStatus;
|
|
});
|
|
},
|
|
|
|
async deleteAway (id) {
|
|
await destrxoy({ id });
|
|
await this.getList();
|
|
},
|
|
|
|
examineAway (row, status) {
|
|
this.$confirm("是否确认审批?", "提示", {}).then(_ => {
|
|
save({
|
|
...row,
|
|
financial_status: status
|
|
}).then(_ => {
|
|
this.$message.success("操作成功");
|
|
this.getList()
|
|
})
|
|
})
|
|
},
|
|
canExpense (row, status) {
|
|
this.$confirm(`是否${ status ? "开启" : "关闭" }报销?`, "提示", {}).then(_ => {
|
|
save({
|
|
...row,
|
|
can_expenses: status
|
|
}).then(_ => {
|
|
this.$message.success("操作成功");
|
|
this.getList()
|
|
})
|
|
})
|
|
},
|
|
},
|
|
computed: {
|
|
isAuthEdit () {
|
|
return function (row) {
|
|
return !(row.FLOWSTATUS.useCar.getStatus() > 1 || row.FLOWSTATUS.subsidize.getStatus() > 1 || row.FLOWSTATUS.away.getStatus() > 1 || row.FLOWSTATUS.financial.getStatus() > 1)
|
|
}
|
|
},
|
|
isAuthCanExpense () {
|
|
return function (row) {
|
|
return (this.$moment().diff(this.$moment(row.end_date),"days") > 30) && this.expenseUser.indexOf(this.$store.state.user.username) !== -1 && !row.can_expenses
|
|
}
|
|
}
|
|
},
|
|
created() {
|
|
this.window.width = screen.availWidth * 0.95;
|
|
this.window.height = screen.availHeight * 0.95;
|
|
this.window.top = (window.screen.height - 30 - this.window.height) / 2;
|
|
this.window.left = (window.screen.width - 10 - this.window.width) / 2;
|
|
this.select.id = this.$route.query.awayId;
|
|
this.getList(true)
|
|
|
|
window.onfocus = () => {
|
|
this.getList()
|
|
}
|
|
},
|
|
destroyed() {
|
|
window.onfocus = null;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.selects {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
|
|
& > div {
|
|
margin-bottom: 6px;
|
|
margin-right: 4px;
|
|
|
|
& > span {
|
|
word-break: keep-all;
|
|
padding: 0 4px ;
|
|
}
|
|
}
|
|
}
|
|
</style>
|