Commit a568381b by zhangtw
parents d53de9f0 df77b1f4
......@@ -106,7 +106,6 @@ export const getLeaveTypeList = (param) => {
})
}
// 转交审批人(前端发起将当前待审批任务转给其他审批人)
export const transferLeaveApproval = (param) => {
return axios.request({
......@@ -124,3 +123,10 @@ export const selectTransferApprovalList = (param) => {
data: param
})
}
export const deleteById = (param) => {
return axios.request({
url: '/api/ac/jilinsscgsdp/keyDmLeave/deleteById',
method: 'post',
data: param
})
}
......@@ -27,7 +27,7 @@
value-format="yyyy-MM-dd"
placeholder="请选择开始时间"
class="mr10"
style="width: 200px"
style="width: 150px"
/>
<span>结束时间:</span>
<DatePicker
......@@ -37,15 +37,17 @@
value-format="yyyy-MM-dd"
placeholder="请选择结束时间"
class="mr10"
style="width: 200px"
style="width: 150px"
/>
<br>
<div class="mt8">
<span>入库类型:</span>
<Select
v-model="filters.inbound.inbound_type"
placeholder="请选择入库类型"
class="mr10"
style="width: 200px"
clearable
>
<Option :value='1'>手工入库</Option>
<Option :value='2'>归还入库</Option>
......@@ -56,10 +58,12 @@
placeholder="请选择入库状态"
class="mr10"
style="width: 200px"
clearable
>
<Option :value='0'>待入库</Option>
<Option :value='1'>已入库</Option>
</Select>
</div>
</Col>
<Col span="6" class="text-right">
<Button type="primary" class="mr10" @click="handleSearch('inbound')">搜索</Button>
......@@ -72,10 +76,10 @@
<Table :data="tables.inbound" :loading="loading.inbound" :columns="inboundColumns" border>
<template slot="action" slot-scope="{ row }">
<Poptip confirm title="确认执行入库?" transfer @on-ok="doInbound(row)" v-if="canEdit(row)">
<Button size="small" type="success">入库</Button>
<Button size="small" type="success" class="mr5">入库</Button>
</Poptip>
<Button size="small" @click="openDetail(row)">详细</Button>
<Button size="small" type="primary" @click="openEdit(row)" v-if="canEdit(row)">修改</Button>
<Button size="small" @click="openDetail(row)" class="mr5">详细</Button>
<Button size="small" type="primary" @click="openEdit(row)" v-if="canEdit(row)" class="mr5">修改</Button>
<Poptip confirm title="确认删除?" transfer @on-ok="deleteInbound(row)" v-if="canEdit(row)">
<Button size="small" type="error">删除</Button>
</Poptip>
......@@ -151,13 +155,13 @@
<!-- 入库弹窗 -->
<Modal v-model="inboundModal.visible" :title="inboundModal.isEdit ? '修改入库' : '新增入库'" width="800">
<Form :model="inboundModal.form" :rules="inboundRules" :label-width="120" ref="inboundForm">
<FormItem label="入库单号">
<FormItem label="入库单号" prop="inbound_no">
<Input v-model="inboundModal.form.inbound_no" />
</FormItem>
<FormItem label="批次号">
<FormItem label="批次号" prop="batch_no">
<Input v-model="inboundModal.form.batch_no" />
</FormItem>
<FormItem label="入库日期">
<FormItem label="入库日期" prop="inbound_date">
<DatePicker
v-model="inboundModal.form.inbound_date"
type="date"
......@@ -327,7 +331,7 @@ export default {
return h('span', this.inboundStatusMap[row.inbound_status] || row.inbound_status || '-')
}
},
{ title: '操作', slot: 'action', width: 360, align: 'center' }
{ title: '操作', slot: 'action', width: 260, align: 'center' }
],
returnColumns: [
{ type: 'index', title: '序号', width: 60, align: 'center' },
......@@ -366,6 +370,7 @@ export default {
{ title: '物料编码', key: 'material_code', align: 'center' },
{ title: '物料名称', key: 'material_name', align: 'center' },
{ title: '总量', key: 'total_quantity', align: 'center' },
{ title: '借出', key: 'borrowed_quantity', align: 'center' },
{
title: '可用',
key: 'available_quantity',
......@@ -373,9 +378,7 @@ export default {
render: (h, { row }) => {
return h('span', (row.total_quantity - row.borrowed_quantity - row.damaged_quantity) || 0)
}
},
{ title: '借出', key: 'borrowed_quantity', align: 'center' },
{ title: '损坏', key: 'damaged_quantity', align: 'center' }
}
],
// 模态窗口内表格列定义
inboundDetailColumns: [
......@@ -487,7 +490,19 @@ export default {
inboundSelectedDetails: [],
inboundModal: { visible: false, isEdit: false, saving: false, form: {}, details: [] },
returnModal: { visible: false, record: {}, details: [], saving: false },
detailModal: { visible: false, loading: false, data: {}, details: [], logs: [] }
detailModal: { visible: false, loading: false, data: {}, details: [], logs: [] },
// 表单验证规则
inboundRules: {
inbound_no: [
{ required: true, message: '请填写入库单号', trigger: 'blur' }
],
batch_no: [
{ required: true, message: '请选择批次号', trigger: 'blur' }
],
inbound_date: [
{ required: true, message: '请选择入库日期' }
]
}
}
},
watch: {},
......@@ -824,6 +839,9 @@ export default {
.text-right { text-align: right; }
.page_style { margin-top: 12px; text-align: right; }
.mt8 { margin-top: 8px; }
.mr5 {
margin-right: 5px;
}
/* 搜索区域外层盒:统一间距+背景 */
.search-container {
padding: 16px;
......
......@@ -40,6 +40,7 @@
style="width: 200px"
/>
<br>
<div class="mt8">
<span>审批状态:</span>
<Select
v-model="filters.apply.approval_status"
......@@ -52,6 +53,7 @@
<Option :value='9'>审核通过</Option>
<Option :value='-1'>驳回</Option>
</Select>
</div>
</Col>
<!-- 右侧操作按钮区:固定居右 -->
<Col span="6" class="action-col">
......@@ -378,7 +380,7 @@ export default {
return h('span', this.approvalStatusMap[row.approval_status + ''] || row.approval_status || '-')
}
},
{ title: '操作', slot: 'action', align: 'center', width: 320 }
{ title: '操作', slot: 'action', align: 'center', width: 260 }
],
pendingColumns: [
{ type: 'index', title: '序号', width: 60, align: 'center' },
......
......@@ -42,8 +42,8 @@
</div>
<Table :data="tables.workload" :loading="loading.workload" :columns="workloadColumns" border>
<template slot="action" slot-scope="{ row }">
<Button size="small" class="mr10" @click="openWorkloadDetail(row,'leave')">请假明细</Button>
<Button size="small" @click="openWorkloadDetail(row,'inventory')">申领明细</Button>
<Button size="small" type="primary" class="mr10" @click="openWorkloadDetail(row,'leave')">请假明细</Button>
<Button size="small" type="primary" @click="openWorkloadDetail(row,'inventory')">申领明细</Button>
</template>
</Table>
</TabPane>
......
......@@ -7,33 +7,34 @@
<TabPane label="请假申请" name="apply">
<div class="search-div">
<Row type="flex" :gutter="16" class="mt8">
<Col span="12">
<Col span="18">
<span>开始:</span>
<DatePicker v-model="filters.apply.start_time" type="date" placeholder="开始日期" style="min-width:110px;margin-right:20px" />
<DatePicker v-model="filters.apply.start_time" type="date" placeholder="开始日期" style="width: 200px" class="mr10" />
<span>结束:</span>
<DatePicker v-model="filters.apply.end_time" type="date" placeholder="结束日期" style="min-width:110px;margin-right:20px" />
</Col>
<Col span="8">
<DatePicker v-model="filters.apply.end_time" type="date" placeholder="结束日期" style="width: 200px" class="mr10" />
<span>状态:</span>
<Select v-model="filters.apply.status" style="width: 60%">
<Option v-for="opt in statusOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</Option>
<Select v-model="filters.apply.status" style="width: 200px">
<Option v-for="opt in statusOptionsFor('apply')" :key="opt.id" :value="opt.id">{{ opt.name }}</Option>
</Select>
</Col>
<Col span="4" class="text-right">
<Col span="6" class="text-right">
<Button type="primary" class="mr10" @click="handleSearch('apply')">搜索</Button>
<Button class="mr10" @click="handleReset('apply')">重置</Button>
<Button type="success" @click="openApplyModal">申请</Button>
<Button type="primary" class="mr10" @click="handleReset('apply')">重置</Button>
<Button type="primary" @click="openApplyModal">申请</Button>
</Col>
</Row>
</div>
<Table border :loading="loading.apply" :columns="applyColumns" :data="tables.apply">
<template slot="action" slot-scope="{ row }">
<Button size="small" @click="openDetail(row)">详细</Button>
<Button size="small" type="primary" class="mr5" @click="openEdit(row)" v-if="canEdit(row)">修改</Button>
<Button size="small" type="success" class="mr5" @click="submit(row)" v-if="canSubmit(row)">提交</Button>
<Button size="small" type="info" class="mr5" @click="refillApplyDirect(row)" v-if="row.status === -1">重新填报</Button>
<Button size="small" class="mr10" @click="openDetail(row)">详细</Button>
<Button size="small" type="primary" class="mr10" @click="openEdit(row)" v-if="canEdit(row)">修改</Button>
<Button size="small" type="success" class="mr10" @click="submit(row)" v-if="canSubmit(row)">提交</Button>
<Poptip confirm title="确认删除?" transfer @on-ok="deleteApply(row)" v-if="canDelete(row)">
<Button size="small" type="error" class="mr10">删除</Button>
</Poptip>
<Button size="small" type="primary" class="mr10" @click="refillApplyDirect(row)" v-if="row.status === -1">重新填报</Button>
<Poptip confirm title="确认撤回?" transfer @on-ok="revoke(row)" v-if="canRevoke(row)">
<Button size="small" type="warning">撤回</Button>
<Button size="small" type="warning" class="mr10">撤回</Button>
</Poptip>
</template>
</Table>
......@@ -45,7 +46,7 @@
<Table border :loading="loading.pending" :columns="pendingColumns" :data="tables.pending">
<template slot="action" slot-scope="{ row }">
<div class="action-buttons">
<Button size="small" type="primary" @click="openApproveModal(row)">处理</Button>
<Button size="small" type="primary" class="mr10" @click="openApproveModal(row)">处理</Button>
</div>
</template>
</Table>
......@@ -56,27 +57,25 @@
<TabPane label="审核历史查询" name="history">
<div class="search-div">
<Row type="flex" :gutter="16" align="middle">
<Col span="12">
<Col span="18">
<span>开始:</span>
<DatePicker v-model="filters.history.start_time" type="date" placeholder="开始日期" style="min-width:110px;margin-right:20px" />
<DatePicker v-model="filters.history.start_time" type="date" placeholder="开始日期" style="width: 200px" class="mr10" />
<span>结束:</span>
<DatePicker v-model="filters.history.end_time" type="date" placeholder="结束日期" style="min-width:110px;margin-right:20px" />
</Col>
<Col span="8">
<DatePicker v-model="filters.history.end_time" type="date" placeholder="结束日期" style="width: 200px" class="mr10" />
<span>状态:</span>
<Select v-model="filters.history.status" style="width: 60%">
<Option v-for="opt in statusOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</Option>
<Select v-model="filters.history.status" style="width: 200px">
<Option v-for="opt in statusOptionsFor('history')" :key="opt.id" :value="opt.id">{{ opt.name }}</Option>
</Select>
</Col>
<Col span="4" class="text-right">
<Col span="6" class="text-right">
<Button type="primary" class="mr10" @click="handleSearch('history')">搜索</Button>
<Button @click="handleReset('history')">重置</Button>
<Button type="primary" class="mr10" @click="handleReset('history')">重置</Button>
</Col>
</Row>
</div>
<Table border :loading="loading.history" :columns="historyColumns" :data="tables.history">
<template slot="action" slot-scope="{ row }">
<Button size="small" @click="openHistoryDetail(row)">详细</Button>
<Button size="small" class="mr10" @click="openHistoryDetail(row)">详细</Button>
</template>
</Table>
<Page class="page_style" :total="pagers.history.totalRecord" :current="pagers.history.pageNo" :page-size="pagers.history.pageSize"
......@@ -86,27 +85,25 @@
<TabPane label="请假申请查询" name="query">
<div class="search-div">
<Row type="flex" :gutter="16" align="middle">
<Col span="12">
<Col span="18">
<span>开始:</span>
<DatePicker v-model="filters.query.start_time" type="date" placeholder="开始日期" style="min-width:110px;margin-right:20px" />
<DatePicker v-model="filters.query.start_time" type="date" placeholder="开始日期" style="width: 200px" class="mr10" />
<span>结束:</span>
<DatePicker v-model="filters.query.end_time" type="date" placeholder="结束日期" style="min-width:110px;margin-right:20px" />
</Col>
<Col span="8">
<DatePicker v-model="filters.query.end_time" type="date" placeholder="结束日期" style="width: 200px" class="mr10" />
<span>状态:</span>
<Select v-model="filters.query.status" style="width: 60%">
<Option v-for="opt in statusOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</Option>
<Select v-model="filters.query.status" style="width: 200px">
<Option v-for="opt in statusOptionsFor('query')" :key="opt.id" :value="opt.id">{{ opt.name }}</Option>
</Select>
</Col>
<Col span="4" class="text-right">
<Col span="6" class="text-right">
<Button type="primary" class="mr10" @click="handleSearch('query')">搜索</Button>
<Button @click="handleReset('query')">重置</Button>
<Button type="primary" class="mr10" @click="handleReset('query')">重置</Button>
</Col>
</Row>
</div>
<Table border :loading="loading.query" :columns="queryColumns" :data="tables.query">
<template slot="action" slot-scope="{ row }">
<Button size="small" @click="openDetail(row)">详细</Button>
<Button size="small" class="mr10" @click="openDetail(row)">详细</Button>
</template>
</Table>
<Page class="page_style" :total="pagers.query.totalRecord" :current="pagers.query.pageNo" :page-size="pagers.query.pageSize"
......@@ -116,15 +113,15 @@
<TabPane label="请假统计" name="stats">
<div class="search-div">
<Row type="flex" :gutter="16" align="middle">
<Col span="16">
<Col span="18">
<span>开始:</span>
<DatePicker v-model="statsStart" type="date" placeholder="开始日期" style="min-width:110px;margin-right:20px" />
<DatePicker v-model="statsStart" type="date" placeholder="开始日期" style="width: 200px" class="mr10" />
<span>结束:</span>
<DatePicker v-model="statsEnd" type="date" placeholder="结束日期" style="min-width:110px;margin-right:20px" />
<DatePicker v-model="statsEnd" type="date" placeholder="结束日期" style="width: 200px" class="mr10" />
</Col>
<Col span="8" class="text-right">
<Col span="6" class="text-right">
<Button type="primary" class="mr10" @click="loadStats">统计</Button>
<Button @click="resetStats">重置</Button>
<Button type="primary" class="mr10" @click="resetStats">重置</Button>
</Col>
</Row>
</div>
......@@ -146,6 +143,9 @@
<FormItem label="结束时间" prop="end_time">
<DatePicker v-model="applyModal.form.end_time" type="datetime" placeholder="请选择结束时间" />
</FormItem>
<FormItem label="请假时长(天)" prop="duration">
<Input v-model="applyModal.form.duration" placeholder="可手动录入或自动计算" />
</FormItem>
<FormItem label="请假事由" prop="reason">
<Input type="textarea" v-model="applyModal.form.reason" :rows="3" />
</FormItem>
......@@ -155,11 +155,11 @@
<FormItem label="紧急电话" prop="emergency_phone">
<Input v-model="applyModal.form.emergency_phone" />
</FormItem>
<FormItem label="指定审批人" prop="approver_id">
<FormItem label="审批人" prop="approver_id">
<Select v-if="leaveApprovalOptions.length > 0" v-model="applyModal.form.approver_id" style="width: 60%">
<Option v-for="opt in leaveApprovalOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</Option>
</Select>
<span v-else style="color: #999; font-style: italic;">暂无审批人</span>
<span v-else style="color: #999; font-style: italic;">请先进行审批人配置</span>
</FormItem>
</Form>
<div slot="footer">
......@@ -206,11 +206,14 @@
<Select v-if="leaveApprovalOptions.length > 0" v-model="approveModal.transferApprover" style="width: 60%" placeholder="请选择审批人">
<Option v-for="opt in leaveApprovalOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</Option>
</Select>
<span v-else style="color: #999; font-style: italic;">暂无审批人</span>
<span v-else style="color: #999; font-style: italic;">请先进行审批人配置</span>
</FormItem>
<FormItem label="审批意见" prop="comment">
<Input type="textarea" v-model="approveModal.comment" :rows="3" placeholder="请输入审批意见(驳回时必填)" />
<FormItem :label="approveModal.transferEnabled ? '转审原因' : '审批意见'" prop="comment">
<Input type="textarea"
v-model="approveModal.comment"
:rows="3"
:placeholder="approveModal.transferEnabled ? '请输入转审原因(选填)' : '请输入审批意见(驳回时必填)'" />
</FormItem>
</Form>
<div slot="footer">
......@@ -278,8 +281,10 @@ import {
getLeaveStats,
getLeaveById,
getLeaveTypeList,
selectTransferApprovalList
, transferLeaveApproval } from '@/api/key-dm-leave'
deleteById,
selectTransferApprovalList,
transferLeaveApproval
} from '@/api/key-dm-leave'
// 注意:不单独调用后台的 isPending 接口,改为复用 getPendingList 获取 totalRecord 判定是否存在待办
import { getLeaveApprovalPermission } from '@/api/key-dm-user-permission'
......@@ -311,13 +316,13 @@ export default {
],
applyColumns: [
{ type: 'index', title: '序号', width: 60, align: 'center' },
{ title: '申请人', key: 'user_name', align: 'center' },
{ title: '部门', key: 'department_name', align: 'center' },
{ title: '申请人', key: 'user_name', align: 'center' },
{ title: '请假类型', key: 'leave_type_name', align: 'center' },
{ title: '起止时间', key: 'start_time', width: 300, align: 'center', render: (h, { row }) => h('span', `${row.start_time || '-'} ~ ${row.end_time || '-'}`) },
{ title: '时长', key: 'duration', align: 'center' },
{ title: '状态', key: 'status', align: 'center', render: (h, { row }) => h('span', this.mapStatusText(row.status)) },
{ title: '操作', slot: 'action', align: 'center', width: 160 }
{ title: '操作', slot: 'action', align: 'center', width: 250 }
],
pendingColumns: [
{ type: 'index', title: '序号', width: 60, align: 'center' },
......@@ -373,6 +378,8 @@ export default {
}
],
applyModal: { visible: false, isEdit: false, saving: false, form: {} },
// 控制是否在赋值时触发自动计算(true = 允许计算;false = 赋值时不计算)
suppressDurationCalc: false,
approveModal: { visible: false, record: {}, comment: '', submitting: false, transferEnabled: false, transferApprover: '', approvalFlow: [] },
transferModal: { visible: false, selectedApprover: '', comment: '', processing: false, record: {} },
detailModal: { visible: false, loading: false, data: {}, approvals: [] },
......@@ -390,8 +397,59 @@ export default {
end_time: [
{ required: true, message: '请选择结束时间', trigger: 'change', type: 'date' }
],
duration: [
{
validator: function (rule, value, callback) {
const form = (this && this.applyModal && this.applyModal.form) ? this.applyModal.form : {}
const parseToDateLocal = (v) => {
if (v === null || v === undefined || v === '') return null
if (typeof v === 'number') return new Date(v)
if (typeof v === 'string') {
if (/^\d+$/.test(v)) return new Date(Number(v))
const s = v.includes('T') ? v : v.replace(' ', 'T')
const parsed = new Date(s)
return isNaN(parsed.getTime()) ? null : parsed
}
if (v instanceof Date) return isNaN(v.getTime()) ? null : v
const parsed = new Date(v)
return isNaN(parsed.getTime()) ? null : parsed
}
// 解析起止时间的整天差
const sd = parseToDateLocal(form.start_time)
const ed = parseToDateLocal(form.end_time)
let fullDays = 0
if (sd && ed) {
const diff = ed.getTime() - sd.getTime()
fullDays = Math.floor(diff / (1000 * 60 * 60 * 24))
}
// 如果不足整天,不校验(允许用户填写任意时长)
if (fullDays < 1) { callback(); return }
// 整天或以上时,必须填写且整数部分需与计算天数一致
if (value === null || value === undefined || String(value).trim() === '') {
callback(new Error('请填写请假时长')); return
}
const num = Number(value)
if (isNaN(num) || num <= 0) { callback(new Error('请假天数必须为大于 0 的数字')); return }
const integerPart = Math.floor(num)
if (integerPart !== fullDays) {
callback(new Error(`请假整数天应为 ${fullDays} 天,请确认`)); return
}
callback()
},
trigger: 'blur'
}
],
approver_id: [
{ required: true, message: '请选择指定审批人', trigger: 'change' }
{ required: true, message: '请选择审批人', trigger: 'change' }
],
reason: [
{ required: true, message: '请填写请假事由', trigger: 'change' }
],
emergency_phone: [
{ message: '请输入紧急电话', trigger: 'blur' },
......@@ -400,7 +458,8 @@ export default {
message: '请输入有效的电话号码',
trigger: 'blur'
}
]
],
// (必填性与具体数值由上面的 validator 决定)
}
}
},
......@@ -410,8 +469,23 @@ export default {
this.loadLeaveApprovalOptions()
// 加载待审批计数,用于页面顶部/选项卡徽章显示
this.loadPendingCount()
// 将 duration 的 validator 绑定到组件实例的方法,确保内部能访问 this.applyModal.form
this.applyRules.duration = [{ validator: this.validateDuration, trigger: 'blur' }]
},
watch: {
// 监听开始时间和结束时间变化,自动计算天数
'applyModal.form.start_time' (newVal) {
if (this.suppressDurationCalc) return
// 用户修改起始时间时,先清空已有时长(避免与新时间不符),再进行自动计算
if (this.applyModal && this.applyModal.form) this.applyModal.form.duration = ''
this.calculateDuration()
},
'applyModal.form.end_time' (newVal) {
if (this.suppressDurationCalc) return
// 用户修改结束时间时,先清空已有时长(避免与新时间不符),再进行自动计算
if (this.applyModal && this.applyModal.form) this.applyModal.form.duration = ''
this.calculateDuration()
},
// 当弹窗关闭时清理选择的审批人,确保下次打开时下拉框能正确刷新显示
'applyModal.visible' (val) {
if (!val && this.applyModal && this.applyModal.form) {
......@@ -439,6 +513,79 @@ export default {
}
},
methods: {
// validator 方法:确保能通过 this 访问组件数据
validateDuration (rule, value, callback) {
const form = this.applyModal && this.applyModal.form ? this.applyModal.form : {}
const parseToDateLocal = (v) => {
if (v === null || v === undefined || v === '') return null
if (typeof v === 'number') return new Date(v)
if (typeof v === 'string') {
if (/^\d+$/.test(v)) return new Date(Number(v))
const s = v.includes('T') ? v : v.replace(' ', 'T')
const parsed = new Date(s)
return isNaN(parsed.getTime()) ? null : parsed
}
if (v instanceof Date) return isNaN(v.getTime()) ? null : v
const parsed = new Date(v)
return isNaN(parsed.getTime()) ? null : parsed
}
const sd = parseToDateLocal(form.start_time)
const ed = parseToDateLocal(form.end_time)
let fullDays = 0
if (sd && ed) {
const diff = ed.getTime() - sd.getTime()
fullDays = Math.floor(diff / (1000 * 60 * 60 * 24))
}
// 如果不足整天,不校验
if (fullDays < 1) { callback(); return }
if (value === null || value === undefined || String(value).trim() === '') {
callback(new Error('请填写请假时长')); return
}
const num = Number(value)
if (isNaN(num) || num <= 0) { callback(new Error('请假天数必须为大于 0 的数字')); return }
const integerPart = Math.floor(num)
if (integerPart !== fullDays) {
callback(new Error(`请假整数天应为 ${fullDays} 天,请确认`)); return
}
callback()
},
// 返回给定 tab 的状态下拉选项:只有 apply tab 显示“未提交(0)”,其他 tab 隐藏该选项
statusOptionsFor (tab) {
if (tab === 'apply') return this.statusOptions
// 过滤掉 id 为 '0' 或 0 的未提交选项
return (this.statusOptions || []).filter(opt => String(opt.id) !== '0')
},
// 计算请假天数(只计算整天,忽略零点几部分)
calculateDuration () {
const form = this.applyModal.form
if (!form || !form.start_time || !form.end_time) return
const startDate = new Date(form.start_time)
const endDate = new Date(form.end_time)
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) return
if (endDate.getTime() <= startDate.getTime()) return
// 计算整天数(向下取整),只要整天 >=1 则自动填充为整数天
const diffTime = endDate.getTime() - startDate.getTime()
const fullDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))
const existing = form.duration !== null && form.duration !== undefined && String(form.duration).trim() !== ''
if (fullDays >= 1) {
// 只有当表单中尚未填写时才自动填充,避免覆盖后端/用户已有值
if (!existing) form.duration = String(fullDays)
} else {
// 少于整天时不自动计算,交由用户手动填写(例如半天、几小时)
// 不覆盖已有用户填写的值
if (!existing) form.duration = ''
}
},
handleTabChange (name) {
this.activeTab = name
if (name === 'pending') this.fetchList('pending')
......@@ -709,12 +856,18 @@ export default {
// 默认开始时间为当天(时分秒置为 0),精确到天
const today = new Date()
today.setHours(0, 0, 0, 0)
this.applyModal.form = { user_id: '', user_name: '', leave_type_id: '', start_time: today, end_time: '', duration_unit: 2, duration: 0, reason: '', emergency_contact: '', emergency_phone: '', approver_id: this.selectedApprovalUser || '' }
// 在赋值期间禁止自动计算,直到下一个 tick 再恢复,避免渲染期间 watcher 覆盖表单值
this.suppressDurationCalc = true
this.applyModal.form = { user_id: '', user_name: '', leave_type_id: '', start_time: today, end_time: '', duration_unit: 2, duration: '', reason: '', emergency_contact: '', emergency_phone: '', approver_id: this.selectedApprovalUser || '' }
this.$nextTick(() => { this.suppressDurationCalc = false })
this.applyModal.visible = true
},
openEdit (row) {
this.applyModal.isEdit = true
// 在赋值期间禁止自动计算,直到渲染稳定后再恢复,避免覆盖已有 duration
this.suppressDurationCalc = true
this.applyModal.form = Object.assign({}, row)
this.$nextTick(() => { this.suppressDurationCalc = false })
// ensure approver_id exists on form when editing
if (!this.applyModal.form.approver_id) this.applyModal.form.approver_id = row.approver_id || row.approverId || row.transfer_to_id || ''
// 保证与 leaveApprovalOptions 中 id 的类型一致(字符串)
......@@ -788,6 +941,10 @@ export default {
const status = row && row.status !== null && row.status !== undefined ? Number(row.status) : null
return status === 1
},
canDelete (row) {
const status = row && row.status !== null && row.status !== undefined ? Number(row.status) : null
return status === 0
},
submit (row) {
this.$Modal.confirm({ title: '确认提交',
content: '确认提交此请假申请进入审批流程?',
......@@ -837,7 +994,7 @@ export default {
}
}).catch(err => {
// 出错时提供默认占位并清空展示
this.transferApprovalOptions = [{ id: '', name: '暂无审批人' }]
this.transferApprovalOptions = [{ id: '', name: '请先进行审批人配置' }]
this.approveModal.approvalFlow = []
console.error('selectTransferApprovalList error', err)
}).finally(() => {
......@@ -933,6 +1090,8 @@ export default {
refillApply () {
// 将批准记录数据反显到申请表单,清除 id 和 leave_id
this.applyModal.isEdit = false
// 在赋值期间禁止自动计算,直到渲染稳定后再恢复
this.suppressDurationCalc = true
this.applyModal.form = {
leave_type_id: this.approveModal.record.leave_type_id || '',
start_time: this.approveModal.record.start_time || '',
......@@ -943,6 +1102,7 @@ export default {
approver_id: this.approveModal.record.approver_id || this.selectedApprovalUser || ''
}
// 不保留 id 和 leave_id,保持为空
this.$nextTick(() => { this.suppressDurationCalc = false })
this.applyModal.visible = true
// 关闭审批弹窗
this.approveModal.visible = false
......@@ -950,6 +1110,8 @@ export default {
refillApplyDirect (row) {
// 直接从列表行数据进行重新填报,清除 id 和 leave_id
this.applyModal.isEdit = false
// 在赋值期间禁止自动计算,直到渲染稳定后再恢复
this.suppressDurationCalc = true
this.applyModal.form = {
leave_type_id: row.leave_type_id || '',
start_time: row.start_time || '',
......@@ -960,6 +1122,7 @@ export default {
approver_id: row.approver_id || this.selectedApprovalUser || ''
}
// 不保留 id 和 leave_id,保持为空
this.$nextTick(() => { this.suppressDurationCalc = false })
this.applyModal.visible = true
},
openDetail (row) {
......@@ -1024,6 +1187,17 @@ export default {
this.statsEnd = null
this.statsDept = ''
this.tables.stats = []
},
deleteApply (row) {
deleteById({ id: row.id, leave_id: row.leave_id }).then(ret => {
if (ret.data && ret.data.errcode === 0) {
this.$Message.success('删除成功')
this.fetchList('apply')
} else {
this.$Notice.error({ title: '删除失败', desc: ret.data && ret.data.errmsg })
}
})
}
}
}
......
......@@ -67,7 +67,7 @@ export default {
{ type: 'selection', width: 60, align: 'center' },
{ title: '归属部门', key: 'office_name', align: 'center', minWidth: 150 },
{ title: '姓名', key: 'name', align: 'center', minWidth: 100 },
{ title: '工号', key: 'gh', align: 'center', minWidth: 120 },
// { title: '工号', key: 'gh', align: 'center', minWidth: 120 },
// { title: '邮箱', key: 'email', align: 'center', minWidth: 150 },
{ title: '电话', key: 'phone', align: 'center', minWidth: 120 },
{ title: '手机', key: 'mobile', align: 'center', minWidth: 120 }
......
......@@ -53,13 +53,12 @@ export default {
selectedRow: null,
confirming: false,
columns: [
{ title: '归属部门', key: 'office_name', align: 'center', minWidth: 150 },
{ title: '姓名', key: 'name', align: 'center', minWidth: 100 },
{ title: '工号', key: 'gh', align: 'center', minWidth: 120 },
// { title: '工号', key: 'gh', align: 'center', minWidth: 120 },
{ title: '邮箱', key: 'email', align: 'center', minWidth: 150 },
{ title: '电话', key: 'phone', align: 'center', minWidth: 120 },
{ title: '手机', key: 'mobile', align: 'center', minWidth: 120 },
{ title: '归属部门', key: 'office_name', align: 'center', minWidth: 150 },
{ title: '人员分类', key: 'category_names', align: 'center', minWidth: 200 }
{ title: '手机', key: 'mobile', align: 'center', minWidth: 120 }
]
}
},
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论