This commit is contained in:
shijing 2026-03-23 14:49:24 +08:00
commit d1f7209469
36 changed files with 2763 additions and 760 deletions

View File

@ -4,7 +4,7 @@ NODE_ENV = development
# 标题
# VUE_APP_TITLE = '曲阳金隅安全智能管控平台'
# VUE_APP_TITLE = '托克逊能源管理平台'
VUE_APP_TITLE = '中建材光科技有限公司'
VUE_APP_TITLE = '中建材光科技有限公司'
# VUE_APP_TITLE = '超低排放系统'
VUE_APP_PJ = 'gx'
@ -21,20 +21,28 @@ VUE_APP_PJ = 'gx'
# VUE_APP_BASEURL = http://10.50.211.228:2250/
# VUE_APP_BASEURL = http://127.0.0.1:8887
# VUE_APP_BASEURL = http://127.0.0.1:226
VUE_APP_API_BASEURL = http://127.0.0.1:2226/api
VUE_APP_BASEURL = http://127.0.0.1:2226
# #光子
# VUE_APP_API_BASEURL = http://tkx.xxhhcty.xyz:8080/api
# VUE_APP_BASEURL = http://tkx.xxhhcty.xyz:8080
# 托克逊
# VUE_APP_API_BASEURL = http://10.50.211.228:2250/api
# VUE_APP_BASEURL = http://10.50.211.228:2250/
# 光芯
VUE_APP_API_BASEURL = http://49.232.14.174:2226/api
VUE_APP_BASEURL = http://49.232.14.174:2226
# VUE_APP_API_BASEURL = http://127.0.0.1:2226/api
# VUE_APP_BASEURL = http://127.0.0.1:2226
# 光芯线上
# VUE_APP_API_BASEURL = http://gxerp.xxhhcty.xyz:8080/api
# VUE_APP_BASEURL = http://gxerp.xxhhcty.xyz:8080
# # 凌源 bh
# VUE_APP_API_BASEURL = http://lybh.xxhhcty.xyz:8080/api
# VUE_APP_BASEURL = http://lybh.xxhhcty.xyz:8080/
# 凌源 sl
# VUE_APP_API_BASEURL = http://lysl.xxhhcty.xyz:8080/api
# VUE_APP_BASEURL = http://lysl.xxhhcty.xyz:8080/
# 本地端口
VUE_APP_PORT = 2800

View File

@ -4,8 +4,7 @@
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build --report",
"lint": "vue-cli-service lint"
"build": "vue-cli-service build --report"
},
"dependencies": {
"@element-plus/icons-vue": "2.0.10",
@ -49,40 +48,11 @@
},
"devDependencies": {
"@babel/core": "7.21.00",
"@babel/eslint-parser": "7.19.1",
"@vue/cli-plugin-babel": "5.0.8",
"@vue/cli-plugin-eslint": "5.0.8",
"@vue/cli-service": "5.0.8",
"eslint": "8.35.0",
"eslint-plugin-vue": "9.9.0",
"sass": "1.58.3",
"sass-loader": "10.1.1"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"globals": {
"APP_CONFIG": true
},
"extends": [
"plugin:vue/vue3-essential"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {
"indent": 0,
"no-tabs": 0,
"no-mixed-spaces-and-tabs": 0,
"vue/no-unused-components": 0,
"vue/multi-word-component-names": 0,
"no-debugger": "off",
"no-console": "off",
"no-trailing-spaces": "off"
}
},
"browserslist": [
"> 1%",
"last 2 versions",

114
src/api/model/mpr.js Normal file
View File

@ -0,0 +1,114 @@
import config from "@/config"
import http from "@/utils/request"
export default {
requisition: {
list: {
name: "申购单列表",
req: async function(data){
return await http.get(`${config.API_URL}/mpr/requisition/`, data);
}
},
create: {
name: "创建申购单",
req: async function(data){
return await http.post(`${config.API_URL}/mpr/requisition/`, data);
}
},
item: {
name: "获取申购单详情",
req: async function(id){
return await http.get(`${config.API_URL}/mpr/requisition/${id}/`);
}
},
update: {
name: "更新申购单",
req: async function(id, data){
return await http.put(`${config.API_URL}/mpr/requisition/${id}/`, data);
}
},
delete: {
name: "删除申购单",
req: async function(id){
return await http.delete(`${config.API_URL}/mpr/requisition/${id}/`);
}
},
},
warehouseStock: {
list: {
name: "物料库存列表",
req: async function(data){
return await http.get(`${config.API_URL}/mpr/warehouse_stock/`, data);
}
},
item: {
name: "获取库存详情",
req: async function(id){
return await http.get(`${config.API_URL}/mpr/warehouse_stock/${id}/`);
}
},
},
materialRequisition: {
list: {
name: "领用单列表",
req: async function(data){
return await http.get(`${config.API_URL}/mpr/material_requisition/`, data);
}
},
create: {
name: "创建领用单",
req: async function(data){
return await http.post(`${config.API_URL}/mpr/material_requisition/`, data);
}
},
item: {
name: "获取领用单详情",
req: async function(id){
return await http.get(`${config.API_URL}/mpr/material_requisition/${id}/`);
}
},
update: {
name: "更新领用单",
req: async function(id, data){
return await http.put(`${config.API_URL}/mpr/material_requisition/${id}/`, data);
}
},
delete: {
name: "删除领用单",
req: async function(id){
return await http.delete(`${config.API_URL}/mpr/material_requisition/${id}/`);
}
},
},
warehouseEntry: {
list: {
name: "入库单列表",
req: async function(data){
return await http.get(`${config.API_URL}/mpr/warehouse_entry/`, data);
}
},
create: {
name: "创建入库单",
req: async function(data){
return await http.post(`${config.API_URL}/mpr/warehouse_entry/`, data);
}
},
item: {
name: "获取入库单详情",
req: async function(id){
return await http.get(`${config.API_URL}/mpr/warehouse_entry/${id}/`);
}
},
update: {
name: "更新入库单",
req: async function(id, data){
return await http.put(`${config.API_URL}/mpr/warehouse_entry/${id}/`, data);
}
},
delete: {
name: "删除入库单",
req: async function(id){
return await http.delete(`${config.API_URL}/mpr/warehouse_entry/${id}/`);
}
},
}
}

View File

@ -0,0 +1,80 @@
<template>
<el-dropdown trigger="click" @command="handleExport">
<el-button type="success" icon="el-icon-download">导出</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="page">导出本页数据</el-dropdown-item>
<el-dropdown-item command="all">导出全部数据</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script>
import { dataToExcel } from "@/utils/exportExcel";
const ACT_STATE_MAP = { 0: "草稿中", 1: "进行中", 2: "被退回", 3: "被撤回", 4: "已完成", 5: "已关闭" };
export default {
name: "ScExportBtn",
props: {
getTableRef: { type: Function, required: true },
columns: { type: Array, required: true },
fileName: { type: String, default: "台账数据" },
},
methods: {
flattenData(list) {
if (!Array.isArray(list)) return [];
return list.map(row => {
const flat = { ...row };
const actState = row.ticket_?.act_state;
flat._act_state_text = ACT_STATE_MAP[actState] ?? "";
flat._state_name = row.ticket_?.state_?.name ?? "";
for (const key of Object.keys(flat)) {
if (Array.isArray(flat[key])) {
flat[key] = flat[key].join("、");
}
}
//
for (const key of Object.keys(flat)) {
if (typeof row[key] === "boolean") {
flat["_" + key + "_text"] = row[key] ? "是" : "否";
}
}
return flat;
});
},
getFlatColumns() {
return this.columns.map(col => {
if (col.key === "ticket_.act_state") return { ...col, key: "_act_state_text", type_dict: undefined };
// columns key _text
if (col.boolKey) return { ...col, key: "_" + col.boolKey + "_text", type_dict: undefined };
return col;
});
},
doExport(data) {
const flatData = this.flattenData(data);
const flatCols = this.getFlatColumns();
dataToExcel(flatCols, flatData, this.fileName);
},
handleExport(command) {
const table = this.getTableRef();
if (!table) return;
if (command === "page") {
this.doExport(table.tableData);
} else if (command === "all") {
const query = Object.assign({}, table.query, table.tableParams, { page: 0 });
const loading = this.$loading({ lock: true, text: "数据导出中...", background: "rgba(0,0,0,0.1)" });
table.apiObj.req(query).then((res) => {
loading.close();
this.doExport(res);
}).catch((err) => {
loading.close();
console.error("导出失败", err);
this.$message.error("导出失败");
});
}
},
},
};
</script>

View File

@ -2091,6 +2091,55 @@ const routes = [
},
],
},
//物资申购 mpr
{
name: "mpr",
path: "/mpr",
meta: {
title: "物资管理",
icon: "el-icon-document",
type: "menu",
perms: ["mpr"],
},
children: [
{
name: "requisition",
path: "/mpr/requisition",
meta: {
title: "申购单管理",
perms: ["requisition"],
},
component: "mpr/requisition",
},
{
name: "warehouse_entry",
path: "/mpr/warehouse_entry",
meta: {
title: "入库单管理",
perms: ["warehouse_entry"],
},
component: "mpr/warehouse_entry",
},
{
name: "warehouse_stock",
path: "/mpr/warehouse_stock",
meta: {
title: "物料库存",
perms: ["warehouse_stock"],
},
component: "mpr/warehouse_stock",
},
{
name: "material_requisition",
path: "/mpr/material_requisition",
meta: {
title: "领用记录",
perms: ["material_requisition"],
},
component: "mpr/material_requisition",
},
],
},
//采购 pum
{
name: "pum",

View File

@ -3,6 +3,7 @@
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd('入库')" v-auth="'assetlog.create'">资产入库</el-button>
<ExportBtn v-if="canExport" :getTableRef="() => $refs.table" :columns="exportCols" fileName="资产台账" />
</div>
<div class="right-panel">
<el-input
@ -54,10 +55,20 @@
</el-drawer>
</template>
<script setup>
import { ref } from 'vue'
import { ref, computed } from 'vue'
import API from '@/api'
import TOOL from "@/utils/tool.js"
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
import assetlogin_form from './assetlogin_form.vue'
import ExportBtn from '@/components/scExportBtn/index.vue'
const EXPORT_DEPTS = ['财务', '运营保障部', '综合管理部']
const userInfo = TOOL.data.get("USER_INFO")
const canExport = computed(() => {
const deptName = userInfo?.belong_dept_name || ''
return EXPORT_DEPTS.some(d => deptName.includes(d))
})
const query = ref({});
const drawerVisible = ref(false);
const drawerTitle = ref('资产入库');
@ -67,4 +78,12 @@ const handleAdd = () => {
mode.value = 'add';
drawerVisible.value = true;
}
const exportCols = [
{ header: "操作类型", key: "type", wch: 10 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
{ header: "启用日期", key: "start_date", wch: 16 },
{ header: "保管部门", key: "keep_dept_name", wch: 16 },
{ header: "保管人", key: "keeper_name", wch: 10 },
{ header: "创建时间", key: "create_time", wch: 18 },
]
</script>

View File

@ -1,47 +1,58 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="API.hrm.empcontract.list"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="部门" prop="dept_need_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="劳动合同变更" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<empcontract_form :mode="mode" :t_id="t_id"></empcontract_form>
</el-drawer>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="劳动合同台账" />
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="API.hrm.empcontract.list" row-key="id" stripe
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}">
<el-table-column label="部门" prop="dept_need_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="员工姓名" prop="employee_name" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位" prop="post_name" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="入职日期" prop="join_date" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="合同结束日期" prop="end_contract" min-width="110" show-overflow-tooltip></el-table-column>
<el-table-column label="变更次数" prop="counts" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="应续签" prop="plan_renewal" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="正常续签" prop="normal_renewal" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="续签/变更(年)" prop="change_date" min-width="110" show-overflow-tooltip></el-table-column>
<el-table-column label="变更原因" prop="change_reason" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" min-width="180">
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="劳动合同变更" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<empcontract_form :mode="mode" :t_id="t_id"></empcontract_form>
</el-drawer>
</template>
<script setup>
import { ref } from 'vue'
import API from '@/api'
import empcontract_form from './empcontract_form.vue'
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
const query = ref({});
const drawerVisible = ref(false);
const mode = ref('add');
const t_id = ref(null);
const handleAdd = () => {
mode.value = 'add';
drawerVisible.value = true;
}
</script>
import ExportBtn from '@/components/scExportBtn/index.vue'
import { actStateEnum } from "@/utils/enum.js"
const drawerVisible = ref(false)
const mode = ref('add')
const t_id = ref(null)
const handleAdd = () => { mode.value = 'add'; t_id.value = null; drawerVisible.value = true; }
const exportCols = [
{ header: "部门", key: "dept_need_name", wch: 15 },
{ header: "员工姓名", key: "employee_name", wch: 10 },
{ header: "岗位", key: "post_name", wch: 12 },
{ header: "入职日期", key: "join_date", wch: 12 },
{ header: "合同结束日期", key: "end_contract", wch: 14 },
{ header: "变更次数", key: "counts", wch: 8 },
{ header: "应续签", key: "plan_renewal", wch: 12 },
{ header: "正常续签", key: "normal_renewal", wch: 12 },
{ header: "续签/变更(年)", key: "change_date", wch: 12 },
{ header: "变更原因", key: "change_reason", wch: 25 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
]
</script>

View File

@ -1,48 +1,42 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="API.hrm.empjoin.list"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="部门" prop="dept_need_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="入职日期" prop="join_date" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="员工需求审核" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<empjoin_form :mode="mode" :t_id="t_id"></empjoin_form>
</el-drawer>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="人员交接台账" />
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="API.hrm.empjoin.list" row-key="id" stripe
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}">
<el-table-column label="部门" prop="dept_need_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="入职日期" prop="join_date" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" min-width="180">
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="人员交接审核" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<empjoin_form :mode="mode" :t_id="t_id"></empjoin_form>
</el-drawer>
</template>
<script setup>
import { ref } from 'vue'
import API from '@/api'
import empjoin_form from './empjoin_form.vue'
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
const query = ref({});
const drawerVisible = ref(false);
const mode = ref('add');
const t_id = ref(null);
const handleAdd = () => {
mode.value = 'add';
drawerVisible.value = true;
}
</script>
import ExportBtn from '@/components/scExportBtn/index.vue'
import { actStateEnum } from "@/utils/enum.js"
const drawerVisible = ref(false)
const mode = ref('add')
const t_id = ref(null)
const handleAdd = () => { mode.value = 'add'; t_id.value = null; drawerVisible.value = true; }
const exportCols = [
{ header: "部门", key: "dept_need_name", wch: 15 },
{ header: "入职日期", key: "join_date", wch: 12 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
]
</script>

View File

@ -1,56 +1,58 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="API.hrm.empneed.list"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="部门" prop="dept_need_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_.name }}</el-tag>
</template>
</el-table-column>
<el-table-column label="需求岗位" prop="post_need" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="需求人数" prop="count_need" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="工资报酬" prop="salary" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="到岗日期" prop="arrival_date" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位人员职责描述" prop="duty" width="130" show-overflow-tooltip></el-table-column>
<el-table-column label="性别要求" prop="gender" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="学历要求" prop="education" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="申请理由" prop="reason" width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="相关专业及技能要求" prop="professional_requirement" width="200" show-overflow-tooltip></el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="员工需求审核" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<empneed_form :mode="mode" :t_id="t_id"></empneed_form>
</el-drawer>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="人员需求台账" />
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="API.hrm.empneed.list" row-key="id" stripe
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}">
<el-table-column label="部门" prop="dept_need_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="需求岗位" prop="post_need" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="需求人数" prop="count_need" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="工资报酬" prop="salary" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="到岗日期" prop="arrival_date" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位职责" prop="duty" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="性别要求" prop="gender" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="学历要求" prop="education" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="申请理由" prop="reason" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="专业及技能要求" prop="professional_requirement" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" min-width="180">
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="员工需求审核" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<empneed_form :mode="mode" :t_id="t_id"></empneed_form>
</el-drawer>
</template>
<script setup>
import { ref } from 'vue'
import API from '@/api'
import empneed_form from './empneed_form.vue'
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
const query = ref({});
const drawerVisible = ref(false);
const mode = ref('add');
const t_id = ref(null);
const handleAdd = () => {
mode.value = 'add';
drawerVisible.value = true;
}
</script>
import ExportBtn from '@/components/scExportBtn/index.vue'
import { actStateEnum } from "@/utils/enum.js"
const drawerVisible = ref(false)
const mode = ref('add')
const t_id = ref(null)
const handleAdd = () => { mode.value = 'add'; t_id.value = null; drawerVisible.value = true; }
const exportCols = [
{ header: "部门", key: "dept_need_name", wch: 15 },
{ header: "需求岗位", key: "post_need", wch: 12 },
{ header: "需求人数", key: "count_need", wch: 10 },
{ header: "工资报酬", key: "salary", wch: 10 },
{ header: "到岗日期", key: "arrival_date", wch: 12 },
{ header: "岗位职责", key: "duty", wch: 20 },
{ header: "性别要求", key: "gender", wch: 8 },
{ header: "学历要求", key: "education", wch: 10 },
{ header: "申请理由", key: "reason", wch: 20 },
{ header: "专业及技能要求", key: "professional_requirement", wch: 25 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
]
</script>

View File

@ -1,134 +1,116 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
<div class="right-panel">
<el-select
v-model="query.leave_type"
placeholder="请假类型"
@change="handleQuery"
clearable
style="margin-left: 2px; width: 120px"
>
<el-option
v-for="item in leaveOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
<el-cascader
v-model="query.employee__belong_dept"
:options="deptData"
clearable
placeholder="部门/单位"
@change="handleQuery"
:show-all-levels="false"
:props="{ emitPath: false, checkStrictly: true }"
style="margin-left: 4px; width: 150px"
/>
<el-button
type="primary"
icon="el-icon-search"
@click="handleQuery"
></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="this.$API.hrm.leave.list"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="部门" prop="belong_dept_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="姓名" prop="employee_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位" prop="post_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_.name }}</el-tag>
</template>
</el-table-column>
<el-table-column label="请假类型" prop="leave_type" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="开始时间" prop="start_date" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="结束时间" prop="end_date" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="请假小时数" prop="hour" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="请假事由" prop="reason" width="150" show-overflow-tooltip></el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="请假审批" v-model="drawerVisible" :size="'50%'" destroy-on-close>
<div style="display: flex; height: calc(100% - 60px);">
<div style="flex: 1; padding-right: 20px; overflow-y: auto;">
<leave_form
:mode="mode"
:t_id="t_id"
@success="()=>{handleQuery(); drawerVisible = false}"
@closed="drawerVisible = false"
/>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="请假台账" />
</div>
<div class="right-panel">
<el-input v-model="query.search" placeholder="姓名/工号" clearable @keyup.enter="handleQuery" style="width:140px" />
<el-select v-model="query.leave_type" placeholder="请假类型" @change="handleQuery" clearable style="width:120px">
<el-option v-for="item in leaveOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-cascader v-model="query.employee__belong_dept" :options="deptData" clearable placeholder="部门"
@change="handleQuery" :show-all-levels="false" :props="{ emitPath: false, checkStrictly: true }"
style="width:150px" />
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="this.$API.hrm.leave.list" row-key="id" stripe
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}">
<el-table-column label="姓名" prop="employee_name" min-width="80" show-overflow-tooltip />
<el-table-column label="部门" prop="belong_dept_name" min-width="100" show-overflow-tooltip />
<el-table-column label="岗位" prop="post_name" min-width="80" show-overflow-tooltip />
<el-table-column label="请假类型" min-width="80">
<template #default="scope">
<el-tag
:type="leaveTagType[scope.row.leave_type] || 'info'"
effect="plain"
size="small">
{{ leaveTypeMap[scope.row.leave_type] ?? scope.row.leave_type }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="开始时间" prop="start_date" min-width="140" show-overflow-tooltip />
<el-table-column label="结束时间" prop="end_date" min-width="140" show-overflow-tooltip />
<el-table-column label="时长(h)" prop="hour" min-width="70" align="center" />
<el-table-column label="请假事由" prop="reason" min-width="150" show-overflow-tooltip />
<el-table-column label="审批状态" min-width="180">
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type" size="small">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain" size="small">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="请假审批" v-model="drawerVisible" size="55%" destroy-on-close direction="rtl">
<div style="display: flex; height: calc(100% - 60px);">
<div style="flex: 1; padding-right: 20px; overflow-y: auto;">
<leave_form :mode="mode" :t_id="t_id"
@success="()=>{handleQuery(); drawerVisible = false}" />
</div>
</div>
</div>
</el-drawer>
</el-drawer>
</template>
<script>
import leave_form from './leave_form.vue'
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
import { genTree } from "@/utils/verificate";
import ExportBtn from '@/components/scExportBtn/index.vue'
import { actStateEnum } from "@/utils/enum.js"
import { genTree } from "@/utils/verificate"
const LEAVE_OPTIONS = [
{ label: "事假", value: 10 },
{ label: "病假", value: 20 },
{ label: "婚假", value: 30 },
{ label: "丧假", value: 40 },
{ label: "公假", value: 50 },
{ label: "工伤", value: 60 },
{ label: "产假", value: 70 },
{ label: "护理假", value: 80 },
{ label: "其他", value: 90 },
];
const LEAVE_TYPE_MAP = { 10: "事假", 20: "病假", 30: "婚假", 40: "丧假", 50: "公假", 60: "工伤", 70: "产假", 80: "护理假", 90: "其他" };
const LEAVE_TAG_TYPE = { 10: "", 20: "danger", 30: "success", 40: "info", 50: "warning", 60: "danger", 70: "success", 80: "warning", 90: "info" };
export default {
name: "hrm.leave",
components: {
leave_form,
},
data() {
return {
actStateEnum, interveneTypeEnum,
drawerVisible: false,
mode: 'show',
t_id: null,
deptData: [],
query: {},
leaveOptions:[
{ label: "事假", value: 10 },
{ label: "病假", value: 20 },
{ label: "婚假", value: 30 },
{ label: "丧假", value: 40 },
{ label: "公假", value: 50 },
{ label: "工伤", value: 60 },
{ label: "产假", value: 70 },
{ label: "护理假", value: 80 },
{ label: "其他", value: 90 }
],
};
},
mounted() {
this.getDept();
},
methods: {
handleAdd() {
this.mode = 'add';
this.t_id = null;
this.drawerVisible = true;
},
handleQuery() {
this.$refs.table.queryData(this.query);
},
async getDept() {
let res = await this.$API.system.dept.list.req({
page: 0,
type__in: "dept,rparty",
});
this.deptData = genTree(res);
},
name: "hrm.leave",
components: { leave_form, ExportBtn },
data() {
return {
actStateEnum,
drawerVisible: false,
mode: 'show',
t_id: null,
deptData: [],
query: {},
leaveOptions: LEAVE_OPTIONS,
leaveTypeMap: LEAVE_TYPE_MAP,
leaveTagType: LEAVE_TAG_TYPE,
exportCols: [
{ header: "姓名", key: "employee_name", wch: 10 },
{ header: "部门", key: "belong_dept_name", wch: 15 },
{ header: "岗位", key: "post_name", wch: 12 },
{ header: "请假类型", key: "leave_type", wch: 10, type_dict: LEAVE_TYPE_MAP },
{ header: "开始时间", key: "start_date", wch: 18 },
{ header: "结束时间", key: "end_date", wch: 18 },
{ header: "时长(h)", key: "hour", wch: 8 },
{ header: "请假事由", key: "reason", wch: 25 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
],
};
},
mounted() { this.getDept(); },
methods: {
handleAdd() { this.mode = 'add'; this.t_id = null; this.drawerVisible = true; },
handleQuery() { this.$refs.table.queryData(this.query); },
async getDept() {
let res = await this.$API.system.dept.list.req({ page: 0, type__in: "dept,rparty" });
this.deptData = genTree(res);
},
},
};
</script>
</script>

View File

@ -1,218 +1,246 @@
<template>
<el-container>
<el-main class="nopadding">
<el-form label-width="80px" :rules="rules" :model="formData" style="padding: 20px;" :disabled="localMode === 'show'">
<el-form-item label="员工信息" required>
{{ formData.employee_name }}{{ formData.belong_dept_name }} - {{ formData.post_name }}
</el-form-item>
<el-form-item label="请假类型" required>
<el-select
v-model="formData.leave_type"
placeholder="请选择请假类型"
clearable
style="width: 200px"
@change="handleTypeChange"
>
<el-option label="事假" :value="10" />
<el-option label="病假" :value="20" />
<el-option label="婚假" :value="30" />
<el-option label="丧假" :value="40" />
<el-option label="公假" :value="50" />
<el-option label="工伤" :value="60" />
<el-option label="产假" :value="70" />
<el-option label="护理假" :value="80" />
<el-option label="其他" :value="90" />
</el-select>
</el-form-item>
<el-form-item label="开始日期" required>
<el-date-picker
v-model="formData.start_date"
type="datetime"
placeholder="请假开始日期"
value-format="YYYY-MM-DD HH:mm:ss"
:readonly="localMode === 'show'"
style="width: 200px"
></el-date-picker>
</el-form-item>
<el-form-item label="结束日期" required>
<el-date-picker
v-model="formData.end_date"
type="datetime"
placeholder="请假结束日期"
value-format="YYYY-MM-DD HH:mm:ss"
:readonly="localMode === 'show'"
style="width: 200px"
></el-date-picker>
</el-form-item>
<el-form-item label="请假时长一天8h计算" label-width="180px" required>
<el-input v-model="formData.hour" type="number" min="1" style="width: 160px">
<template #append>小时</template>
</el-input>
</el-form-item>
<el-form-item label="上传附件"
v-if = "showUpload"
prop="file">
<sc-upload-file
v-model="formData.file"
:multiple="false"
:limit="1"
:accept="['.xlsx', '.xls','.pdf','.docx', '.doc', '.jpg', '.png', '.jpeg']"
@success = "fileUPSuccess"
:disabled="localMode ==='show'"
>
<el-button type="primary" icon="el-icon-upload"> </el-button>
<el-container>
<el-main class="nopadding">
<el-form label-width="100px" :rules="rules" :model="formData" ref="formRef"
style="padding: 20px;" :disabled="localMode === 'show'">
<el-form-item label="员工信息" prop="employee" required>
<template v-if="localMode === 'add'">
<el-select
v-model="formData.employee"
filterable
:filter-method="filterEmployee"
placeholder="请输入姓名搜索"
:loading="empLoading"
style="width: 100%"
@change="handleEmpChange">
<el-option
v-for="item in filteredEmpOptions"
:key="item.id"
:label="`${item.name}${item.belong_dept_name || ''} - ${item.post_name || ''}`"
:value="item.id" />
</el-select>
</template>
<template v-else>
<span style="font-weight:500">{{ formData.employee_name }}</span>
<span style="color:#909399;margin-left:8px">{{ formData.belong_dept_name }} / {{ formData.post_name }}</span>
</template>
</el-form-item>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="请假类型" prop="leave_type" required>
<el-select v-model="formData.leave_type" placeholder="请选择" clearable
style="width: 100%" @change="handleTypeChange">
<el-option v-for="item in leaveOptions" :key="item.value"
:label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请假时长" prop="hour" required>
<el-input v-model="formData.hour" type="number" :min="1" placeholder="小时数">
<template #append>小时</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="开始时间" prop="start_date" required>
<el-date-picker
v-model="formData.start_date"
type="datetime"
placeholder="开始时间"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结束时间" prop="end_date" required>
<el-date-picker
v-model="formData.end_date"
type="datetime"
placeholder="结束时间"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="上传附件" v-if="showUpload" prop="file">
<sc-upload-file
v-model="formData.file"
:multiple="false"
:limit="1"
:accept="['.xlsx','.xls','.pdf','.docx','.doc','.jpg','.png','.jpeg']"
@success="fileUPSuccess"
:disabled="localMode === 'show'">
<el-button type="primary" icon="el-icon-upload">选择文件</el-button>
</sc-upload-file>
</el-form-item>
<el-form-item label="申请理由" required>
<el-input v-model="formData.reason" type="textarea" rows="3" style="width: 400px" placeholder="请输入请假理由"></el-input>
</el-form-item>
</el-form>
<el-footer>
<el-button type="danger"
v-if="localMode=='edit'"
style="margin-right: 4px;"
@click="handleDel"
:loading="saveLoading"
>删除</el-button>
<ticketd_b
v-if = "formData.ticket_ && localMode=='show'"
:t_id="formData.id"
:ticket_="formData.ticket_"
:ticket_data="ticket_data"
@success="$emit('success', localMode)"
ref="ticketd_b"
></ticketd_b>
<el-button
v-if="localMode!='show'"
type="primary"
style="margin-right: 4px;"
@click="handleSave"
:loading="saveLoading"
>提交审批</el-button>
</el-footer>
</el-main>
<el-aside width="20%" v-if="formData.ticket_">
<ticketd :ticket_="formData.ticket_" @success="$emit('success')"></ticketd>
</el-aside>
</el-container>
<el-form-item label="请假事由" prop="reason" required>
<el-input v-model="formData.reason" type="textarea" :rows="3" placeholder="请输入请假理由" />
</el-form-item>
</el-form>
<el-footer>
<el-button type="danger" v-if="localMode === 'edit'" @click="handleDel" :loading="saveLoading">删除</el-button>
<ticketd_b
v-if="formData.ticket_ && localMode === 'show'"
:t_id="formData.id"
:ticket_="formData.ticket_"
:ticket_data="ticket_data"
@success="$emit('success', localMode)"
ref="ticketd_b" />
<el-button v-if="localMode !== 'show'" type="primary" @click="handleSave" :loading="saveLoading">提交审批</el-button>
</el-footer>
</el-main>
<el-aside width="20%" v-if="formData.ticket_">
<ticketd :ticket_="formData.ticket_" @success="$emit('success')" style="margin-top: 20px;" />
</el-aside>
</el-container>
</template>
<script>
import ticketd_b from "@/views/wf/ticketd_b.vue";
import ticketd from '@/views/wf/ticketd.vue'
export default {
components: {
ticketd_b,
ticketd
},
props: {
mode: {
type: String,
default: 'show'
},
t_id: {
type: String,
default: ""
}
},
computed: {
showUpload() {
return [20, 30, 40, 70].includes(this.formData.leave_type)
},
},
data() {
return {
formData: {},
ticket_data: {},
localMode: this.mode,
saveLoading: false,
rules: {
leave_type: [{ required: true, message: "请输入请假类型", trigger: "blur" }],
start_date: [{ required: true, message: "请选择开始时间", trigger: "blur" }],
end_date: [{ required: true, message: "请选择结束时间", trigger: "blur" }],
hour: [{ required: true, message: "请输入请假时长", trigger: "blur" }],
file: [{ required: true, message: "请上传附件", trigger: "blur" }],
reason: [{ required: true, message: "请输入请假理由", trigger: "blur" }],
},
}
},
watch: {
mode(val) {
this.localMode = val;
const LEAVE_OPTIONS = [
{ label: "事假", value: 10 },
{ label: "病假", value: 20 },
{ label: "婚假", value: 30 },
{ label: "丧假", value: 40 },
{ label: "公假", value: 50 },
{ label: "工伤", value: 60 },
{ label: "产假", value: 70 },
{ label: "护理假", value: 80 },
{ label: "其他", value: 90 },
];
const LEAVE_TYPE_NAME = Object.fromEntries(LEAVE_OPTIONS.map(i => [i.value, i.label]));
},
},
mounted() {
if (this.t_id) {
this.getTid();
}else {
this.initFormData();
}
export default {
components: { ticketd_b, ticketd },
props: {
mode: { type: String, default: 'show' },
t_id: { type: String, default: "" },
},
data() {
return {
formData: {},
ticket_data: {},
localMode: this.mode,
saveLoading: false,
empLoading: false,
empOptions: [],
filterKeyword: '',
currentDeptId: null,
leaveOptions: LEAVE_OPTIONS,
rules: {
employee: [{ required: true, message: "请选择员工", trigger: "change" }],
leave_type: [{ required: true, message: "请选择请假类型", trigger: "change" }],
start_date: [{ required: true, message: "请选择开始时间", trigger: "change" }],
end_date: [{ required: true, message: "请选择结束时间", trigger: "change" }],
hour: [{ required: true, message: "请输入请假时长", trigger: "blur" }],
reason: [{ required: true, message: "请输入请假理由", trigger: "blur" }],
},
}
},
computed: {
showUpload() {
return [20, 30, 40, 70].includes(this.formData.leave_type)
},
methods: {
async getTid() {
try {
let res = await this.$API.hrm.leave.item.req(this.t_id);
this.formData = res;
if (res.ticket_ && res.ticket_.state_.type == 1 && res.create_by == this.$TOOL.data.get("USER_INFO").id) {
this.localMode = "edit";
}
} catch (error) {
console.error('获取请假数据失败:', error);
}
},
async initFormData() {
try {
let res = await this.$API.hrm.employee.read.req();
this.formData.employee_name = res.name;
this.formData.belong_dept_name = res.belong_dept_name;
this.formData.post_name = res.post_name;
this.formData.employee = res.id;
this.localMode = "add";
} catch (error) {
console.error('初始化表单数据失败:', error);
}
},
handleTypeChange(val) {
const map = {
10: '事假',
20: '病假',
30: '婚假',
40: '丧假',
50: '公假',
60: '工伤',
70: '产假',
80: '护理假',
90: '其他',
}
this.formData.leave_type_name = map[val] || ''
},
handleDel() {
this.$confirm(`确定删除吗?`, "提示", {
type: "warning",
})
.then(()=>{
this.$API.hrm.leave.delete.req(this.formData.id).then(res=>{
this.$message.success("删除成功");
this.$emit('success');
})
})
},
async handleSave() {
if (this.localMode == "add") {
try {
let res = await this.$API.hrm.leave.create.req(this.formData);
this.$message.success("提交成功");
this.$emit('success', this.localMode);
} catch (error) {
console.error('请假需求申请失败:', error);
throw error;
}
} else if (this.localMode == "edit") {
this.$message.error("不支持编辑");
}
},
},
};
</script>
filteredEmpOptions() {
if (!this.filterKeyword) return this.empOptions;
const kw = this.filterKeyword.toLowerCase();
return this.empOptions.filter(e =>
(e.name || '').toLowerCase().includes(kw) ||
(e.belong_dept_name || '').toLowerCase().includes(kw) ||
(e.post_name || '').toLowerCase().includes(kw)
);
},
},
watch: {
mode(val) { this.localMode = val; },
},
mounted() {
if (this.t_id) {
this.getTid();
} else {
this.initFormData();
}
},
methods: {
async getTid() {
try {
let res = await this.$API.hrm.leave.item.req(this.t_id);
this.formData = res;
if (res.ticket_ && res.ticket_.state_.type == 1 && res.create_by == this.$TOOL.data.get("USER_INFO").id) {
this.localMode = "edit";
}
} catch (e) {
console.error('获取请假数据失败:', e);
}
},
async initFormData() {
try {
let userInfo = this.$TOOL.data.get("USER_INFO");
this.currentDeptId = userInfo.belong_dept;
//
let res = await this.$API.hrm.employee.read.req();
this.formData.employee_name = res.name;
this.formData.belong_dept_name = res.belong_dept_name;
this.formData.post_name = res.post_name;
//
await this.loadDeptEmployees();
// add
this.localMode = "add";
} catch (e) {
console.error('初始化表单数据失败:', e);
}
},
async loadDeptEmployees() {
if (!this.currentDeptId) return;
try {
let res = await this.$API.hrm.employee.list.req({ page: 0, belong_dept: this.currentDeptId });
this.empOptions = Array.isArray(res) ? res : (res.results || []);
} catch (e) {
console.error(e);
}
},
filterEmployee(keyword) {
this.filterKeyword = keyword;
},
handleEmpChange(id) {
const emp = this.empOptions.find(e => e.id === id);
if (emp) {
this.formData.employee_name = emp.name;
this.formData.belong_dept_name = emp.belong_dept_name || '';
this.formData.post_name = emp.post_name || '';
}
},
handleTypeChange(val) {
this.formData.leave_type_name = LEAVE_TYPE_NAME[val] || ''
},
handleDel() {
this.$confirm('确定删除吗?', "提示", { type: "warning" }).then(() => {
this.$API.hrm.leave.delete.req(this.formData.id).then(() => {
this.$message.success("删除成功");
this.$emit('success');
})
})
},
async handleSave() {
if (this.localMode == "add") {
try {
await this.$API.hrm.leave.create.req(this.formData);
this.$message.success("提交成功");
this.$emit('success', this.localMode);
} catch (e) {
console.error('请假申请失败:', e);
throw e;
}
}
},
fileUPSuccess(res) {
this.formData.file = res?.path || ''
},
},
};
</script>

View File

@ -1,119 +1,83 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
<div class="right-panel">
<el-input
v-model="query.search"
placeholder="姓名/手机号"
clearable
@keyup.enter="handleQuery"
style="margin-left: 4px; width: 150px"
></el-input>
<el-cascader
v-model="query.reg_dept"
:options="deptData"
clearable
placeholder="部门/单位"
@change="handleQuery"
:show-all-levels="false"
:props="{ emitPath: false, checkStrictly: true }"
style="margin-left: 4px; width: 150px"
/>
<el-button
type="primary"
icon="el-icon-search"
@click="handleQuery"
></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="this.$API.hrm.probation.list"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="部门" prop="reg_dept_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="姓名" prop="employee_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位" prop="post_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_.name }}</el-tag>
</template>
</el-table-column>
<el-table-column label="身份证号" prop="IDcard" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="试用日期" prop="trial_date" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="转正日期" prop="regular_date" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="转正申请" prop="content" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="应聘人员登记表" prop="record_file" width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="员工转正申请表" prop="apply_file" width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="PPT 汇报考核" prop="ppt_file" width="150" show-overflow-tooltip></el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="转正审批" v-model="drawerVisible" :size="'50%'" destroy-on-close>
<div style="display: flex; height: calc(100% - 60px);">
<div style="flex: 1; padding-right: 20px; overflow-y: auto;">
<probation_form
:mode="mode"
:t_id="t_id"
@success="()=>{handleQuery(); drawerVisible = false}"
@closed="drawerVisible = false"
/>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="人员转正台账" />
</div>
<div class="right-panel">
<el-input v-model="query.search" placeholder="姓名/手机号" clearable @keyup.enter="handleQuery" style="width:150px"></el-input>
<el-cascader v-model="query.reg_dept" :options="deptData" clearable placeholder="部门/单位"
@change="handleQuery" :show-all-levels="false" :props="{ emitPath: false, checkStrictly: true }"
style="width:150px" />
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="this.$API.hrm.probation.list" row-key="id" stripe
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}">
<el-table-column label="部门" prop="reg_dept_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="姓名" prop="employee_name" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位" prop="post_name" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="身份证号" prop="IDcard" min-width="170" show-overflow-tooltip></el-table-column>
<el-table-column label="试用日期" prop="trial_date" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="转正日期" prop="regular_date" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="转正申请" prop="content" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" min-width="180">
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="转正审批" v-model="drawerVisible" :size="'50%'" destroy-on-close>
<div style="display: flex; height: calc(100% - 60px);">
<div style="flex: 1; padding-right: 20px; overflow-y: auto;">
<probation_form :mode="mode" :t_id="t_id"
@success="()=>{handleQuery(); drawerVisible = false}" @closed="drawerVisible = false" />
</div>
</div>
</div>
</el-drawer>
</el-drawer>
</template>
<script>
import probation_form from './probation_form.vue'
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
import { genTree } from "@/utils/verificate";
import ExportBtn from '@/components/scExportBtn/index.vue'
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js"
import { genTree } from "@/utils/verificate"
export default {
name: "hrm.probation",
components: {
probation_form,
},
data() {
return {
actStateEnum, interveneTypeEnum,
drawerVisible: false,
mode: 'show',
t_id: null,
deptData: [],
query: {},
nameList:[],
};
},
mounted() {
this.getDept();
},
methods: {
handleAdd() {
this.mode = 'add';
this.t_id = null;
this.drawerVisible = true;
},
handleQuery() {
this.$refs.table.queryData(this.query);
},
async getDept() {
let res = await this.$API.system.dept.list.req({
page: 0,
type__in: "dept,rparty",
});
this.deptData = genTree(res);
},
name: "hrm.probation",
components: { probation_form, ExportBtn },
data() {
return {
actStateEnum, interveneTypeEnum,
drawerVisible: false,
mode: 'show',
t_id: null,
deptData: [],
query: {},
exportCols: [
{ header: "部门", key: "reg_dept_name", wch: 15 },
{ header: "姓名", key: "employee_name", wch: 10 },
{ header: "岗位", key: "post_name", wch: 12 },
{ header: "身份证号", key: "IDcard", wch: 20 },
{ header: "试用日期", key: "trial_date", wch: 12 },
{ header: "转正日期", key: "regular_date", wch: 12 },
{ header: "转正申请", key: "content", wch: 25 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
],
};
},
mounted() { this.getDept(); },
methods: {
handleAdd() { this.mode = 'add'; this.t_id = null; this.drawerVisible = true; },
handleQuery() { this.$refs.table.queryData(this.query); },
async getDept() {
let res = await this.$API.system.dept.list.req({ page: 0, type__in: "dept,rparty" });
this.deptData = genTree(res);
},
},
};
</script>
</script>

View File

@ -1,65 +1,55 @@
<template>
<el-container>
<el-header>
<div class="left-panel"></div>
<div class="right-panel">
<!-- <el-button type="primary" @click="handleAdd">新增</el-button> -->
<el-input
v-model="query.search"
placeholder="姓名"
clearable
@keyup.enter="$refs.table.refresh()"
></el-input>
<el-button
type="primary"
icon="el-icon-search"
@click="handleQuery"
></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="API.hrm.resignation.list"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="姓名" prop="employee_name" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_.name }}</el-tag>
<el-container>
<el-header>
<div class="left-panel">
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="离职申请台账" />
</div>
<div class="right-panel">
<el-input v-model="query.search" placeholder="姓名" clearable @keyup.enter="handleQuery" style="width:150px"></el-input>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="API.hrm.resignation.list" row-key="id" stripe
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}">
<el-table-column label="姓名" prop="employee_name" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="部门" prop="belong_dept_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位" prop="post_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="身份证号" prop="employee_id_number" min-width="170" show-overflow-tooltip></el-table-column>
<el-table-column label="离职日期" prop="end_date" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="原因" prop="reason" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" min-width="180">
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
</el-table-column>`
<el-table-column label="部门" prop="belong_dept_name" width="120" show-overflow-tooltip></el-table-column>`
<el-table-column label="岗位" prop="post_name" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="身份证号" prop="employee_id_number" width="200" show-overflow-tooltip></el-table-column>
<el-table-column label="离职日期" prop="end_date" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="原因" prop="reason" show-overflow-tooltip></el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="离职申请" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<resignation-form :mode="mode" :t_id="t_id"></resignation-form>
</el-drawer>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="离职申请" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<resignation-form :mode="mode" :t_id="t_id"></resignation-form>
</el-drawer>
</template>
<script setup>
import { ref } from 'vue'
import API from '@/api'
import resignationForm from './resignation_form.vue'
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
const query = ref({});
const drawerVisible = ref(false);
const mode = ref('add');
const t_id = ref(null);
const handleAdd = () => {
mode.value = 'add';
drawerVisible.value = true;
}
</script>
import ExportBtn from '@/components/scExportBtn/index.vue'
import { actStateEnum } from "@/utils/enum.js"
const query = ref({})
const drawerVisible = ref(false)
const mode = ref('add')
const t_id = ref(null)
const table = ref(null)
const handleQuery = () => { table.value?.queryData(query.value) }
const exportCols = [
{ header: "姓名", key: "employee_name", wch: 10 },
{ header: "部门", key: "belong_dept_name", wch: 15 },
{ header: "岗位", key: "post_name", wch: 12 },
{ header: "身份证号", key: "employee_id_number", wch: 20 },
{ header: "离职日期", key: "end_date", wch: 12 },
{ header: "原因", key: "reason", wch: 25 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
]
</script>

View File

@ -1,66 +1,68 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="API.hrm.transfer.list"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="员工" prop="employee_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位" prop="post_name" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="原部门" prop="original_dept" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="入职部门" prop="new_dept" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="跨部门调动" prop="is_change" width="80" show-overflow-tooltip>
<template #default="scope">
{{scope.row.is_change?'是':'否'}}
</template>
</el-table-column>
<el-table-column label="跨部门调动" prop="is_change" width="80" show-overflow-tooltip>
<template #default="scope">
{{scope.row.is_promotion?'是':'否'}}
</template>
</el-table-column>
<el-table-column label="原岗位" prop="original_post" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="入职岗位" prop="new_post" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="调岗日期" prop="transfer_date" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="个人工作内容" prop="content" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="调岗原因" prop="transfer_reason" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="调岗日期" prop="transfer_date" width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="人员调岗审核" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<transfer_form :mode="mode" :t_id="t_id"></transfer_form>
</el-drawer>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="人员调岗台账" />
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="API.hrm.transfer.list" row-key="id" stripe
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}">
<el-table-column label="员工" prop="employee_name" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="岗位" prop="post_name" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="原部门" prop="original_dept_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="调入部门" prop="new_dept_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="原岗位" prop="original_post_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="调入岗位" prop="new_post_name" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="跨部门调动" min-width="90" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="scope.row.is_change ? 'danger' : 'info'" size="small">{{ scope.row.is_change ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="晋升" min-width="70" show-overflow-tooltip>
<template #default="scope">
<el-tag :type="scope.row.is_promotion ? 'success' : 'info'" size="small">{{ scope.row.is_promotion ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="调岗日期" prop="transfer_date" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="个人工作内容" prop="content" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="调岗原因" prop="transfer_reason" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" min-width="180">
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="人员调岗审核" v-model="drawerVisible" :size="'80%'" destroy-on-close>
<transfer_form :mode="mode" :t_id="t_id"></transfer_form>
</el-drawer>
</template>
<script setup>
import { ref } from 'vue'
import API from '@/api'
import transfer_form from './transfer_form.vue'
import { actStateEnum } from "@/utils/enum.js";
const query = ref({});
const drawerVisible = ref(false);
const mode = ref('add');
const t_id = ref(null);
const handleAdd = () => {
mode.value = 'add';
drawerVisible.value = true;
}
</script>
import ExportBtn from '@/components/scExportBtn/index.vue'
import { actStateEnum } from "@/utils/enum.js"
const drawerVisible = ref(false)
const mode = ref('add')
const t_id = ref(null)
const handleAdd = () => { mode.value = 'add'; t_id.value = null; drawerVisible.value = true; }
const exportCols = [
{ header: "员工", key: "employee_name", wch: 10 },
{ header: "岗位", key: "post_name", wch: 12 },
{ header: "原部门", key: "original_dept_name", wch: 12 },
{ header: "调入部门", key: "new_dept_name", wch: 12 },
{ header: "原岗位", key: "original_post_name", wch: 12 },
{ header: "调入岗位", key: "new_post_name", wch: 12 },
{ header: "跨部门调动", key: "_is_change_text", wch: 10 },
{ header: "晋升", key: "_is_promotion_text", wch: 8 },
{ header: "调岗日期", key: "transfer_date", wch: 12 },
{ header: "个人工作内容", key: "content", wch: 20 },
{ header: "调岗原因", key: "transfer_reason", wch: 20 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
]
</script>

View File

@ -0,0 +1,128 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" v-auth="'material_requisition.create'">新增领用单</el-button>
</div>
<div class="right-panel">
<el-select v-model="query.belong_dept" placeholder="领用部门" clearable style="width: 140px; margin-right: 10px;" @change="handleQuery">
<el-option v-for="d in deptOptions" :key="d.id" :label="d.name" :value="d.id"></el-option>
</el-select>
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 260px; margin-right: 10px;"
@change="handleDateChange"
></el-date-picker>
<el-input v-model="query.search" placeholder="编号/操作人/领取人" clearable style="width: 200px;" @keyup.enter="handleQuery"></el-input>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="$API.mpr.materialRequisition.list"
row-key="id"
stripe
:query="query"
@row-click="rowClick"
>
<el-table-column type="index" width="50" />
<el-table-column label="编号" prop="number" width="200" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<template v-if="scope.row.ticket_">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
<el-tag v-else type="info">未提交</el-tag>
</template>
</el-table-column>
<el-table-column label="领用部门" prop="belong_dept_name" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="填报时间" prop="req_date" width="120" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="领取人" prop="collector" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="操作人" prop="create_by_name" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="创建时间" prop="create_time" width="170" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="备注" prop="note" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" fixed="right" align="center" width="100">
<template #default="scope">
<el-button link type="danger" @click.stop="handleDel(scope.row)" v-auth="'material_requisition.delete'">删除</el-button>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="领用记录详情" v-model="drawerVisible" :size="'85%'" destroy-on-close>
<requisition-form :mode="mode" :t_id="t_id" @success="handleSuccess"></requisition-form>
</el-drawer>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import API from '@/api'
import requisitionForm from './material_requisition_form.vue'
import { actStateEnum } from "@/utils/enum.js"
const table = ref(null)
const query = ref({})
const dateRange = ref(null)
const drawerVisible = ref(false)
const mode = ref('add')
const t_id = ref(null)
const deptOptions = ref([])
onMounted(async () => {
try {
let res = await API.system.dept.list.req({ page: 0 })
deptOptions.value = Array.isArray(res) ? res : (res.results || [])
} catch (e) {}
})
const handleAdd = () => {
mode.value = 'add'
t_id.value = null
drawerVisible.value = true
}
const rowClick = (row) => {
t_id.value = row.id
mode.value = 'show'
drawerVisible.value = true
}
const handleQuery = () => {
table.value.refresh()
}
const handleDateChange = (val) => {
if (val) {
query.value.req_date_after = val[0]
query.value.req_date_before = val[1]
} else {
delete query.value.req_date_after
delete query.value.req_date_before
}
handleQuery()
}
const handleDel = (row) => {
ElMessageBox.confirm('确定删除该领用记录吗?', '提示', { type: 'warning' })
.then(() => {
API.mpr.materialRequisition.delete.req(row.id).then(() => {
ElMessage.success('删除成功')
table.value.refresh()
})
})
}
const handleSuccess = () => {
drawerVisible.value = false
table.value.refresh()
}
</script>

View File

@ -0,0 +1,397 @@
<template>
<el-container>
<el-main class="nopadding">
<div style="padding: 20px;">
<el-descriptions title="物资领用单" :column="3" border>
<el-descriptions-item label="编号">{{ formData.number || '自动生成' }}</el-descriptions-item>
<el-descriptions-item label="领用部门">{{ formData.belong_dept_name || currentUser.belong_dept_name }}</el-descriptions-item>
<el-descriptions-item label="填报时间">
<el-date-picker
v-if="isEditable"
v-model="formData.req_date"
type="date"
placeholder="填报时间"
value-format="YYYY-MM-DD"
style="width: 200px;"
/>
<span v-else>{{ formData.req_date }}</span>
</el-descriptions-item>
<el-descriptions-item label="操作人">{{ formData.create_by_name || currentUser.name }}</el-descriptions-item>
<el-descriptions-item label="领取人">
<el-input v-if="isEditable" v-model="formData.collector" placeholder="领取人" style="width: 200px;" />
<span v-else>{{ formData.collector }}</span>
</el-descriptions-item>
<el-descriptions-item label="备注">
<el-input v-if="isEditable" v-model="formData.note" type="textarea" :rows="1" placeholder="备注" />
<span v-else>{{ formData.note }}</span>
</el-descriptions-item>
</el-descriptions>
<!-- 库存物品从物料库存中选择 -->
<div style="margin-top: 20px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h4 style="margin: 0;">库存物品领用</h4>
<el-button v-if="isEditable" type="primary" size="small" icon="el-icon-plus" @click="openStockPicker">从库存选择</el-button>
</div>
<el-table :data="stockItems" border stripe style="width: 100%">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="领用类型" width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.req_type" placeholder="领用类型" />
<span v-else>{{ scope.row.req_type }}</span>
</template>
</el-table-column>
<el-table-column label="物资名称" min-width="120" prop="name" show-overflow-tooltip></el-table-column>
<el-table-column label="规格型号" width="120" prop="spec" show-overflow-tooltip></el-table-column>
<el-table-column label="单位" width="80" prop="unit"></el-table-column>
<el-table-column label="库存量" width="100">
<template #default="scope">
<span style="color: #909399;">{{ scope.row.stock_quantity }}</span>
</template>
</el-table-column>
<el-table-column label="领用量" width="130">
<template #default="scope">
<el-input-number
v-if="isEditable"
v-model="scope.row.quantity"
:min="0"
:max="Number(scope.row.stock_quantity)"
:precision="3"
size="small"
controls-position="right"
/>
<span v-else>{{ scope.row.quantity }}</span>
</template>
</el-table-column>
<el-table-column label="备注" min-width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.note" placeholder="备注" />
<span v-else>{{ scope.row.note }}</span>
</template>
</el-table-column>
<el-table-column v-if="isEditable" label="操作" width="80" align="center" fixed="right">
<template #default="scope">
<el-button link type="danger" @click="delStockItem(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 非物资清单物品 -->
<div style="margin-top: 20px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h4 style="margin: 0;">非物资清单物品</h4>
<el-button v-if="isEditable" type="primary" size="small" icon="el-icon-plus" @click="addNonStockItem">添加</el-button>
</div>
<el-table :data="nonStockItems" border stripe style="width: 100%">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="领用类型" width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.req_type" placeholder="领用类型" />
<span v-else>{{ scope.row.req_type }}</span>
</template>
</el-table-column>
<el-table-column label="物资名称" min-width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.name" placeholder="名称" />
<span v-else>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="规格型号" width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.spec" placeholder="规格型号" />
<span v-else>{{ scope.row.spec }}</span>
</template>
</el-table-column>
<el-table-column label="单位" width="80">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.unit" placeholder="单位" />
<span v-else>{{ scope.row.unit }}</span>
</template>
</el-table-column>
<el-table-column label="领用量" width="130">
<template #default="scope">
<el-input-number v-if="isEditable" v-model="scope.row.quantity" :min="0" :precision="3" size="small" controls-position="right" />
<span v-else>{{ scope.row.quantity }}</span>
</template>
</el-table-column>
<el-table-column label="备注" min-width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.note" placeholder="备注" />
<span v-else>{{ scope.row.note }}</span>
</template>
</el-table-column>
<el-table-column v-if="isEditable" label="操作" width="80" align="center" fixed="right">
<template #default="scope">
<el-button link type="danger" @click="delNonStockItem(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div style="text-align: right; margin-top: 15px; font-size: 14px;">
<span style="margin-right: 30px;">部门负责人___________</span>
<span>领取人{{ formData.collector || '___________' }}</span>
</div>
</div>
<el-footer style="padding: 10px 20px; text-align: left;">
<el-button type="danger"
v-if="localMode === 'edit'"
style="margin-right: 4px;"
@click="handleDel"
:loading="saveLoading"
>删除</el-button>
<el-button
v-if="isEditable"
type="primary"
style="margin-right: 4px;"
@click="handleSubmit"
:loading="saveLoading"
>提交审批</el-button>
<ticketd_b
v-if="formData.ticket_ && localMode === 'show'"
:t_id="formData.id"
:ticket_="formData.ticket_"
:ticket_data="ticket_data"
@success="$emit('success')"
ref="ticketd_b"
></ticketd_b>
</el-footer>
</el-main>
<el-aside width="20%" v-if="formData.ticket_">
<ticketd :ticket_="formData.ticket_" @success="$emit('success')"></ticketd>
</el-aside>
</el-container>
<!-- 库存选择对话框 -->
<el-dialog title="选择库存物品" v-model="stockPickerVisible" width="80%" destroy-on-close>
<div style="margin-bottom: 10px; display: flex; gap: 10px;">
<el-input v-model="stockSearch" placeholder="搜索名称/规格/供应商" clearable style="width: 300px;" @keyup.enter="loadStockList"></el-input>
<el-button type="primary" @click="loadStockList">搜索</el-button>
</div>
<el-table :data="stockList" border stripe @selection-change="handleStockSelectionChange" max-height="400">
<el-table-column type="selection" width="55" />
<el-table-column label="名称" prop="name" min-width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="规格" prop="spec" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="单位" prop="unit" width="80"></el-table-column>
<el-table-column label="库存量" prop="quantity" width="100"></el-table-column>
<el-table-column label="仓库" prop="warehouse_name" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="入库单号" prop="entry_number" width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="供应商" prop="supplier_name" width="120" show-overflow-tooltip></el-table-column>
</el-table>
<template #footer>
<el-button @click="stockPickerVisible = false">取消</el-button>
<el-button type="primary" @click="confirmStockPick">确认选择 ({{ selectedStocks.length }})</el-button>
</template>
</el-dialog>
</template>
<script>
import ticketd_b from "@/views/wf/ticketd_b.vue"
import ticketd from '@/views/wf/ticketd.vue'
export default {
name: 'MaterialRequisitionForm',
components: { ticketd_b, ticketd },
props: {
mode: { type: String, default: 'show' },
t_id: { type: String, default: "" }
},
emits: ['success'],
data() {
return {
formData: {},
stockItems: [],
nonStockItems: [],
localMode: this.mode,
saveLoading: false,
ticket_data: {},
currentUser: this.$TOOL.data.get("USER_INFO") || {},
stockPickerVisible: false,
stockSearch: '',
stockList: [],
selectedStocks: [],
}
},
computed: {
isEditable() {
return this.localMode === 'add' || this.localMode === 'edit'
},
},
async mounted() {
if (this.t_id) {
this.loadData()
} else {
this.localMode = 'add'
}
},
methods: {
async loadData() {
try {
let res = await this.$API.mpr.materialRequisition.item.req(this.t_id)
this.formData = res
const allItems = res.items_ || []
this.stockItems = allItems.filter(i => i.is_stock_item).map(i => ({
...i,
stock_id: i.stock,
stock_quantity: '—',
}))
this.nonStockItems = allItems.filter(i => !i.is_stock_item)
if (res.ticket_ && res.ticket_.state_.type === 1 && res.create_by === this.currentUser.id) {
this.localMode = 'edit'
}
} catch (error) {
this.$message.error('加载失败')
}
},
async openStockPicker() {
this.stockSearch = ''
this.selectedStocks = []
await this.loadStockList()
this.stockPickerVisible = true
},
async loadStockList() {
try {
let res = await this.$API.mpr.warehouseStock.list.req({ page: 0, search: this.stockSearch })
const existingIds = new Set(this.stockItems.map(i => i.stock_id))
this.stockList = (Array.isArray(res) ? res : res.results || []).filter(
s => Number(s.quantity) > 0 && !existingIds.has(s.id)
)
} catch (error) {
this.$message.error('加载库存失败')
}
},
handleStockSelectionChange(rows) {
this.selectedStocks = rows
},
confirmStockPick() {
this.selectedStocks.forEach(s => {
this.stockItems.push({
is_stock_item: true,
stock_id: s.id,
name: s.name,
spec: s.spec,
unit: s.unit,
stock_quantity: s.quantity,
quantity: 0,
req_type: '',
note: '',
})
})
this.stockPickerVisible = false
},
addNonStockItem() {
this.nonStockItems.push({
is_stock_item: false,
name: '',
spec: '',
unit: '',
quantity: 0,
req_type: '',
note: '',
})
},
delStockItem(index) {
this.stockItems.splice(index, 1)
},
delNonStockItem(index) {
this.nonStockItems.splice(index, 1)
},
validate() {
if (!this.formData.req_date) {
this.$message.warning('请选择填报时间')
return false
}
const allItems = [...this.stockItems, ...this.nonStockItems]
if (allItems.length === 0) {
this.$message.warning('请至少添加一项领用物品')
return false
}
for (let i = 0; i < this.stockItems.length; i++) {
const row = this.stockItems[i]
if (!row.quantity || Number(row.quantity) <= 0) {
this.$message.warning(`库存物品第${i + 1}领用量必须大于0`)
return false
}
if (Number(row.quantity) > Number(row.stock_quantity)) {
this.$message.warning(`库存物品第${i + 1}行:领用量(${row.quantity})超过库存量(${row.stock_quantity})`)
return false
}
}
for (let i = 0; i < this.nonStockItems.length; i++) {
const row = this.nonStockItems[i]
if (!row.name) {
this.$message.warning(`非清单物品第${i + 1}行:请填写物资名称`)
return false
}
if (!row.quantity || Number(row.quantity) <= 0) {
this.$message.warning(`非清单物品第${i + 1}领用量必须大于0`)
return false
}
}
return true
},
buildPayload() {
const items = []
this.stockItems.forEach(row => {
items.push({
is_stock_item: true,
stock: row.stock_id,
req_type: row.req_type,
name: row.name,
spec: row.spec,
unit: row.unit,
quantity: row.quantity,
note: row.note,
})
})
this.nonStockItems.forEach(row => {
items.push({
is_stock_item: false,
req_type: row.req_type,
name: row.name,
spec: row.spec,
unit: row.unit,
quantity: row.quantity,
note: row.note,
})
})
return {
req_date: this.formData.req_date,
collector: this.formData.collector,
note: this.formData.note,
items: items
}
},
async handleSubmit() {
if (!this.validate()) return
this.saveLoading = true
try {
if (this.localMode === 'add') {
await this.$API.mpr.materialRequisition.create.req(this.buildPayload())
this.$message.success('提交成功')
} else if (this.localMode === 'edit') {
await this.$API.mpr.materialRequisition.update.req(this.formData.id, this.buildPayload())
this.$message.success('更新并提交成功')
}
this.$emit('success')
} catch (error) {
const msg = error?.response?.data?.detail || error?.response?.data?.message || '提交失败'
this.$message.error(msg)
} finally {
this.saveLoading = false
}
},
handleDel() {
this.$confirm('确定删除该领用单吗?', '提示', { type: 'warning' })
.then(() => {
this.$API.mpr.materialRequisition.delete.req(this.formData.id).then(() => {
this.$message.success('删除成功')
this.$emit('success')
})
})
}
}
}
</script>

View File

@ -0,0 +1,123 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" v-auth="'requisition.create'">新增申购</el-button>
</div>
<div class="right-panel">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 260px; margin-right: 10px;"
@change="handleDateChange"
></el-date-picker>
<el-input
v-model="query.search"
placeholder="编号/申购人"
clearable
style="width: 200px;"
@keyup.enter="handleQuery"
></el-input>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="$API.mpr.requisition.list"
row-key="id"
stripe
:query="query"
@row-click="rowClick"
>
<el-table-column type="index" width="50" />
<el-table-column label="编号" prop="number" width="200" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<template v-if="scope.row.ticket_">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
<el-tag v-else type="info">未提交</el-tag>
</template>
</el-table-column>
<el-table-column label="申购部门" prop="belong_dept_name" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="申购人" prop="create_by_name" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="联系电话" prop="phone" width="130" show-overflow-tooltip></el-table-column>
<el-table-column label="申购日期" prop="req_date" width="120" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="合计金额" prop="total_amount" width="120" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="备注" prop="note" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" fixed="right" align="center" width="100">
<template #default="scope">
<el-button link type="danger" @click.stop="handleDel(scope.row)" v-auth="'requisition.delete'">删除</el-button>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="物资申购单" v-model="drawerVisible" :size="'85%'" destroy-on-close>
<requisition-form :mode="mode" :t_id="t_id" @success="handleSuccess"></requisition-form>
</el-drawer>
</template>
<script setup>
import { ref } from 'vue'
import API from '@/api'
import requisitionForm from './requisition_form.vue'
import { actStateEnum } from "@/utils/enum.js"
const table = ref(null)
const query = ref({})
const dateRange = ref(null)
const drawerVisible = ref(false)
const mode = ref('add')
const t_id = ref(null)
const handleAdd = () => {
mode.value = 'add'
t_id.value = null
drawerVisible.value = true
}
const rowClick = (row) => {
t_id.value = row.id
mode.value = 'show'
drawerVisible.value = true
}
const handleQuery = () => {
table.value.refresh()
}
const handleDateChange = (val) => {
if (val) {
query.value.req_date_after = val[0]
query.value.req_date_before = val[1]
} else {
delete query.value.req_date_after
delete query.value.req_date_before
}
handleQuery()
}
const handleDel = (row) => {
ElMessageBox.confirm('确定删除该申购单吗?', '提示', { type: 'warning' })
.then(() => {
API.mpr.requisition.delete.req(row.id).then(() => {
ElMessage.success('删除成功')
table.value.refresh()
})
})
}
const handleSuccess = () => {
drawerVisible.value = false
table.value.refresh()
}
</script>

View File

@ -0,0 +1,279 @@
<template>
<el-container>
<el-main class="nopadding">
<div style="padding: 20px;">
<el-descriptions title="物资申购单" :column="3" border>
<el-descriptions-item label="编号">{{ formData.number || '自动生成' }}</el-descriptions-item>
<el-descriptions-item label="申购部门">{{ formData.belong_dept_name || currentUser.belong_dept_name }}</el-descriptions-item>
<el-descriptions-item label="申购人">{{ formData.create_by_name || currentUser.name }}</el-descriptions-item>
<el-descriptions-item label="联系电话">
<el-input v-if="isEditable" v-model="formData.phone" placeholder="联系电话" style="width: 200px;" />
<span v-else>{{ formData.phone }}</span>
</el-descriptions-item>
<el-descriptions-item label="申购日期">
<el-date-picker
v-if="isEditable"
v-model="formData.req_date"
type="date"
placeholder="申购日期"
value-format="YYYY-MM-DD"
style="width: 200px;"
/>
<span v-else>{{ formData.req_date }}</span>
</el-descriptions-item>
<el-descriptions-item label="合计金额">
<span style="font-weight: bold; color: #e6a23c;">¥ {{ calcTotalAmount }}</span>
</el-descriptions-item>
<el-descriptions-item label="备注" :span="3">
<el-input v-if="isEditable" v-model="formData.note" type="textarea" :rows="2" placeholder="备注" />
<span v-else>{{ formData.note }}</span>
</el-descriptions-item>
</el-descriptions>
<div style="margin-top: 20px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h4 style="margin: 0;">申购明细</h4>
<el-button v-if="isEditable" type="primary" size="small" icon="el-icon-plus" @click="addItem">添加物品</el-button>
</div>
<el-table :data="items" border stripe style="width: 100%">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="物品名称" min-width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.item_name" placeholder="物品名称" />
<span v-else>{{ scope.row.item_name }}</span>
</template>
</el-table-column>
<el-table-column label="规格及型号" min-width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.spec" placeholder="规格型号" />
<span v-else>{{ scope.row.spec }}</span>
</template>
</el-table-column>
<el-table-column label="单位" width="80">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.unit" placeholder="单位" />
<span v-else>{{ scope.row.unit }}</span>
</template>
</el-table-column>
<el-table-column label="申购数量" width="120">
<template #default="scope">
<el-input-number v-if="isEditable" v-model="scope.row.req_quantity" :min="0" :precision="3" size="small" controls-position="right" />
<span v-else>{{ scope.row.req_quantity }}</span>
</template>
</el-table-column>
<el-table-column label="现库存量" width="120">
<template #default="scope">
<el-input-number v-if="isEditable" v-model="scope.row.current_stock" :min="0" :precision="3" size="small" controls-position="right" />
<span v-else>{{ scope.row.current_stock }}</span>
</template>
</el-table-column>
<el-table-column label="需用日期" width="160">
<template #default="scope">
<el-date-picker v-if="isEditable" v-model="scope.row.need_date" type="date" placeholder="需用日期" value-format="YYYY-MM-DD" size="small" />
<span v-else>{{ scope.row.need_date }}</span>
</template>
</el-table-column>
<el-table-column label="需采购数量" width="130">
<template #default="scope">
<el-input-number v-if="isEditable" v-model="scope.row.purchase_quantity" :min="0" :precision="3" size="small" controls-position="right" />
<span v-else>{{ scope.row.purchase_quantity }}</span>
</template>
</el-table-column>
<el-table-column label="单价" width="120">
<template #default="scope">
<el-input-number v-if="isEditable" v-model="scope.row.unit_price" :min="0" :precision="2" size="small" controls-position="right" />
<span v-else>{{ scope.row.unit_price }}</span>
</template>
</el-table-column>
<el-table-column label="总价" width="110">
<template #default="scope">
<span style="font-weight: bold;">{{ calcRowTotal(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="备注" min-width="100">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.note" placeholder="备注" />
<span v-else>{{ scope.row.note }}</span>
</template>
</el-table-column>
<el-table-column v-if="isEditable" label="操作" width="80" align="center" fixed="right">
<template #default="scope">
<el-button link type="danger" @click="delItem(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div style="text-align: right; margin-top: 10px; font-size: 16px; font-weight: bold;">
合计¥ {{ calcTotalAmount }}
</div>
</div>
</div>
<el-footer style="padding: 10px 20px; text-align: left;">
<el-button type="danger"
v-if="localMode === 'edit'"
style="margin-right: 4px;"
@click="handleDel"
:loading="saveLoading"
>删除</el-button>
<el-button
v-if="isEditable"
type="primary"
style="margin-right: 4px;"
@click="handleSubmit"
:loading="saveLoading"
>提交审批</el-button>
<ticketd_b
v-if="formData.ticket_ && localMode === 'show'"
:t_id="formData.id"
:ticket_="formData.ticket_"
:ticket_data="ticket_data"
@success="$emit('success')"
ref="ticketd_b"
></ticketd_b>
</el-footer>
</el-main>
<el-aside width="20%" v-if="formData.ticket_">
<ticketd :ticket_="formData.ticket_" @success="$emit('success')"></ticketd>
</el-aside>
</el-container>
</template>
<script>
import ticketd_b from "@/views/wf/ticketd_b.vue"
import ticketd from '@/views/wf/ticketd.vue'
export default {
name: 'RequisitionForm',
components: { ticketd_b, ticketd },
props: {
mode: { type: String, default: 'show' },
t_id: { type: String, default: "" }
},
emits: ['success'],
data() {
return {
formData: {},
items: [],
localMode: this.mode,
saveLoading: false,
ticket_data: {},
currentUser: this.$TOOL.data.get("USER_INFO") || {}
}
},
computed: {
isEditable() {
return this.localMode === 'add' || this.localMode === 'edit'
},
calcTotalAmount() {
let total = 0
this.items.forEach(row => {
total += Number(this.calcRowTotal(row))
})
return total.toFixed(2)
}
},
mounted() {
if (this.t_id) {
this.loadData()
} else {
this.localMode = 'add'
}
},
methods: {
calcRowTotal(row) {
return (Number(row.purchase_quantity || 0) * Number(row.unit_price || 0)).toFixed(2)
},
async loadData() {
try {
let res = await this.$API.mpr.requisition.item.req(this.t_id)
this.formData = res
this.items = res.items_ || []
if (res.ticket_ && res.ticket_.state_.type === 1 && res.create_by === this.currentUser.id) {
this.localMode = 'edit'
}
} catch (error) {
this.$message.error('加载失败')
}
},
addItem() {
this.items.push({
item_name: '',
spec: '',
unit: '',
req_quantity: 0,
current_stock: 0,
need_date: null,
purchase_quantity: 0,
unit_price: 0,
total_price: 0,
note: ''
})
},
delItem(index) {
this.items.splice(index, 1)
},
validate() {
if (!this.formData.req_date) {
this.$message.warning('请选择申购日期')
return false
}
if (this.items.length === 0) {
this.$message.warning('请至少添加一项申购物品')
return false
}
for (let i = 0; i < this.items.length; i++) {
if (!this.items[i].item_name) {
this.$message.warning(`${i + 1}行:请填写物品名称`)
return false
}
}
return true
},
buildPayload() {
return {
phone: this.formData.phone,
req_date: this.formData.req_date,
note: this.formData.note,
items: this.items.map(row => ({
item_name: row.item_name,
spec: row.spec,
unit: row.unit,
req_quantity: row.req_quantity,
current_stock: row.current_stock,
need_date: row.need_date,
purchase_quantity: row.purchase_quantity,
unit_price: row.unit_price,
note: row.note
}))
}
},
async handleSubmit() {
if (!this.validate()) return
this.saveLoading = true
try {
if (this.localMode === 'add') {
await this.$API.mpr.requisition.create.req(this.buildPayload())
this.$message.success('提交成功')
} else if (this.localMode === 'edit') {
await this.$API.mpr.requisition.update.req(this.formData.id, this.buildPayload())
this.$message.success('更新并提交成功')
}
this.$emit('success')
} catch (error) {
this.$message.error('提交失败')
} finally {
this.saveLoading = false
}
},
handleDel() {
this.$confirm('确定删除该申购单吗?', '提示', { type: 'warning' })
.then(() => {
this.$API.mpr.requisition.delete.req(this.formData.id).then(() => {
this.$message.success('删除成功')
this.$emit('success')
})
})
}
}
}
</script>

View File

@ -0,0 +1,133 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" v-auth="'warehouse_entry.create'">新增入库单</el-button>
</div>
<div class="right-panel">
<el-select v-model="query.warehouse" placeholder="仓库" clearable style="width: 150px; margin-right: 10px;" @change="handleQuery">
<el-option v-for="w in warehouseOptions" :key="w.id" :label="w.name" :value="w.id"></el-option>
</el-select>
<el-select v-model="query.entry_type" placeholder="入库类型" clearable style="width: 150px; margin-right: 10px;" @change="handleQuery">
<el-option label="原材料正常入库" value="raw_normal"></el-option>
<el-option label="原材料暂估入库" value="raw_estimated"></el-option>
<el-option label="产品入库" value="product"></el-option>
<el-option label="其他" value="other"></el-option>
</el-select>
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 260px; margin-right: 10px;"
@change="handleDateChange"
></el-date-picker>
<el-input v-model="query.search" placeholder="编号/操作人" clearable style="width: 180px;" @keyup.enter="handleQuery"></el-input>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="$API.mpr.warehouseEntry.list"
row-key="id"
stripe
:query="query"
@row-click="rowClick"
>
<el-table-column type="index" width="50" />
<el-table-column label="编号" prop="number" width="200" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
<template #default="scope">
<template v-if="scope.row.ticket_">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
</el-tag>
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
</template>
<el-tag v-else type="info">未提交</el-tag>
</template>
</el-table-column>
<el-table-column label="仓库" prop="warehouse_name" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="入库类型" prop="entry_type_display" width="140" show-overflow-tooltip></el-table-column>
<el-table-column label="入库方式" prop="entry_method_display" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="入库日期" prop="entry_date" width="120" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="操作人" prop="create_by_name" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="合计金额" prop="total_amount" width="120" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="备注" prop="note" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" fixed="right" align="center" width="100">
<template #default="scope">
<el-button link type="danger" @click.stop="handleDel(scope.row)" v-auth="'warehouse_entry.delete'">删除</el-button>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="仓库入库单" v-model="drawerVisible" :size="'85%'" destroy-on-close>
<entry-form :mode="mode" :t_id="t_id" @success="handleSuccess"></entry-form>
</el-drawer>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import API from '@/api'
import entryForm from './warehouse_entry_form.vue'
import { actStateEnum } from "@/utils/enum.js"
const table = ref(null)
const query = ref({})
const dateRange = ref(null)
const drawerVisible = ref(false)
const mode = ref('add')
const t_id = ref(null)
const warehouseOptions = ref([])
onMounted(async () => {
let res = await API.inm.warehouse.list.req({ page: 0 })
warehouseOptions.value = res
})
const handleAdd = () => {
mode.value = 'add'
t_id.value = null
drawerVisible.value = true
}
const rowClick = (row) => {
t_id.value = row.id
mode.value = 'show'
drawerVisible.value = true
}
const handleQuery = () => {
table.value.refresh()
}
const handleDateChange = (val) => {
if (val) {
query.value.entry_date_after = val[0]
query.value.entry_date_before = val[1]
} else {
delete query.value.entry_date_after
delete query.value.entry_date_before
}
handleQuery()
}
const handleDel = (row) => {
ElMessageBox.confirm('确定删除该入库单吗?', '提示', { type: 'warning' })
.then(() => {
API.mpr.warehouseEntry.delete.req(row.id).then(() => {
ElMessage.success('删除成功')
table.value.refresh()
})
})
}
const handleSuccess = () => {
drawerVisible.value = false
table.value.refresh()
}
</script>

View File

@ -0,0 +1,304 @@
<template>
<el-container>
<el-main class="nopadding">
<div style="padding: 20px;">
<el-descriptions title="仓库入库单" :column="3" border>
<el-descriptions-item label="编号">{{ formData.number || '自动生成' }}</el-descriptions-item>
<el-descriptions-item label="仓库名称">
<el-select v-if="isEditable" v-model="formData.warehouse" placeholder="选择仓库" style="width: 200px;">
<el-option v-for="w in warehouseOptions" :key="w.id" :label="w.name" :value="w.id"></el-option>
</el-select>
<span v-else>{{ formData.warehouse_name }}</span>
</el-descriptions-item>
<el-descriptions-item label="入库日期">
<el-date-picker
v-if="isEditable"
v-model="formData.entry_date"
type="date"
placeholder="入库日期"
value-format="YYYY-MM-DD"
style="width: 200px;"
/>
<span v-else>{{ formData.entry_date }}</span>
</el-descriptions-item>
<el-descriptions-item label="入库类型">
<el-select v-if="isEditable" v-model="formData.entry_type" placeholder="入库类型" style="width: 200px;">
<el-option label="原材料正常入库" value="raw_normal"></el-option>
<el-option label="原材料暂估入库" value="raw_estimated"></el-option>
<el-option label="产品入库" value="product"></el-option>
<el-option label="其他" value="other"></el-option>
</el-select>
<span v-else>{{ formData.entry_type_display }}</span>
</el-descriptions-item>
<el-descriptions-item label="入库方式">
<el-select v-if="isEditable" v-model="formData.entry_method" placeholder="入库方式" style="width: 200px;">
<el-option label="采购" value="purchase"></el-option>
<el-option label="自制" value="self_made"></el-option>
<el-option label="其他" value="other"></el-option>
</el-select>
<span v-else>{{ formData.entry_method_display }}</span>
</el-descriptions-item>
<el-descriptions-item label="合计金额">
<span style="font-weight: bold; color: #e6a23c;">¥ {{ calcTotalAmount }}</span>
</el-descriptions-item>
<el-descriptions-item label="操作人">{{ formData.create_by_name || currentUser.name }}</el-descriptions-item>
<el-descriptions-item label="所属部门">{{ formData.belong_dept_name || currentUser.belong_dept_name }}</el-descriptions-item>
<el-descriptions-item label="备注">
<el-input v-if="isEditable" v-model="formData.note" type="textarea" :rows="1" placeholder="备注" />
<span v-else>{{ formData.note }}</span>
</el-descriptions-item>
</el-descriptions>
<div style="margin-top: 20px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h4 style="margin: 0;">入库明细</h4>
<el-button v-if="isEditable" type="primary" size="small" icon="el-icon-plus" @click="addItem">添加物品</el-button>
</div>
<el-table :data="items" border stripe style="width: 100%">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="名称" min-width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.name" placeholder="名称" />
<span v-else>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="规格" width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.spec" placeholder="规格" />
<span v-else>{{ scope.row.spec }}</span>
</template>
</el-table-column>
<el-table-column label="单位" width="80">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.unit" placeholder="单位" />
<span v-else>{{ scope.row.unit }}</span>
</template>
</el-table-column>
<el-table-column label="数量" width="120">
<template #default="scope">
<el-input-number v-if="isEditable" v-model="scope.row.quantity" :min="0" :precision="3" size="small" controls-position="right" />
<span v-else>{{ scope.row.quantity }}</span>
</template>
</el-table-column>
<el-table-column label="单价" width="120">
<template #default="scope">
<el-input-number v-if="isEditable" v-model="scope.row.unit_price" :min="0" :precision="2" size="small" controls-position="right" />
<span v-else>{{ scope.row.unit_price }}</span>
</template>
</el-table-column>
<el-table-column label="金额" width="110">
<template #default="scope">
<span style="font-weight: bold;">{{ calcRowAmount(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="供应商名称" min-width="120">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.supplier_name" placeholder="供应商" />
<span v-else>{{ scope.row.supplier_name }}</span>
</template>
</el-table-column>
<el-table-column label="账单是否收到" width="120" align="center">
<template #default="scope">
<el-checkbox v-if="isEditable" v-model="scope.row.invoice_received" />
<el-tag v-else :type="scope.row.invoice_received ? 'success' : 'danger'" size="small">
{{ scope.row.invoice_received ? '已收到' : '未收到' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" min-width="100">
<template #default="scope">
<el-input v-if="isEditable" v-model="scope.row.note" placeholder="备注" />
<span v-else>{{ scope.row.note }}</span>
</template>
</el-table-column>
<el-table-column v-if="isEditable" label="操作" width="80" align="center" fixed="right">
<template #default="scope">
<el-button link type="danger" @click="delItem(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div style="text-align: right; margin-top: 10px; font-size: 16px; font-weight: bold;">
合计¥ {{ calcTotalAmount }}
</div>
</div>
</div>
<el-footer style="padding: 10px 20px; text-align: left;">
<el-button type="danger"
v-if="localMode === 'edit'"
style="margin-right: 4px;"
@click="handleDel"
:loading="saveLoading"
>删除</el-button>
<el-button
v-if="isEditable"
type="primary"
style="margin-right: 4px;"
@click="handleSubmit"
:loading="saveLoading"
>提交审批</el-button>
<ticketd_b
v-if="formData.ticket_ && localMode === 'show'"
:t_id="formData.id"
:ticket_="formData.ticket_"
:ticket_data="ticket_data"
@success="$emit('success')"
ref="ticketd_b"
></ticketd_b>
</el-footer>
</el-main>
<el-aside width="20%" v-if="formData.ticket_">
<ticketd :ticket_="formData.ticket_" @success="$emit('success')"></ticketd>
</el-aside>
</el-container>
</template>
<script>
import ticketd_b from "@/views/wf/ticketd_b.vue"
import ticketd from '@/views/wf/ticketd.vue'
export default {
name: 'WarehouseEntryForm',
components: { ticketd_b, ticketd },
props: {
mode: { type: String, default: 'show' },
t_id: { type: String, default: "" }
},
emits: ['success'],
data() {
return {
formData: {
entry_type: 'raw_normal',
entry_method: 'purchase',
},
items: [],
localMode: this.mode,
saveLoading: false,
ticket_data: {},
currentUser: this.$TOOL.data.get("USER_INFO") || {},
warehouseOptions: []
}
},
computed: {
isEditable() {
return this.localMode === 'add' || this.localMode === 'edit'
},
calcTotalAmount() {
let total = 0
this.items.forEach(row => {
total += Number(this.calcRowAmount(row))
})
return total.toFixed(2)
}
},
async mounted() {
let res = await this.$API.inm.warehouse.list.req({ page: 0 })
this.warehouseOptions = res
if (this.t_id) {
this.loadData()
} else {
this.localMode = 'add'
}
},
methods: {
calcRowAmount(row) {
return (Number(row.quantity || 0) * Number(row.unit_price || 0)).toFixed(2)
},
async loadData() {
try {
let res = await this.$API.mpr.warehouseEntry.item.req(this.t_id)
this.formData = res
this.items = res.items_ || []
if (res.ticket_ && res.ticket_.state_.type === 1 && res.create_by === this.currentUser.id) {
this.localMode = 'edit'
}
} catch (error) {
this.$message.error('加载失败')
}
},
addItem() {
this.items.push({
name: '',
spec: '',
unit: '',
quantity: 0,
unit_price: 0,
amount: 0,
supplier_name: '',
invoice_received: false,
note: ''
})
},
delItem(index) {
this.items.splice(index, 1)
},
validate() {
if (!this.formData.warehouse) {
this.$message.warning('请选择仓库')
return false
}
if (!this.formData.entry_date) {
this.$message.warning('请选择入库日期')
return false
}
if (this.items.length === 0) {
this.$message.warning('请至少添加一项入库物品')
return false
}
for (let i = 0; i < this.items.length; i++) {
if (!this.items[i].name) {
this.$message.warning(`${i + 1}行:请填写名称`)
return false
}
}
return true
},
buildPayload() {
return {
warehouse: this.formData.warehouse,
entry_date: this.formData.entry_date,
entry_type: this.formData.entry_type,
entry_method: this.formData.entry_method,
note: this.formData.note,
items: this.items.map(row => ({
name: row.name,
spec: row.spec,
unit: row.unit,
quantity: row.quantity,
unit_price: row.unit_price,
supplier_name: row.supplier_name,
invoice_received: row.invoice_received,
note: row.note
}))
}
},
async handleSubmit() {
if (!this.validate()) return
this.saveLoading = true
try {
if (this.localMode === 'add') {
await this.$API.mpr.warehouseEntry.create.req(this.buildPayload())
this.$message.success('提交成功')
} else if (this.localMode === 'edit') {
await this.$API.mpr.warehouseEntry.update.req(this.formData.id, this.buildPayload())
this.$message.success('更新并提交成功')
}
this.$emit('success')
} catch (error) {
this.$message.error('提交失败')
} finally {
this.saveLoading = false
}
},
handleDel() {
this.$confirm('确定删除该入库单吗?', '提示', { type: 'warning' })
.then(() => {
this.$API.mpr.warehouseEntry.delete.req(this.formData.id).then(() => {
this.$message.success('删除成功')
this.$emit('success')
})
})
}
}
}
</script>

View File

@ -0,0 +1,112 @@
<template>
<el-container>
<el-header>
<div class="left-panel"></div>
<div class="right-panel">
<el-select v-model="query.warehouse" placeholder="仓库" clearable style="width: 150px; margin-right: 10px;" @change="handleQuery">
<el-option v-for="w in warehouseOptions" :key="w.id" :label="w.name" :value="w.id"></el-option>
</el-select>
<el-select v-model="query.entry_type" placeholder="入库类型" clearable style="width: 150px; margin-right: 10px;" @change="handleQuery">
<el-option label="原材料正常入库" value="raw_normal"></el-option>
<el-option label="原材料暂估入库" value="raw_estimated"></el-option>
<el-option label="产品入库" value="product"></el-option>
<el-option label="其他" value="other"></el-option>
</el-select>
<el-select v-model="query.status" placeholder="物料状态" clearable style="width: 120px; margin-right: 10px;" @change="handleQuery">
<el-option label="闲置" value="idle"></el-option>
<el-option label="领用中" value="in_requisition"></el-option>
<el-option label="已领用" value="requisitioned"></el-option>
</el-select>
<el-select v-model="query.invoice_received" placeholder="账单状态" clearable style="width: 120px; margin-right: 10px;" @change="handleQuery">
<el-option label="已收到" :value="true"></el-option>
<el-option label="未收到" :value="false"></el-option>
</el-select>
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 260px; margin-right: 10px;"
@change="handleDateChange"
></el-date-picker>
<el-input v-model="query.search" placeholder="名称/规格/供应商/单号" clearable style="width: 220px;" @keyup.enter="handleQuery"></el-input>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="$API.mpr.warehouseStock.list"
row-key="id"
stripe
:query="query"
>
<el-table-column type="index" width="50" />
<el-table-column label="仓库" prop="warehouse_name" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="入库单号" prop="entry_number" width="200" show-overflow-tooltip></el-table-column>
<el-table-column label="入库日期" prop="entry_date" width="110" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="入库类型" prop="entry_type_display" width="140" show-overflow-tooltip></el-table-column>
<el-table-column label="入库方式" prop="entry_method_display" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="名称" prop="name" min-width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="规格" prop="spec" width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="单位" prop="unit" width="70" show-overflow-tooltip></el-table-column>
<el-table-column label="数量" prop="quantity" width="100" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="单价" prop="unit_price" width="100" show-overflow-tooltip></el-table-column>
<el-table-column label="金额" prop="amount" width="110" sortable show-overflow-tooltip>
<template #default="scope">
<span style="font-weight: bold;">{{ scope.row.amount }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="100" align="center">
<template #default="scope">
<el-tag v-if="Number(scope.row.quantity) <= 0" type="info" size="small">已领完</el-tag>
<el-tag v-else-if="scope.row.status === 'idle'" type="success" size="small">闲置</el-tag>
<el-tag v-else-if="scope.row.status === 'in_requisition'" type="warning" size="small">领用中</el-tag>
<el-tag v-else-if="scope.row.status === 'requisitioned'" type="danger" size="small">已领用</el-tag>
<el-tag v-else type="info" size="small">{{ scope.row.status_display }}</el-tag>
</template>
</el-table-column>
<el-table-column label="供应商" prop="supplier_name" width="140" show-overflow-tooltip></el-table-column>
<el-table-column label="账单" width="90" align="center">
<template #default="scope">
<el-tag :type="scope.row.invoice_received ? 'success' : 'danger'" size="small">
{{ scope.row.invoice_received ? '已收到' : '未收到' }}
</el-tag>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import API from '@/api'
const table = ref(null)
const query = ref({})
const dateRange = ref(null)
const warehouseOptions = ref([])
onMounted(async () => {
let res = await API.inm.warehouse.list.req({ page: 0 })
warehouseOptions.value = res
})
const handleQuery = () => {
table.value.refresh()
}
const handleDateChange = (val) => {
if (val) {
query.value.entry_date_after = val[0]
query.value.entry_date_before = val[1]
} else {
delete query.value.entry_date_after
delete query.value.entry_date_before
}
handleQuery()
}
</script>

View File

@ -7,6 +7,7 @@
icon="el-icon-plus"
@click="handleAdd"
></el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="借阅台账" />
</div>
<div class="right-panel">
<el-input
@ -125,9 +126,10 @@
<script>
import borrowlForm from "./borrowfile_form.vue";
import ExportBtn from "./exportBtn.vue";
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
export default {
components: { borrowlForm },
components: { borrowlForm, ExportBtn },
name: "index",
data() {
return {
@ -137,6 +139,17 @@ export default {
limitedVisible: false,
mode: "show",
t_id: null,
exportCols: [
{ header: "档案名称", key: "file_name", wch: 20 },
{ header: "申请部门", key: "belong_dept_name", wch: 15 },
{ header: "申请人", key: "create_by_name", wch: 12 },
{ header: "申请人电话", key: "contacts", wch: 15 },
{ header: "借阅时间", key: "borrow_date", wch: 15 },
{ header: "借阅数量", key: "count", wch: 10 },
{ header: "用途", key: "remark", wch: 20 },
{ header: "归还时间", key: "return_date", wch: 15 },
{ header: "审批状态", key: "_act_state_text", wch: 12 },
],
};
},
methods: {

View File

@ -0,0 +1,83 @@
<template>
<el-dropdown trigger="click" @command="handleExport">
<el-button type="success" icon="el-icon-download">导出</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="page">导出本页数据</el-dropdown-item>
<el-dropdown-item command="all">导出全部数据</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script>
import { dataToExcel } from "@/utils/exportExcel";
const ACT_STATE_MAP = { 0: "草稿中", 1: "进行中", 2: "被退回", 3: "被撤回", 4: "已完成", 5: "已关闭" };
export default {
name: "OfmExportBtn",
props: {
getTableRef: { type: Function, required: true },
columns: { type: Array, required: true },
fileName: { type: String, default: "台账数据" },
},
methods: {
// getNestedValue null
flattenData(list) {
if (!Array.isArray(list)) return [];
return list.map(row => {
const flat = { ...row };
//
const actState = row.ticket_?.act_state;
flat._act_state_text = ACT_STATE_MAP[actState] ?? "";
flat._state_name = row.ticket_?.state_?.name ?? "";
// /JSONField
for (const key of Object.keys(flat)) {
if (Array.isArray(flat[key])) {
flat[key] = flat[key].join("、");
}
}
//
if (row.is_lending !== undefined) flat._is_lending_text = row.is_lending ? "是" : "否";
if (row.is_city !== undefined) flat._is_city_text = row.is_city ? "是" : "否";
if (row.is_change !== undefined) flat._is_change_text = row.is_change ? "是" : "否";
if (row.is_promotion !== undefined) flat._is_promotion_text = row.is_promotion ? "是" : "否";
return flat;
});
},
// columns /type_dict key
getFlatColumns() {
return this.columns.map(col => {
if (col.key === "ticket_.act_state") return { ...col, key: "_act_state_text", type_dict: undefined };
if (col.key === "is_lending") return { ...col, key: "_is_lending_text", type_dict: undefined };
if (col.key === "is_city") return { ...col, key: "_is_city_text", type_dict: undefined };
return col;
});
},
doExport(data) {
const flatData = this.flattenData(data);
const flatCols = this.getFlatColumns();
dataToExcel(flatCols, flatData, this.fileName);
},
handleExport(command) {
const table = this.getTableRef();
if (!table) return;
if (command === "page") {
this.doExport(table.tableData);
} else if (command === "all") {
const query = Object.assign({}, table.query, table.tableParams, { page: 0 });
const loading = this.$loading({ lock: true, text: "数据导出中...", background: "rgba(0,0,0,0.1)" });
table.apiObj.req(query).then((res) => {
loading.close();
this.doExport(res);
}).catch((err) => {
loading.close();
console.error("导出失败", err);
this.$message.error("导出失败");
});
}
},
},
};
</script>

View File

@ -7,6 +7,7 @@
icon="el-icon-plus"
@click="handleAdd"
></el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="会议室预约台账" />
</div>
<div class="right-panel">
<el-date-picker
@ -79,10 +80,11 @@
<script>
import bookingDialog from "./mroombooking_form.vue";
import ExportBtn from "./exportBtn.vue";
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
export default {
name: "index",
components: { bookingDialog },
components: { bookingDialog, ExportBtn },
data() {
return {
actStateEnum, interveneTypeEnum,
@ -97,7 +99,14 @@ export default {
edit: "编辑会议预定",
show: "查看会议预定",
},
mRoomList: []
mRoomList: [],
exportCols: [
{ header: "标题", key: "title", wch: 20 },
{ header: "会议室名称", key: "mroom_name", wch: 15 },
{ header: "预约日期", key: "mdate", wch: 15 },
{ header: "预约时间", key: "time_ranges", wch: 25 },
{ header: "审批状态", key: "_act_state_text", wch: 12 },
],
};
},
mounted() {
@ -135,7 +144,7 @@ export default {
await this.$API.ofm.mroombooking.checkDelete.req(id);
this.$message.success("删除成功");
this.$refs.table.refresh();
} catch (error) {
} catch (error) { // eslint-disable-line no-empty
}
},
//

View File

@ -7,6 +7,7 @@
icon="el-icon-plus"
@click="handleAdd"
></el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="宣传报道台账" />
</div>
</el-header>
<el-main class="nopadding">
@ -76,7 +77,21 @@
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" align="center" width="250">
<el-table-column
label="终版文件"
min-width="120"
align="center">
<template #default="scope">
<el-link
v-if="scope.row.final_file"
type="primary"
:href="scope.row.final_file"
target="_blank"
>查看文件</el-link>
<span v-else style="color:#999">未上传</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" align="center" width="300">
<template #default="scope">
<el-button
link
@ -85,6 +100,14 @@
@click="publicityShow(scope.row)"
>详情
</el-button>
<el-button
v-if="scope.row.ticket_?.state_?.name === '档案管理员审批'"
link
size="small"
type="success"
@click="handleUploadFinal(scope.row)"
>终版上传
</el-button>
<el-popconfirm
title="确定删除吗?"
@confirm="handleDel(scope.row)"
@ -119,12 +142,30 @@
</div>
</div>
</el-drawer>
<el-dialog
v-model="uploadVisible"
title="终版文件上传"
width="500px"
:destroy-on-close="true">
<sc-upload-file
v-model="finalFilePath"
:multiple="false"
:limit="1"
accept=".pdf,.doc,.docx,.jpg,.png,.jpeg">
<el-button type="primary" icon="el-icon-upload">选择文件</el-button>
</sc-upload-file>
<template #footer>
<el-button @click="uploadVisible = false">取消</el-button>
<el-button type="primary" :loading="uploadLoading" @click="submitFinalFile">确认上传</el-button>
</template>
</el-dialog>
</template>
<script>
import publicity from "./publicity_form.vue";
import ExportBtn from "./exportBtn.vue";
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
export default {
components: {publicity},
components: {publicity, ExportBtn},
name: "index",
data() {
return {
@ -134,6 +175,25 @@ export default {
limitedVisible: false,
mode: "show",
t_id: null,
uploadVisible: false,
uploadLoading: false,
finalFilePath: "",
uploadRowId: null,
exportCols: [
{ header: "记录编号", key: "number", wch: 15 },
{ header: "送审稿件标题", key: "title", wch: 20 },
{ header: "所有撰稿人", key: "participants", wch: 15 },
{ header: "所在部门", key: "belong_dept_name", wch: 15 },
{ header: "涉密等级", key: "level", wch: 12 },
{ header: "稿件内容涉及", key: "content", wch: 20 },
{ header: "宣传报道目的", key: "report_purpose", wch: 20 },
{ header: "宣传报道渠道", key: "channel", wch: 15 },
{ header: "第一撰稿人自审", key: "review", wch: 15 },
{ header: "部门负责人意见", key: "dept_opinion", wch: 15 },
{ header: "总经理意见", key: "dept_opinion_review", wch: 15 },
{ header: "终版文件", key: "final_file", wch: 25 },
{ header: "审批状态", key: "_act_state_text", wch: 12 },
],
};
},
@ -154,6 +214,31 @@ export default {
this.$refs.table.refresh();
this.$message.success("删除成功");
},
handleUploadFinal(row) {
this.uploadRowId = row.id;
this.finalFilePath = row.final_file || "";
this.uploadVisible = true;
},
async submitFinalFile() {
if (!this.finalFilePath) {
this.$message.warning("请先选择文件");
return;
}
this.uploadLoading = true;
try {
await this.$API.ofm.publicity.update.req(this.uploadRowId, {
final_file: this.finalFilePath,
});
this.$message.success("终版文件上传成功");
this.uploadVisible = false;
this.$refs.table.refresh();
} catch (e) {
console.error(e);
this.$message.error("上传失败");
} finally {
this.uploadLoading = false;
}
},
//
handleQuery() {
this.$refs.table.queryData(this.query);

View File

@ -76,28 +76,26 @@
<el-radio label="内容涉及国家秘密,申请按涉密渠道发布"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="所在部室定密意见" prop="dept_opinion" v-if="['部门领导审批', '总经理审批', '结束'].includes(addForm.ticket_?.state_?.name)">
<!-- 所在部室定密意见部门负责人审批可填综合管理部审批/总经理审批/档案管理员审批/结束只读 -->
<el-form-item label="所在部室定密意见" prop="dept_opinion" v-if="['部门负责人审批','综合管理部审批','总经理审批','档案管理员审批','结束'].includes(stateName)">
<div class="dept-opinion-wrap">
<div>
<el-radio-group v-model="addForm.dept_opinion" style="display: inline;" :disabled="addForm.ticket_?.state_?.name === '总经理审批'">
<el-radio-group v-model="addForm.dept_opinion" style="display: inline;" :disabled="stateName !== '部门负责人审批'">
<el-radio label="不符合定密要求">不符合定密要求</el-radio>
<el-radio label="同意内容为涉密事项">同意内容为涉密事项</el-radio>
</el-radio-group>
</div>
<!-- 根据选择显示不同的选项 -->
<div v-if="addForm.dept_opinion === '不符合定密要求'" style="margin-top: 8px;">
<span>应做</span>
<el-radio-group v-model="disposalMethod" style="display: inline; margin-left: 5px;" :disabled="addForm.ticket_?.state_?.name === '总经理审批'">
<el-radio-group v-model="disposalMethod" style="display: inline; margin-left: 5px;" :disabled="stateName !== '部门负责人审批'">
<el-radio label="公开">公开</el-radio>
<el-radio label="受控">受控</el-radio>
</el-radio-group>
<span>处理</span>
</div>
<div v-if="addForm.dept_opinion === '同意内容为涉密事项'" style="margin-top: 8px;">
<span>涉密等级为</span>
<el-radio-group v-model="addForm.secret_level" style="display: inline; margin-left: 5px;">
<el-radio-group v-model="addForm.secret_level" style="display: inline; margin-left: 5px;" :disabled="stateName !== '部门负责人审批'">
<el-radio label="机密">机密</el-radio>
<el-radio label="秘密">秘密</el-radio>
</el-radio-group>
@ -107,26 +105,44 @@
placeholder="请输入期限"
style="width: 200px; margin-left: 5px;"
size="small"
:disabled="stateName !== '部门负责人审批'"
/>
<span>请按总院管理要求做好保密管理</span>
</div>
</div>
</el-form-item>
<el-form-item label="综合管理部审查意见" prop="dept_opinion_review" v-if="['部门领导审批', '总经理审批', '结束'].includes(addForm.ticket_?.state_?.name)">
<el-radio-group v-model="addForm.dept_opinion_review" :disabled="addForm.ticket_?.state_?.name === '总经理审批'">
<!-- 综合管理部审查意见综合管理部审批可填总经理审批/档案管理员审批/结束只读 -->
<el-form-item label="综合管理部审查意见" prop="dept_opinion_review" v-if="['综合管理部审批','总经理审批','档案管理员审批','结束'].includes(stateName)">
<el-radio-group v-model="addForm.dept_opinion_review" :disabled="stateName !== '综合管理部审批'">
<el-radio label="内容不涉及国家秘密和商业秘密,同意公开"></el-radio>
<el-radio label="内容不涉及国家秘密、但涉及商业秘密,同意受控公开"></el-radio>
<el-radio label="内容涉及国家秘密,同意按涉密渠道发布"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="总经理审查意见" prop="publicity_opinion" v-if="['总经理审批', '结束'].includes(addForm.ticket_?.state_?.name)">
<el-radio-group v-model="addForm.publicity_opinion">
<!-- 总经理审查意见总经理审批可填档案管理员审批/结束只读 -->
<el-form-item label="总经理审查意见" prop="publicity_opinion" v-if="['总经理审批','档案管理员审批','结束'].includes(stateName)">
<el-radio-group v-model="addForm.publicity_opinion" :disabled="stateName !== '总经理审批'">
<el-radio label="同意公开宣传报道"></el-radio>
<el-radio label="同意受控报道"></el-radio>
<el-radio label="同意按涉密渠道宣传报道"></el-radio>
<el-radio label="不同意任何渠道的宣传报道"></el-radio>
</el-radio-group>
</el-form-item>
</el-form-item>
<!-- 终版文件档案管理员审批可上传结束可查看 -->
<el-form-item v-if="['档案管理员审批','结束'].includes(stateName)" :required="stateName === '档案管理员审批'" label="终版文件">
<div v-if="stateName === '档案管理员审批'">
<sc-upload-file
v-model="finalFileValue"
:multiple="false"
:limit="1"
accept=".pdf,.doc,.docx,.jpg,.png,.jpeg">
<el-button type="primary" icon="el-icon-upload">上传终版文件</el-button>
</sc-upload-file>
<el-link v-if="addForm.final_file" type="primary" :href="addForm.final_file" target="_blank" style="margin-top:8px">{{ addForm.final_file }}</el-link>
</div>
<el-link v-else-if="addForm.final_file" type="primary" :href="addForm.final_file" target="_blank">查看终版文件</el-link>
<span v-else style="color:#999">未上传</span>
</el-form-item>
</el-form>
<el-footer>
<ticketd_b
@ -219,9 +235,23 @@ export default {
'addForm.publicity_opinion'(val) {
this.ticket_data.publicity_opinion = val
},
'addForm.final_file'(val) {
this.ticket_data.final_file = val
},
deep:true
},
computed: {
stateName() {
return this.addForm.ticket_?.state_?.name || '';
},
finalFileValue: {
get() {
return this.addForm.final_file || "";
},
set(val) {
this.addForm.final_file = val;
}
},
disposalMethod: {
get() {
return this.addForm.disposal_method || '';
@ -234,14 +264,18 @@ export default {
methods: {
async submit_b_func() {
let that = this;
if (that.stateName === '档案管理员审批' && !that.addForm.final_file) {
that.$message.warning("请先上传终版文件");
throw new Error("终版文件必填");
}
if (that.localMode === "add") {
let res = await that.$API.ofm.publicity.create.req(that.addForm);
that.addForm.id = res.id;
} else if (that.localMode === "edit"){
} else {
await that.$API.ofm.publicity.update.req(
that.addForm.id,
that.addForm
);
);
}
},
getTid (){

View File

@ -7,6 +7,7 @@
icon="el-icon-plus"
@click="handleAdd"
>新增</el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="用印申请台账" />
</div>
<div class="right-panel">
<el-input
@ -80,6 +81,15 @@
<span v-else></span>
</template>
</el-table-column>
<el-table-column
label="终版文件"
min-width="80"
align="center">
<template #default="scope">
<el-link v-if="scope.row.final_file" type="primary" :href="scope.row.final_file" target="_blank">查看文件</el-link>
<span v-else style="color:#999">未上传</span>
</template>
</el-table-column>
<el-table-column label="审批信息" width="200">
<template #default="scope">
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
@ -138,9 +148,10 @@
</template>
<script>
import SealForm from "./seal_form.vue";
import ExportBtn from "./exportBtn.vue";
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
export default {
components: { SealForm},
components: { SealForm, ExportBtn},
name: "index",
data() {
return {
@ -150,6 +161,20 @@ export default {
limitedVisible: false,
mode: "show",
t_id: null,
exportCols: [
{ header: "用印时间", key: "create_time", wch: 20 },
{ header: "用印类别", key: "seal", wch: 15 },
{ header: "文件(资料)名称", key: "filename", wch: 25 },
{ header: "份数", key: "file_count", wch: 8 },
{ header: "印章部门", key: "belong_dept_name", wch: 15 },
{ header: "用印人", key: "create_by_name", wch: 12 },
{ header: "借出时间", key: "lending_date", wch: 15 },
{ header: "拟归还时间", key: "return_date", wch: 15 },
{ header: "实际归还时间", key: "actual_return_date", wch: 15 },
{ header: "是否借出", key: "_is_lending_text", wch: 10 },
{ header: "终版文件", key: "final_file", wch: 25 },
{ header: "审批状态", key: "_act_state_text", wch: 12 },
],
};
},
methods: {

View File

@ -80,13 +80,28 @@
</sc-upload-file>
</el-form-item>
<el-form-item label="用印份数" prop="file_count">
<el-input-number
v-model="localForm.file_count"
<el-input-number
v-model="localForm.file_count"
:min="0"
:step="1"
controls-position="right"
:disabled="localMode ==='show'"></el-input-number>
</el-form-item>
<!-- 终版文件提交人处理可上传结束可查看 -->
<el-form-item v-if="['提交人处理','结束'].includes(stateName)" :required="stateName === '提交人处理'" label="终版文件">
<div v-if="stateName === '提交人处理'">
<sc-upload-file
v-model="finalFileValue"
:multiple="false"
:limit="1"
accept=".pdf,.doc,.docx,.jpg,.png,.jpeg,.xlsx,.xls">
<el-button type="primary" icon="el-icon-upload">上传终版文件</el-button>
</sc-upload-file>
<el-link v-if="localForm.final_file" type="primary" :href="localForm.final_file" target="_blank" style="margin-top:8px">{{ localForm.final_file }}</el-link>
</div>
<el-link v-else-if="localForm.final_file" type="primary" :href="localForm.final_file" target="_blank">查看终版文件</el-link>
<span v-else style="color:#999">未上传</span>
</el-form-item>
</el-form>
<el-footer>
<ticketd_b
@ -155,6 +170,22 @@ export default {
'localForm.actual_return_date'(val) {
this.ticket_data.actual_return_date = val
},
'localForm.final_file'(val) {
this.ticket_data.final_file = val
},
},
computed: {
stateName() {
return this.localForm.ticket_?.state_?.name || '';
},
finalFileValue: {
get() {
return this.localForm.final_file || "";
},
set(val) {
this.localForm.final_file = val;
}
},
},
methods: {
handleDateChange(val) {
@ -163,11 +194,14 @@ export default {
},
async submit_b_func() {
let that = this;
if (that.stateName === '提交人处理' && !that.localForm.final_file) {
that.$message.warning("请先上传终版文件");
throw new Error("终版文件必填");
}
if(that.localMode == "add") {
let res = await that.$API.ofm.lendingseal.create.req(that.localForm);
that.localForm.id = res.id;
} else if (that.localMode == "edit") {
} else {
await that.$API.ofm.lendingseal.update.req(that.localForm.id, that.localForm);
}
},

View File

@ -7,6 +7,7 @@
icon="el-icon-plus"
@click="handleAdd"
></el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="用车申请台账" />
</div>
<div class="right-panel">
<el-date-picker
@ -155,10 +156,11 @@
<script>
import VehicleForm from "./vehicle_form.vue";
import ExportBtn from "./exportBtn.vue";
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
export default {
components: {
VehicleForm
VehicleForm, ExportBtn
},
name: "index",
data() {
@ -169,7 +171,22 @@ export default {
limitedVisible: false,
type: "show",
t_id: null,
vehicleList: []
vehicleList: [],
exportCols: [
{ header: "日期", key: "create_time", wch: 20 },
{ header: "用车部门", key: "belong_dept_name", wch: 15 },
{ header: "用车人", key: "create_by_name", wch: 12 },
{ header: "用车事由", key: "reason", wch: 20 },
{ header: "接待人员", key: "reception", wch: 12 },
{ header: "市内用车", key: "_is_city_text", wch: 10 },
{ header: "发车地点", key: "location", wch: 15 },
{ header: "途经地点", key: "via", wch: 15 },
{ header: "到达地点", key: "destination", wch: 15 },
{ header: "出发公里(km)", key: "start_km", wch: 14 },
{ header: "结束公里(km)", key: "end_km", wch: 14 },
{ header: "使用公里(km)", key: "actual_km", wch: 14 },
{ header: "审批状态", key: "_act_state_text", wch: 12 },
],
};
},
mounted(){

View File

@ -4,6 +4,7 @@
</div>
</template>
<script>
/* global gantt */
import GanttComponent from '@/components/GanttComponent.vue';
export default {
name: "rparty",

View File

@ -144,6 +144,7 @@
</el-drawer>
</template>
<script>
/* global gantt */
import GanttComponent from '@/components/GanttComponent.vue';
import saveDialog from "./utask_form.vue";
import { useTransitionFallthroughEmits } from 'element-plus';

View File

@ -238,6 +238,7 @@
></save-dialog>
</template>
<script>
/* global gantt */
import saveDialog from "./utask_form.vue";
import showDrawer from "./mtask_drawer.vue";
import GanttComponent from "@/components/GanttComponent.vue";

View File

@ -232,6 +232,7 @@
></save-dialog>
</template>
<script>
/* global gantt */
import saveDialog from "./utask_form.vue";
import showDrawer from "./mtask_drawer.vue";
import GanttComponent from "@/components/GanttComponent.vue";

View File

@ -240,6 +240,7 @@
</showDrawer>
</template>
<script>
/* global gantt */
import GanttComponent from "@/components/GanttComponent.vue";
import saveDialog from "./utask_form_2.vue";
import showDrawer from "./mtask_drawer.vue";

View File

@ -261,6 +261,7 @@
></save-dialog>
</template>
<script>
/* global gantt */
import saveDialog from "./utask_form.vue";
import showDrawer from "./mtask_drawer.vue";
import GanttComponent from "@/components/GanttComponent.vue";

View File

@ -3,6 +3,7 @@
<el-header>
<div class="left-panel">
<el-button type="primary" @click="handleAdd">新增</el-button>
<ExportBtn :getTableRef="() => $refs.table" :columns="exportCols" fileName="供应商审核台账" />
</div>
</el-header>
@ -53,6 +54,7 @@
import { ref } from 'vue'
import API from '@/api'
import supplieraudit_form from './supplieraudit_form.vue'
import ExportBtn from '@/components/scExportBtn/index.vue'
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
const query = ref({});
const drawerVisible = ref(false);
@ -62,4 +64,10 @@ const handleAdd = () => {
mode.value = 'add';
drawerVisible.value = true;
}
const exportCols = [
{ header: "供应商名称", key: "name", wch: 20 },
{ header: "审批状态", key: "_act_state_text", wch: 10 },
{ header: "物料名称", key: "material_name", wch: 20 },
{ header: "物料类别", key: "material_cate", wch: 20 },
]
</script>