Commit cc0018b2 authored by wangjiancheng's avatar wangjiancheng

feat:项目管理

parent 175d0ce8
import request from '@/utils/request'
// 查询项目管理列表
export function listProject(query) {
return request({
url: '/system/project/list',
method: 'get',
params: query
})
}
// 查询项目管理详细
export function getProject(id) {
return request({
url: '/system/project/' + id,
method: 'get'
})
}
// 新增项目管理
export function addProject(data) {
return request({
url: '/system/project',
method: 'post',
data: data
})
}
// 修改项目管理
export function updateProject(data) {
return request({
url: '/system/project',
method: 'put',
data: data
})
}
// 删除项目管理
export function delProject(id) {
return request({
url: '/system/project/' + id,
method: 'delete'
})
}
// 查询草稿箱列表
export function listDraft(query) {
return request({
url: '/system/project/draft/list',
method: 'get',
params: query
})
}
// 新增草稿箱
export function addDraft(data) {
data.darft = '0'
return request({
url: '/system/project/draft',
method: 'post',
data: data
})
}
// 逻辑删除项目
export function logicRemove(id) {
return request({
url: '/system/project/logicRemove/' + id,
method: 'delete'
})
}
<template>
<div class="app-container">
<el-form ref="form" :model="form" :rules="rules" label-width="auto">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="请输入项目名称" />
</el-form-item>
<el-form-item label="项目类型" prop="projectType">
<el-select v-model="form.projectType" placeholder="请选择项目类型" >
<el-option
v-for="dict in project_type"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="预计结束时间" prop="startDate">
<el-date-picker
v-model="form.startDate"
type="date"
placeholder="选择日期"
>
</el-date-picker>
</el-form-item>
<el-form-item label="预计开始时间" prop="endDate">
<el-date-picker
class="el-input"
v-model="form.endDate"
type="date"
placeholder="选择日期"
>
</el-date-picker>
</el-form-item>
<el-form-item label="项目经理" prop="projectManagerId">
<el-select v-model="form.projectManagerId" placeholder="请选择项目经理" >
<el-option
v-for="dict in managerOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="项目成员" prop="projectMemberIds">
<el-select v-model="form.projectMemberIds" placeholder="请选择项目成员" >
<el-option
v-for="dict in membersOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="项目成本" prop="projectCost">
<el-input v-model="form.projectCost" placeholder="请输入项目成本" ></el-input>
</el-form-item>
<el-form-item label="项目描述" prop="projectDescribe">
<el-input type="textarea" v-model="form.projectDescribe" placeholder="请输入项目描述" ></el-input>
</el-form-item>
<el-form-item label="项目状态" prop="projectStatus">
<el-select v-model="form.projectStatus" placeholder="请选择项目状态" >
<el-option
v-for="dict in project_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="项目附件" >
<el-upload
v-model:file-list="form.fileList"
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
multiple
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:limit="3"
:on-exceed="handleExceed"
>
<el-button type="text">上传附件</el-button>
</el-upload>
</el-form-item>
<el-form-item label="项目回款">
<el-select
v-model="form.repaymentCount"
placeholder="请选择项目回款笔数"
@change="updateRepaymentInputs"
>
<el-option
v-for="num in 10"
:key="num"
:label="num"
:value="num"
></el-option>
</el-select>
</el-form-item>
<el-form :model="form" label-width="120px">
<div v-for="(item, index) in form.repaymentDetails" :key="index">
<el-row>
<el-col :span="5">
<!-- 回款比例 -->
<el-form-item :label="'第 ' + (index + 1) + ' 笔'">
<el-input v-model="item.repaymentPercentage" suffix="%" ></el-input>
</el-form-item>
</el-col>
<el-col :span="5">
<!-- 回款条件 -->
<el-form-item>
<el-input v-model="item.repaymentCondition" ></el-input>
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</el-form>
<!-- 提交和保存草稿按钮 -->
<div>
<el-button type="primary" @click="handleSubmit" >提交</el-button>
<el-button type="primary" @click="saveDraft">保存草稿</el-button>
<el-button type="info" @click="reset">取消</el-button>
</div>
</div>
</template>
<script setup name="add">
import { listUser } from "../../api/system/user.js";
const { proxy } = getCurrentInstance();
const { project_status, project_type } = proxy.useDict('project_status', 'project_type');
const form = reactive({
projectName: '',
projectType: '',
startDate: '',
endDate: '',
departmentLeadId: '',
projectManagerId: '',
projectMemberIds: [],
projectCost: '',
projectDescribe: '',
projectStatus: '',
fileList: [],
repaymentCount: null,
repaymentDetails: []
})
const rules = ref({
projectName: [
{ required: true, message: '项目名称不能为空', trigger: 'blur' }
],
projectType: [
{ required: true, message: '项目类型不能为空', trigger: 'blur' }
],
startDate: [
{ required: true, message: '预计开始时间不能为空', trigger: 'blur' }
],
endDate: [
{ required: true, message: '预计结束时间不能为空', trigger: 'blur' }
]
})
const headOptions = ref([])
const managerOptions = ref([])
const membersOptions = ref([])
const getUserList = () => {
listUser().then(response => {
headOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
managerOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
membersOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
})
}
// 提交表单
const handleSubmit = () => {
console.log(form)
}
// 保存草稿
const saveDraft = () => {
console.log(form)
}
// 重置表单
const resetForm = () => {
form.projectName = ''
form.projectType = ''
form.startDate = ''
form.endDate = ''
form.departmentLeadId = ''
form.projectManagerId = ''
form.projectMemberIds = []
form.projectCost = ''
form.projectDescribe = ''
form.projectStatus = ''
form.fileList = []
form.repaymentCount = ''
form.repaymentDetails = []
}
// 返回项目管理页面
const reset = () => {
// 返回项目
proxy.$router.push({ path: '/project' })
resetForm()
}
const updateRepaymentInputs = () => {
// 根据用户输入的回款笔数更新百分比输入框的数量
if (form.repaymentCount > 0) {
form.repaymentDetails = Array.from({ length: form.repaymentCount }, () => ({
repaymentPercentage: null, // 回款百分比
repaymentCondition: "" // 回款前置条件
}));
} else {
form.repaymentDetails = [];
}
}
// 删除附件相关事件
const handleRemove = (file, fileList) => {
console.log(file, fileList)
}
// 预览附件相关事件
const handlePreview = (file) => {
console.log(file)
}
// 上传附件数量限制
const handleExceed = (files, fileList) => {
this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
}
// 上传附件删除相关事件
const beforeRemove = (file, fileList) => {
return this.$confirm(`确定移除 ${file.name}?`);
}
// 上传附件成功相关事件
// 在组件挂载时执行
onMounted(() => {
getUserList()
});
</script>
<style scoped lang="scss">
</style>
<template>
<div class="app-container">
<el-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="项目编号" align="center" prop="projectNumber" />
<el-table-column label="项目名称" align="center" prop="projectName" />
<el-table-column label="项目类型" align="center" prop="projectType">
<template #default="scope">
<dict-tag :options="project_type" :value="scope.row.projectType"/>
</template>
</el-table-column>
<el-table-column label="预计开始时间" align="center" prop="startDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.startDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="预计结束时间" align="center" prop="endDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.endDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="事业部负责人" align="center" prop="departmentLeaderId" />
<el-table-column label="项目经理" align="center" prop="projectManagerId" />
<el-table-column label="项目成本" align="center" prop="projectCost" />
<el-table-column label="项目描述" align="center" prop="projectDescribe" />
<el-table-column label="项目状态" align="center" prop="projectStatus">
<template #default="scope">
<dict-tag :options="project_status" :value="scope.row.projectStatus"/>
</template>
</el-table-column>
<el-table-column label="立项时间" align="center" prop="createDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="更新时间" align="center" prop="updateDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.updateDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:project:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:project:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script setup name="draft">
import { listProject,logicRemove} from "../../api/project/project.js";
const { proxy } = getCurrentInstance();
const { project_status, project_type } = proxy.useDict('project_status', 'project_type');
const projectList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
projectNumber: null,
projectName: null,
projectType: null,
departmentLeaderId: null,
projectManagerId: null,
projectStatus: null,
},
rules: {
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询项目管理列表 */
function getList() {
loading.value = true;
listProject(queryParams.value).then(response => {
projectList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
// 取消按钮
function cancel() {
open.value = false;
reset();
}
// 表单重置
function reset() {
form.value = {
id: null,
projectNumber: null,
projectName: null,
projectType: null,
startDate: null,
endDate: null,
departmentLeaderId: null,
projectManagerId: null,
projectCost: null,
projectDescribe: null,
projectStatus: null,
createDate: null,
updateDate: null,
draft: null,
delFlag: null
};
proxy.resetForm("projectRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
// 跳转新增页面
proxy.$router.push({ path: '/project/opera/add' });
}
/** 修改按钮操作 */
function handleUpdate(row) {
proxy.$router.push({ path: '/project/opera/edit', query: { id: row.id } });
}
// 查看详情
function handleView(row) {
// 跳转详情页面
proxy.$router.push({ path: '/project/opera/view', query: { id: row.id } });
}
// 查看草稿箱列表
function handleDraft() {
// 跳转草稿箱页面
proxy.$router.push({ path: '/project/opera/draft' });
}
/** 逻辑删除按钮操作 */
function handleDelete(row) {
const _ids = row.id || ids.value;
proxy.$modal.confirm('是否确认删除项目管理编号为"' + _ids + '"的数据项?').then(function() {
return logicRemove(_ids);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download('system/project/export', {
...queryParams.value
}, `project_${new Date().getTime()}.xlsx`)
}
getList();
</script>
<style scoped lang="scss">
</style>
<template>
<div class="app-container">
<el-form ref="form" :model="form" :rules="rules" label-width="auto">
<el-form-item label="项目编号">
<el-input v-model="form.projectNumber" placeholder="请输入项目编号" disabled/>
</el-form-item>
<el-form-item label="项目名称">
<el-input v-model="form.projectName" placeholder="请输入项目名称"/>
</el-form-item>
<el-form-item label="项目类型">
<el-select v-model="form.projectType" placeholder="请选择项目类型" >
<el-option
v-for="dict in project_type"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="预计结束时间">
<el-date-picker
v-model="form.startDate"
type="date"
placeholder="选择日期"
/>
</el-form-item>
<el-form-item label="预计开始时间">
<el-date-picker
v-model="form.endDate"
type="date"
placeholder="选择日期"
/>
</el-form-item>
<el-form-item label="事业部门负责人">
<el-select v-model="form.departmentLeadId" placeholder="请选择事业部门负责人" disabled>
<el-option
v-for="dict in headOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="项目经理">
<el-select v-model="form.projectManagerId" placeholder="请选择项目经理" disabled>
<el-option
v-for="dict in managerOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="项目成员">
<el-select v-model="form.projectMemberIds" placeholder="请选择项目成员">
<el-option
v-for="dict in membersOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="项目成本">
<el-input v-model="form.projectCost" placeholder="请输入项目成本" />
</el-form-item>
<el-form-item label="项目描述">
<el-input v-model="form.projectDescribe" placeholder="请输入项目描述" />
</el-form-item>
<el-form-item label="项目状态">
<el-select v-model="form.projectStatus" placeholder="请选择项目状态">
<el-option
v-for="dict in project_status"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="项目附件">
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:file-list="form.fileList"
:on-change="handleChange"
:limit="3"
:on-exceed="handleExceed"
:auto-upload="false"
:on-success="handleSuccess">
<el-button size="default" type="text">点击上传</el-button>
</el-upload>
</el-form-item>
<el-form-item label="项目回款笔数">
<el-select
v-model="form.repaymentCount"
placeholder="请选择项目回款笔数"
@change="updateRepaymentInputs"
>
<el-option
v-for="num in 10"
:key="num"
:label="num"
:value="num"
></el-option>
</el-select>
</el-form-item>
<el-form :model="form" label-width="120px">
<div v-for="(item, index) in form.repaymentDetails" :key="index">
<el-row>
<el-col :span="5">
<!-- 回款比例 -->
<el-form-item :label="'第 ' + (index + 1) + ' 笔'">
<el-input v-model="item.repaymentPercentage" suffix="%"></el-input>
</el-form-item>
</el-col>
<el-col :span="5">
<!-- 回款条件 -->
<el-form-item>
<el-input v-model="item.repaymentCondition"></el-input>
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</el-form>
<div class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="submitForm">确 定</el-button>
</div>
</div>
</template>
<script setup name="edit">
import {getProject} from "../../api/project/project.js";
import {listUser} from "../../api/system/user.js";
const { proxy } = getCurrentInstance();
const { project_status, project_type } = proxy.useDict('project_status', 'project_type');
const headOptions = ref([])
const managerOptions = ref([])
const membersOptions = ref([])
const repaymentInputs = ref([])
const form = ref({
projectNumber: '',
projectName: '',
projectType: '',
startDate: '',
endDate: '',
departmentLeadId: '',
projectManagerId: '',
projectMemberIds: [],
projectCost: '',
projectDescribe: '',
projectStatus: '',
fileList: [],
repaymentCount: '',
repaymentDetails: [],
})
const rules = ref({
projectName: [
{ required: true, message: '项目名称不能为空', trigger: 'blur' }
],
projectType: [
{ required: true, message: '项目类型不能为空', trigger: 'blur' }
],
startDate: [
{ required: true, message: '预计开始时间不能为空', trigger: 'blur' }
],
endDate: [
{ required: true, message: '预计结束时间不能为空', trigger: 'blur' }
]
})
const getUserList = () => {
listUser().then(response => {
headOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
managerOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
membersOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
})
}
let projectId = null;
function getProjectManage(){
projectId = proxy.$route.query.id;
getProject(projectId).then(response => {
form.value = response.data;
})
}
const updateRepaymentInputs = () => {
// 根据输入的回款笔数更新动态生成的回款输入框
const count = parseInt(form.value.repaymentCount)
if (isNaN(count)) {
return
}
repaymentInputs.value = []
for (let i = 0; i < count; i++) {
repaymentInputs.value.push({
repaymentPercentage: '',
repaymentCondition: ''
})
}
}
// 获取 typeName 的方法
const getTypeName = (id) => {
//const type = project_type.find(item => item.id === id);
// return type ? type.name : '未知类型';
}
const handleChange = (file, fileList) => {
console.log(file, fileList)
}
const handleRemove = (file, fileList) => {
console.log(file, fileList)
}
const handleSuccess = (response, file, fileList) => {
console.log(response, file, fileList)
}
const handlePreview = (file) => {
console.log(file)
}
const handleExceed = (files, fileList) => {
proxy.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
}
const cancel = () => {
proxy.$router.push({ path: '/project' })
resetForm()
}
onMounted(() => {
getProjectManage()
getUserList()
})
</script>
<style scoped lang="scss">
</style>
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="项目名称" prop="projectName">
<el-input
v-model="queryParams.projectName"
placeholder="请输入项目名称"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="项目类型" prop="projectType">
<el-select v-model="queryParams.projectType" placeholder="请选择项目类型" clearable>
<el-option
v-for="dict in project_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="事业部负责人" prop="departmentLeaderId">
<el-input
v-model="queryParams.departmentLeaderId"
placeholder="请输入事业部负责人"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="项目经理" prop="projectManagerId">
<el-input
v-model="queryParams.projectManagerId"
placeholder="请输入项目经理"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="项目状态" prop="projectStatus">
<el-select v-model="queryParams.projectStatus" placeholder="请选择项目状态" clearable>
<el-option
v-for="dict in project_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:project:add']"
>项目立项</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Delete"
:disabled="single"
@click="handleDraft"
v-hasPermi="['system:project:draft']"
>草稿箱</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:project:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="projectList">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="项目编号" align="center" prop="projectNumber" />
<el-table-column label="项目名称" align="center" prop="projectName" />
<el-table-column label="项目类型" align="center" prop="projectType">
<template #default="scope">
<dict-tag :options="project_type" :value="scope.row.projectType"/>
</template>
</el-table-column>
<el-table-column label="预计开始时间" align="center" prop="startDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.startDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="预计结束时间" align="center" prop="endDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.endDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="事业部负责人" align="center" prop="departmentLeaderName" />
<el-table-column label="项目经理" align="center" prop="projectManagerName"/>
<el-table-column label="项目成本" align="center" prop="projectCost" />
<el-table-column label="项目状态" align="center" prop="projectStatus">
<template #default="scope">
<dict-tag :options="project_status" :value="scope.row.projectStatus"/>
</template>
</el-table-column>
<el-table-column label="立项时间" align="center" prop="createDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="更新时间" align="center" prop="updateDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.updateDate, '{y}-{m}-{d}') || '-'}}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="250">
<template #default="scope">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['system:project:view']">详情</el-button>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:project:edit']">编辑</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:project:logicRemove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script setup name="Project">
import { listProject,logicRemove} from "../../api/project/project.js";
const { proxy } = getCurrentInstance();
const { project_status, project_type } = proxy.useDict('project_status', 'project_type');
const projectList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
projectNumber: null,
projectName: null,
projectType: null,
departmentLeaderId: null,
projectManagerId: null,
projectStatus: null,
},
rules: {
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询项目管理列表 */
function getList() {
loading.value = true;
listProject(queryParams.value).then(response => {
projectList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
// 取消按钮
function cancel() {
open.value = false;
reset();
}
// 表单重置
function reset() {
form.value = {
id: null,
projectNumber: null,
projectName: null,
projectType: null,
startDate: null,
endDate: null,
departmentLeaderId: null,
projectManagerId: null,
projectCost: null,
projectDescribe: null,
projectStatus: null,
createDate: null,
updateDate: null,
draft: null,
delFlag: null
};
proxy.resetForm("projectRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
// 跳转新增页面
proxy.$router.push({ path: '/project/opera/add' });
}
/** 修改按钮操作 */
function handleUpdate(row) {
proxy.$router.push({ path: '/project/opera/edit', query: { id: row.id } });
}
// 查看详情
function handleView(row) {
// 跳转详情页面
proxy.$router.push({ path: '/project/opera/view', query: { id: row.id } });
}
// 查看草稿箱列表
function handleDraft() {
// 跳转草稿箱页面
proxy.$router.push({ path: '/project/opera/draft' });
}
/** 逻辑删除按钮操作 */
function handleDelete(row) {
const _ids = row.id || ids.value;
proxy.$modal.confirm('是否确认删除项目管理编号为"' + _ids + '"的数据项?').then(function() {
return logicRemove(_ids);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download('system/project/export', {
...queryParams.value
}, `project_${new Date().getTime()}.xlsx`)
}
getList();
</script>
<template>
<div class="app-container">
<el-form :model="form" label-width="auto">
<el-form-item label="项目编号" prop="projectNumber" >
<el-input v-model="form.projectNumber" placeholder="请输入项目编号" disabled></el-input>
</el-form-item>
<el-form-item label="项目名称" prop="projectName" >
<el-input v-model="form.projectName" placeholder="请输入项目名称" readonly></el-input>
</el-form-item>
<el-form-item label="项目类型" prop="projectType" >
<el-select
v-model="form.projectType"
placeholder="请选择项目类型"
readonly>
<el-option
v-for="dict in project_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="开始时间">
<el-date-picker
v-model="form.startDate"
type="date"
placeholder="选择日期"
readonly
></el-date-picker>
</el-form-item>
<el-form-item label="结束时间">
<el-date-picker
v-model="form.endDate"
type="date"
placeholder="选择日期"
readonly
></el-date-picker>
</el-form-item>
<el-form-item label="部门负责人">
<el-input
v-model="form.departmentLeaderName"
placeholder="请输入部门负责人名称"
disabled
></el-input>
</el-form-item>
<el-form-item label="项目经理">
<el-select
v-model="form.projectManagerId"
placeholder="请选择项目经理"
readonly>
<el-option
v-for="dict in managerOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="项目成员">
<el-select
v-model="form.projectMemberIds"
multiple
placeholder="请选择项目成员"
readonly>
<el-option
v-for="dict in membersOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="项目成本(元)">
<el-input
v-model="form.projectCost"
placeholder="请输入项目成本"
readonly
></el-input>
</el-form-item>
<el-form-item label="项目描述">
<el-input
v-model="form.projectDescribe"
type="textarea"
placeholder="请输入项目描述"
readonly
></el-input>
</el-form-item>
<el-form-item label="项目状态">
<el-select
v-model="form.projectStatus"
placeholder="请选择项目状态"
>
<el-option
v-for="dict in project_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="项目附件">
<!-- 展示已上传的附件 -->
<ul>
<li v-for="(file, index) in fileList" :key="index">
<a :href="file.url" target="_blank">{{ file.name }}</a>
</li>
</ul>
</el-form-item>
<el-form-item label="项目回款笔数">
<el-input v-model="form.repaymentCount" readonly></el-input>
</el-form-item>
<el-form :model="form" label-width="120px">
<div v-for="(item, index) in form.repaymentDetails" :key="index">
<el-row>
<el-col :span="5">
<!-- 回款比例 -->
<el-form-item :label="'第 ' + (index + 1) + ' 笔'">
<el-input v-model="item.repaymentPercentage" suffix="%" readonly></el-input>
</el-form-item>
</el-col>
<el-col :span="5">
<!-- 回款条件 -->
<el-form-item>
<el-input v-model="item.repaymentCondition" readonly></el-input>
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</el-form>
<div>
<el-button @click="reset">取消</el-button>
</div>
</div>
</template>
<script setup>
import { getProject } from "../../api/project/project.js";
import {listUser} from "../../api/system/user.js";
const { proxy } = getCurrentInstance();
const { project_status, project_type } = proxy.useDict('project_status', 'project_type');
const form = ref({
projectNumber: '',
projectName: '',
projectType: '',
startDate: '',
endDate: '',
departmentLeaderName: '',
departmentLeadId: '',
projectManagerId: '',
projectMemberIds: [],
projectCost: '',
projectDescribe: '',
projectStatus: '',
fileList: [],
repaymentCount: '',
repaymentDetails: [],
})
const repaymentDetails = ref([])
const headOptions = ref([])
const managerOptions = ref([])
const membersOptions = ref([])
const getUserList = () => {
listUser().then(response => {
headOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
managerOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
membersOptions.value = response.rows.map(item => {
return {
value: item.userId,
label: item.nickName
}
})
})
}
// 定义项目ID
let projectId = null;
function getProjectManage(){
projectId = proxy.$route.query.id;
getProject(projectId).then(response => {
form.value = response.data;
})
}
// 返回项目管理页面
const reset = () => {
// 返回项目
proxy.$router.push({ path: '/project' })
}
// 在组件挂载时执行
onMounted(() => {
getProjectManage()
getUserList()
});
</script>
<style scoped lang="scss">
</style>
<template>
<div class="form-container">
<!-- 标题和分割线 -->
<div class="header-wrapper">
<h3 class="input-label">物品基础信息</h3>
<div class="sep-wrapper">
<div class="sep-label"></div>
<div class="sep-bg"></div>
</div>
</div>
<el-form :model="form" label-width="80px">
<!-- 物品编号 -->
<el-row>
<el-col :span="24">
<label class="input-label">物品编号</label>
<el-input v-model="form.itemCode" disabled style="width: 20%;"></el-input>
</el-col>
</el-row>
<!-- 物品名称 -->
<el-row>
<el-col :span="24">
<label class="input-label">物品名称</label>
<el-input v-model="form.itemName" placeholder="请输入物品名称" style="width: 20%;"></el-input>
</el-col>
</el-row>
<!-- 物品类型 -->
<el-row>
<el-col :span="24">
<label class="input-label">物品类型</label>
<el-select v-model="form.itemType" filterable placeholder="请选择或输入" style="width: 20%;">
<el-option v-for="item in itemTypes" :key="item" :label="item" :value="item"></el-option>
</el-select>
</el-col>
</el-row>
<!-- 单位 -->
<el-row>
<el-col :span="24">
<label class="input-label">单位</label>
<el-input v-model="form.unit" placeholder="请输入单位" style="width: 20%;"></el-input>
</el-col>
</el-row>
</el-form>
<!-- 提交和保存草稿按钮 -->
<div class="button-container">
<el-button type="primary" @click="handleSubmit" style="margin-right: 20px;">提交</el-button>
<el-button @click="saveDraft">保存草稿</el-button>
</div>
</div>
</template>
<script>
import { addMaterial } from '@/api/system/material/material';
import { ElMessage } from 'element-plus';
export default {
data() {
return {
form: {
itemCode: '',
itemName: '',
itemType: '',
unit: ''
},
itemTypes: ['办公家具', '办公设备', '日杂百货']
};
},
methods: {
generateItemCode() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
return `WP${year}${month}${day}${hours}${minutes}${seconds}`;
},
handleSubmit() {
if (this.form.itemName && this.form.itemType && this.form.unit) {
addMaterial(this.form).then(response => {
ElMessage.success('物品信息提交成功');
// 清空表单
this.resetForm();
}).catch(error => {
ElMessage.error('物品信息提交失败: ' + error.message);
});
} else {
ElMessage.warning('请填写所有必填项');
}
},
saveDraft() {
// 保存草稿到本地存储
localStorage.setItem('materialDraft', JSON.stringify(this.form));
ElMessage.info('草稿已保存');
},
resetForm() {
this.form = {
itemCode: this.generateItemCode(), // 重新生成新的物品编号
itemName: '',
itemType: '',
unit: ''
};
// 清除草稿
localStorage.removeItem('materialDraft');
}
},
created() {
// 加载草稿
const draft = localStorage.getItem('materialDraft');
if (draft) {
this.form = JSON.parse(draft);
ElMessage.info('已加载草稿');
}
},
mounted() {
// 页面加载时生成物品编号
if (!this.form.itemCode) {
this.form.itemCode = this.generateItemCode();
}
}
};
</script>
<style scoped>
/* 样式部分保持不变 */
.form-container {
padding-left: 40px;
}
.input-label {
display: block;
font-weight: bold;
margin-bottom: 10px;
}
.sep-label {
border-radius: 0 8px;
width: 110px;
height: 12px;
overflow: hidden;
position: relative;
background-color: rgb(0, 137, 127);
}
.sep-bg {
width: 90%;
border-bottom: 4px solid;
border-color: rgb(0, 137, 127);
height: 2px;
opacity: .2;
margin-top: 6px;
}
.sep-wrapper {
display: flex;
align-items: center;
}
.header-wrapper {
margin-bottom: 20px;
}
.el-row + .el-row {
margin-top: 10px;
}
.button-container {
text-align: left;
margin-top: 20px;
}
</style>
<template>
<div class="form-container">
<!-- 标题和分割线 -->
<div class="header-wrapper">
<h3 class="input-label">物品领用申请</h3>
<div class="sep-wrapper">
<div class="sep-label"></div>
<div class="sep-bg"></div>
</div>
</div>
<el-form :model="form" :rules="rules" ref="form" label-width="80px">
<el-row>
<el-col :span="24">
<label class="input-label">申请日期</label>
<el-date-picker v-model="form.applyDate" type="date" placeholder="选择日期" style="width: 90%;"></el-date-picker>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">申请人</label>
<el-input v-model="form.applicant" placeholder="请输入申请人" style="width: 90%;"></el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">所属部门</label>
<el-input v-model="form.department" placeholder="请输入所属部门" style="width: 90%;"></el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">物品领用明细</label>
<el-table :data="form.items" border style="width: 1131px">
<el-table-column label="序号" width="60" align="center">
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="type" label="物品类型" width="170">
<template #default="scope">
<el-select v-model="scope.row.itemType" placeholder="请选择" @change="onItemTypeChange(scope.$index, $event)">
<el-option v-for="item in itemTypes" :key="item" :label="item" :value="item"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column prop="name" label="物品名称" width="170">
<template #default="scope">
<el-select v-model="scope.row.itemName" placeholder="请选择" @change="updateUnitBasedOnItemName(scope.$index)">
<el-option v-for="item in itemNames" :key="item" :label="item" :value="item"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column prop="unit" label="单位" width="170">
<template #default="scope">
<el-input v-model="scope.row.unit" placeholder="请输入单位" readonly></el-input>
</template>
</el-table-column>
<el-table-column prop="stock" label="库存数量" width="170">
<template #default="scope">
<el-input v-model.number="scope.row.stock" placeholder="请输入库存数量" @input="updateRemaining(scope.$index)"></el-input>
</template>
</el-table-column>
<el-table-column prop="quantity" label="领用数量" width="170">
<template #default="scope">
<el-input-number v-model.number="scope.row.applyQuantity" :min="0" :max="scope.row.stock" @change="updateRemaining(scope.$index)" style="width: 100%;"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="remaining" label="领用后剩余库存" width="220">
<template #default="scope">
<el-input v-model.number="scope.row.applyRemaining" placeholder="自动计算" readonly></el-input>
</template>
</el-table-column>
</el-table>
<!-- 绿色文字按钮 -->
<el-button type="text" @click="addItem" class="custom-text-button">+ 添加</el-button>
<el-button type="text" @click="pasteItem" class="custom-text-button">+ 粘贴新增</el-button>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">领用类型</label>
<el-radio-group v-model="form.usageType">
<div class="radio-item">
<el-radio label="借用(需归还)" class="borrow"><span class="radio-label">借用(需归还)</span></el-radio>
<br>
<el-radio label="领用(无需归还)" class="receive"><span class="radio-label">领用(无需归还)</span></el-radio>
</div>
</el-radio-group>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">申请备注</label>
<el-input type="textarea" v-model="form.remark" placeholder="请输入申请备注" style="width: 70%;" class="custom-textarea"></el-input>
</el-col>
</el-row>
<!-- 标题和分割线 -->
<div class="header-wrapper">
<h3 class="input-label">申请审批</h3>
<div class="sep-wrapper">
<div class="sep-label"></div>
<div class="sep-bg"></div>
</div>
</div>
<!-- 审批时间 -->
<el-row>
<el-col :span="12">
<label class="input-label">审批时间</label>
<el-date-picker v-model="form.approvalDate" type="date" placeholder="选择日期" style="width: 90%;"></el-date-picker>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">审批意见</label>
<el-radio-group v-model="form.approvalAdvice">
<div class="radio-item">
<el-radio label="通过" class="pass"><span class="radio-label">同意</span></el-radio>
<br>
<el-radio label="不通过" class="unpass"><span class="radio-label">不同意</span></el-radio>
</div>
</el-radio-group>
</el-col>
</el-row>
</el-form>
<!-- 提交和保存草稿按钮 -->
<div class="button-container">
<el-button type="primary" @click="submitForm" style="margin-right: 20px;">提交</el-button>
<el-button @click="saveDraft">保存草稿</el-button>
</div>
<el-dialog title="粘贴新增" v-model="showPasteDialog" width="50%">
<!-- 对话框内容 -->
</el-dialog>
</div>
</template>
<script>
import { addApply, updateApply } from '@/api/system/material/apply';
import { listMaterial } from '@/api/system/material/material';
import { ElMessageBox } from 'element-plus';
export default {
data() {
return {
form: {
applyDate: '',
applicant: '',
department: '',
items: [
{ itemType: '', itemName: '', unit: '', stock: 0, applyQuantity: 0, applyRemaining: 0 }
],
usageType: '借用(需归还)',
remark: '',
approvalDate: '',
approvalAdvice: '同意',
},
showPasteDialog: false,
editingId: null,
rules: {
applyDate: [{ required: true, message: '请选择申请日期', trigger: 'change' }],
applicant: [{ required: true, message: '请输入申请人', trigger: 'blur' }],
department: [{ required: true, message: '请输入所属部门', trigger: 'blur' }],
usageType: [{ required: true, message: '请选择领用类型', trigger: 'change' }],
approvalAdvice: [{ required: true, message: '请选择审批意见', trigger: 'change' }],
},
itemTypes: ['办公家具', '办公设备', '日杂百货'], // 物品类型列表
itemNames: [], // 物品名称列表
materials: [], // 物品信息列表
};
},
methods: {
addItem() {
this.form.items.push({ itemType: '', itemName: '', unit: '', stock: 0, applyQuantity: 0, applyRemaining: 0 });
},
pasteItem() {
this.showPasteDialog = true;
},
submitForm() {
this.$refs.form.validate(valid => {
if (valid) {
const data = {
...this.form,
items: JSON.stringify(this.form.items)
};
addApply(data).then(response => {
ElMessageBox.alert('申请提交成功', '提示', {
confirmButtonText: '确定',
callback: action => {
this.$message.success('申请提交成功');
this.resetForm();
// 提交成功后清空草稿
localStorage.removeItem('materialApplyDraft');
}
});
}).catch(error => {
ElMessageBox.alert('申请提交失败', '提示', {
confirmButtonText: '确定',
callback: action => {
this.$message.error('申请提交失败: ' + error.message);
}
});
});
} else {
this.$message.error('请检查表单填写是否正确');
}
});
},
saveDraft() {
localStorage.setItem('materialApplyDraft', JSON.stringify(this.form));
this.$message.info('草稿已保存');
},
updateRemaining(index) {
const item = this.form.items[index];
item.applyRemaining = item.stock - item.applyQuantity;
},
resetForm() {
this.form = {
applyDate: '',
applicant: '',
department: '',
items: [
{ itemType: '', itemName: '', unit: '', stock: 0, applyQuantity: 0, applyRemaining: 0 }
],
usageType: '借用(需归还)',
remark: '',
approvalDate: '',
approvalAdvice: '同意',
};
this.editingId = null;
this.$refs.form.resetFields();
},
fetchMaterials() {
listMaterial().then(response => {
console.log('Response:', response); // 添加调试信息
if (response && response.code === 200) {
if (Array.isArray(response.rows)) { // 直接检查 response.rows
this.materials = response.rows; // 确保正确赋值
this.updateItemNames(); // 确保在材料加载后更新物品名称
} else {
this.$message.error('获取物品信息失败: 返回数据格式不正确');
}
} else {
this.$message.error('获取物品信息失败: ' + response.msg);
}
}).catch(error => {
this.$message.error('获取物品信息失败: ' + error.message);
});
},
updateItemNames(index) {
if (index >= 0 && index < this.form.items.length) {
const selectedType = this.form.items[index].itemType;
if (selectedType) {
this.itemNames = this.materials
.filter(material => material.itemType === selectedType)
.map(material => material.itemName);
} else {
this.itemNames = [];
}
}
},
onItemTypeChange(index, newItemType) {
this.form.items[index].itemType = newItemType;
this.form.items[index].itemName = ''; // 清空物品名称
this.form.items[index].unit = ''; // 清空单位
this.updateItemNames(index); // 更新物品名称选项
},
updateUnitBasedOnItemName(index) {
const item = this.form.items[index];
if (item.itemType && item.itemName) {
const selectedItem = this.materials.find(material =>
material.itemType === item.itemType &&
material.itemName === item.itemName
);
if (selectedItem) {
item.unit = selectedItem.unit;
} else {
item.unit = '';
}
}
}
},
watch: {
'form.items': {
handler(newItems) {
newItems.forEach((item, index) => {
this.updateUnitBasedOnItemName(index);
});
},
deep: true
}
},
created() {
// 加载草稿
const draft = localStorage.getItem('materialApplyDraft');
if (draft) {
this.form = JSON.parse(draft);
this.$message.info('已加载草稿');
}
// 获取物品信息
this.fetchMaterials();
}
};
</script>
<style scoped>
/* 增加左边距 */
.form-container {
padding-left: 40px; /* 调整这个值以适应你的需求 */
}
.input-label {
display: block;
font-weight: bold;
margin-bottom: 10px;
}
/* 分割线样式 */
.sep-label {
border-radius: 0 8px;
width: 110px;
height: 12px;
overflow: hidden;
position: relative;
background-color: rgb(0, 137, 127);
}
.sep-bg {
width: 90%;
border-bottom: 4px solid;
border-color: rgb(0, 137, 127);
height: 2px;
opacity: .2;
margin-top: 6px; /* 调整此值以适应布局 */
}
.sep-wrapper {
display: flex;
align-items: center; /* 垂直居中 */
}
.header-wrapper {
margin-bottom: 20px;
}
/* 增加行间距 */
.el-row + .el-row {
margin-top: 10px;
}
/* 自定义文本按钮样式 */
.custom-text-button {
color: rgb(0, 137, 127);
margin-right: 10px;
}
.radio-item {
margin-bottom: 20px; /* 设置你想要的间隔大小 */
}
.pass .radio-label {
color: white;
background-color: #38b654;
padding: 5px 10px;
border-radius: 4px;
}
.unpass .radio-label {
color: white;
background-color: #f4661a;
padding: 5px 10px;
border-radius: 4px;
}
.borrow .radio-label {
color: white;
background-color: #fa575b;
padding: 5px 10px;
border-radius: 4px;
}
.receive .radio-label {
color: white;
background-color: #00afff;
padding: 5px 10px;
border-radius: 4px;
}
.custom-textarea {
margin-bottom: 10px;
height: 150px; /* 根据需要调整 */
}
/* 确保textarea内部的文字布局合理 */
.custom-textarea >>> .el-textarea__inner {
height: 100%;
line-height: normal;
padding: 10px; /* 可根据实际需求调整 */
box-sizing: border-box;
}
.button-container {
text-align: left; /* 左对齐按钮 */
margin-top: 20px; /* 确保有足够的顶部间距 */
margin-bottom: 40px; /* 页面底部留出间隔 */
}
</style>
<template>
<div class="form-container">
<!-- 标题和分割线 -->
<div class="header-wrapper">
<h3 class="input-label">入库信息填写</h3>
<div class="sep-wrapper">
<div class="sep-label"></div>
<div class="sep-bg"></div>
</div>
</div>
<el-form :model="form" label-width="80px">
<!-- 入库日期 -->
<el-row :gutter="20">
<el-col :span="12">
<label class="input-label">入库日期</label>
<el-date-picker v-model="form.entryDate" type="date" placeholder="选择日期" style="width: 90%;"></el-date-picker>
</el-col>
<!-- 入库人员 -->
<el-col :span="12">
<label class="input-label">入库人员</label>
<el-input v-model="form.entryPerson" prefix-icon="el-icon-user" placeholder="请输入入库人员" style="width: 90%;"></el-input>
</el-col>
</el-row>
<!-- 物品类型 -->
<el-row :gutter="20">
<el-col :span="12">
<label class="input-label">物品类型</label>
<el-select v-model="form.itemType" filterable placeholder="请选择或输入" style="width: 90%;" @change="onItemTypeChange">
<el-option v-for="item in itemTypes" :key="item" :label="item" :value="item"></el-option>
</el-select>
</el-col>
<!-- 物品名称 -->
<el-col :span="12">
<label class="input-label">物品名称</label>
<el-select v-model="form.itemName" filterable placeholder="请选择或输入" style="width: 90%;">
<el-option v-for="item in itemNames" :key="item" :label="item" :value="item"></el-option>
</el-select>
</el-col>
</el-row>
<!-- 单位和数量 -->
<el-row :gutter="20">
<el-col :span="12">
<label class="input-label">单位</label>
<el-input v-model="form.unit" placeholder="请输入单位" style="width: 90%;"></el-input>
</el-col>
<el-col :span="12">
<label class="input-label">数量</label>
<el-input-number v-model="form.entryQuantity" :min="1" style="width: 90%;"></el-input-number>
</el-col>
</el-row>
<!-- 入库方式 -->
<el-row>
<el-col :span="24">
<label class="input-label">入库方式</label>
<el-radio-group v-model="form.entryMethod" style="display: block; margin-bottom: 20px;">
<el-radio label="采购入库" class="item">采购入库</el-radio><br>
<el-radio label="盘点入库">盘点入库</el-radio>
</el-radio-group>
</el-col>
</el-row>
<!-- 标题和分割线 -->
<div class="header-wrapper">
<h3 class="input-label">入库审批</h3>
<div class="sep-wrapper">
<div class="sep-label"></div>
<div class="sep-bg"></div>
</div>
</div>
<!-- 审批时间 -->
<el-row>
<el-col :span="12">
<label class="input-label">审批时间</label>
<el-date-picker v-model="form.approvalDate" type="date" placeholder="选择日期" style="width: 90%;"></el-date-picker>
</el-col>
<el-col :span="12">
<label class="input-label">是否入库合格</label>
<el-radio-group v-model="form.isQualified" style="display: block; margin-bottom: 20px;">
<el-radio label="合格" class="item">合格</el-radio><br>
<el-radio label="不合格">不合格</el-radio>
</el-radio-group>
</el-col>
</el-row>
</el-form>
<!-- 提交和保存草稿按钮 -->
<div class="button-container">
<el-button type="primary" @click="submitForm" style="margin-right: 20px;">提交</el-button>
<el-button @click="saveDraft">保存草稿</el-button>
</div>
</div>
</template>
<script>
import { ElMessageBox } from 'element-plus';
import { addEntry } from '@/api/system/material/entry';
import { listMaterial } from '@/api/system/material/material';
export default {
data() {
return {
form: {
entryDate: '',
entryPerson: '',
itemType: '',
itemName: '',
unit: '',
entryQuantity: 1,
entryMethod: '采购入库',
approvalDate: '',
isQualified: '合格'
},
itemTypes: ['办公家具', '办公设备', '日杂百货'],
itemNames: [],
materials: []
};
},
methods: {
submitForm() {
try {
addEntry(this.form).then(response => {
ElMessageBox.alert('提交成功', '提示', {
confirmButtonText: '确定',
callback: action => {
// 提交成功后清空草稿
localStorage.removeItem('materialApplyDraft');
this.$message.info('草稿已清空');
// 重置表单
this.resetForm();
}
});
}).catch(error => {
ElMessageBox.alert('提交失败', '提示', {
confirmButtonText: '确定',
callback: action => {}
});
});
} catch (error) {
ElMessageBox.alert('提交失败', '提示', {
confirmButtonText: '确定',
callback: action => {}
});
}
},
resetForm() {
this.form = {
entryDate: '',
entryPerson: '',
itemType: '',
itemName: '',
unit: '',
entryQuantity: 1,
entryMethod: '采购入库',
approvalDate: '',
isQualified: '合格'
};
this.itemNames = [];
},
saveDraft() {
// 保存草稿到本地存储
localStorage.setItem('materialApplyDraft', JSON.stringify(this.form));
this.$message.info('草稿已保存');
},
fetchMaterials() {
listMaterial().then(response => {
console.log('Response:', response); // 添加调试信息
if (response && response.code === 200) {
if (Array.isArray(response.rows)) { // 直接检查 response.rows
this.materials = response.rows; // 确保正确赋值
this.updateItemNames(); // 确保在材料加载后更新物品名称
} else {
this.$message.error('获取物品信息失败: 返回数据格式不正确');
}
} else {
this.$message.error('获取物品信息失败: ' + response.msg);
}
}).catch(error => {
this.$message.error('获取物品信息失败: ' + error.message);
});
},
updateItemNames() {
if (this.form.itemType) {
this.itemNames = this.materials
.filter(material => material.itemType === this.form.itemType)
.map(material => material.itemName);
} else {
this.itemNames = [];
}
},
onItemTypeChange(newItemType) {
this.form.itemType = newItemType;
this.form.itemName = ''; // 清空物品名称
this.form.unit = ''; // 清空单位
this.updateItemNames(); // 更新物品名称选项
},
updateUnitBasedOnItemName() {
const selectedItem = this.materials.find(material =>
material.itemType === this.form.itemType &&
material.itemName === this.form.itemName
);
if (selectedItem) {
this.form.unit = selectedItem.unit;
} else {
this.form.unit = '';
}
}
},
watch: {
'form.itemType': {
handler(newItemType) {
this.form.itemName = ''; // 清空物品名称
this.form.unit = ''; // 清空单位
this.updateItemNames();
},
immediate: true
},
'form.itemName': {
handler(newItemName) {
this.updateUnitBasedOnItemName();
},
immediate: true
}
},
created() {
// 加载草稿
const draft = localStorage.getItem('materialApplyDraft');
if (draft) {
this.form = JSON.parse(draft);
this.$message.info('已加载草稿');
this.resetForm();
}
// 获取物品信息
this.fetchMaterials();
}
};
</script>
<style scoped>
.form-container {
padding-left: 40px;
}
.input-label {
display: block;
font-weight: bold;
margin-bottom: 10px;
}
/* 分割线样式 */
.sep-label {
border-radius: 0 8px;
width: 110px;
height: 12px;
overflow: hidden;
position: relative;
background-color: rgb(0, 137, 127);
}
.sep-bg {
width: 90%;
border-bottom: 4px solid;
border-color: rgb(0, 137, 127);
height: 2px;
opacity: .2;
margin-top: 6px; /* 调整此值以适应布局 */
}
.sep-wrapper {
display: flex;
align-items: center; /* 垂直居中 */
}
.header-wrapper {
margin-bottom: 20px;
}
/* 增加行间距 */
.el-row + .el-row {
margin-top: 10px;
}
.item {
margin-bottom: 10px; /* 设置你想要的间隔大小 */
}
.button-container {
text-align: left; /* 左对齐按钮 */
margin-top: 20px; /* 确保有足够的顶部间距 */
}
</style>
<template>
<div class="form-container">
<!-- 标题和分割线 -->
<div class="header-wrapper">
<h3 class="input-label">物品归还</h3>
<div class="sep-wrapper">
<div class="sep-label"></div>
<div class="sep-bg"></div>
</div>
</div>
<el-form :model="form" :rules="rules" ref="form" label-width="80px">
<el-row>
<el-col :span="24">
<label class="input-label">归还日期</label>
<el-date-picker v-model="form.returnDate" type="date" placeholder="选择日期" style="width: 90%;"></el-date-picker>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">归还人</label>
<el-input v-model="form.returner" placeholder="请输入归还人" style="width: 90%;"></el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">所在部门</label>
<el-input v-model="form.department" placeholder="请输入所在部门" style="width: 90%;"></el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">领用归还明细</label>
<el-table :data="form.items" border style="width: 90%">
<el-table-column label="序号" width="60" align="center">
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="选择归还物品" width="170">
<template #default="scope">
<el-button type="text" @click="openItemSelectDialog(scope.$index)">选择数据</el-button>
</template>
</el-table-column>
<el-table-column prop="type" label="物品类型" width="170">
<template #default="scope">
<el-input v-model="scope.row.itemType" placeholder="请输入物品类型"></el-input>
</template>
</el-table-column>
<el-table-column prop="name" label="物品名称" width="170">
<template #default="scope">
<el-input v-model="scope.row.itemName" placeholder="请输入物品名称"></el-input>
</template>
</el-table-column>
<el-table-column prop="unit" label="单位" width="130">
<template #default="scope">
<el-input v-model="scope.row.unit" placeholder="请输入单位"></el-input>
</template>
</el-table-column>
<el-table-column prop="pendingReturn" label="待归还数量" width="170">
<template #default="scope">
<el-input v-model.number="scope.row.pendingReturn" placeholder="请输入待归还数量"></el-input>
</template>
</el-table-column>
<el-table-column prop="returnQuantity" label="归还数量" width="170">
<template #default="scope">
<el-input-number v-model.number="scope.row.returnQuantity" :min="0" :max="scope.row.pendingReturn" placeholder="请输入归还数量" style="width: 100%;"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="remainingReturn" label="剩余归还数量" width="180">
<template #default="scope">
<el-input v-model.number="scope.row.remainingReturn" placeholder="自动计算" readonly></el-input>
</template>
</el-table-column>
</el-table>
<el-button type="text" @click="addItem" class="custom-text-button">+ 添加</el-button>
<el-button type="text" @click="pasteItem" class="custom-text-button">+ 粘贴新增</el-button>
</el-col>
</el-row>
<!-- 标题和分割线 -->
<div class="header-wrapper">
<h3 class="input-label">归还入库审批</h3>
<div class="sep-wrapper">
<div class="sep-label"></div>
<div class="sep-bg"></div>
</div>
</div>
<!-- 审批时间 -->
<el-row>
<el-col :span="12">
<label class="input-label">审批时间</label>
<el-date-picker v-model="form.approvalDate" type="date" placeholder="选择日期" style="width: 90%;"></el-date-picker>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">审批结果</label>
<el-radio-group v-model="form.approvalResult">
<div class="radio-item">
<el-radio label="通过" class="pass"><span class="radio-label">通过</span></el-radio><br>
<el-radio label="不通过" class="unpass"><span class="radio-label">不通过</span></el-radio>
</div>
</el-radio-group>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<label class="input-label">不通过原因</label>
<el-input type="textarea" v-model="form.approvalReason" placeholder="请输入原因" style="width: 70%;" class="custom-textarea"></el-input>
</el-col>
</el-row>
</el-form>
<!-- 提交和保存草稿按钮 -->
<div class="button-container">
<el-button type="primary" @click="submitForm" style="margin-right: 20px;">提交</el-button>
<el-button @click="saveDraft">保存草稿</el-button>
</div>
<!-- 选择数据弹窗 -->
<el-dialog title="选择数据" v-model="showItemSelectDialog" width="50%">
<div style="display: flex; justify-content: flex-end;">
<el-input v-model="searchQuery" placeholder="搜索数据" style="margin-bottom: 10px;width: 200px;"></el-input>
</div>
<el-table :data="filteredItems" border style="width: 100%">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="applicant" label="申请人" width="150"></el-table-column>
<el-table-column prop="itemName" label="物品名称" width="150"></el-table-column>
<el-table-column prop="itemType" label="物品类型" width="150"></el-table-column>
<el-table-column prop="itemUnit" label="单位" width="150"></el-table-column>
<el-table-column prop="quantity" label="待归还数量" width="150"></el-table-column>
</el-table>
</el-dialog>
</div>
</template>
<script>
import { addReturn, updateReturn } from '@/api/system/material/return';
import { listApply } from '@/api/system/material/apply';
import { ElMessageBox } from 'element-plus';
export default {
data() {
return {
form: {
returnDate: '',
returner: '',
department: '',
items: [
{ item: '', itemType: '', itemName: '', unit: '', pendingReturn: 0, returnQuantity: 0, remainingReturn: 0 }
],
approvalResult: '通过',
approvalReason: ''
},
showPasteDialog: false,
editingId: null, // 用于存储正在编辑的归还ID
showItemSelectDialog: false,
searchQuery: '',
itemsList: [],
selectedRowIndex: -1,
rules: {
returnDate: [
{ required: true, message: '请选择归还日期', trigger: 'change' }
],
returner: [
{ required: true, message: '请输入归还人', trigger: 'blur' }
],
department: [
{ required: true, message: '请输入所在部门', trigger: 'blur' }
],
approvalResult: [
{ required: true, message: '请选择审批结果', trigger: 'change' }
]
}
};
},
methods: {
addItem() {
this.form.items.push({
item: '',
itemType: '',
itemName: '',
unit: '',
pendingReturn: 0,
returnQuantity: 0,
remainingReturn: 0
});
},
pasteItem() {
// 实现粘贴新增逻辑
this.showPasteDialog = true;
},
submitForm() {
this.$refs.form.validate(valid => {
if (valid) {
const data = {
...this.form,
items: JSON.stringify(this.form.items)
};
if (this.editingId) {
// 更新现有归还申请
updateReturn(data).then(response => {
ElMessageBox.alert('归还申请更新成功', '提示', {
confirmButtonText: '确定',
callback: action => {
this.$message.success('归还申请更新成功');
this.resetForm();
}
});
}).catch(error => {
ElMessageBox.alert('归还申请更新失败', '提示', {
confirmButtonText: '确定',
callback: action => {
this.$message.error('归还申请更新失败: ' + error.message);
}
});
});
} else {
// 新增归还申请
addReturn(data).then(response => {
ElMessageBox.alert('归还申请提交成功', '提示', {
confirmButtonText: '确定',
callback: action => {
this.$message.success('归还申请提交成功');
this.resetForm();
}
});
}).catch(error => {
ElMessageBox.alert('归还申请提交失败', '提示', {
confirmButtonText: '确定',
callback: action => {
this.$message.error('归还申请提交失败: ' + error.message);
}
});
});
}
} else {
this.$message.error('请检查表单填写是否正确');
}
});
},
saveDraft() {
// 保存草稿到本地存储
localStorage.setItem('materialReturnDraft', JSON.stringify(this.form));
this.$message.info('草稿已保存');
},
updateRemaining(index) {
const item = this.form.items[index];
item.remainingReturn = item.pendingReturn - item.returnQuantity;
},
resetForm() {
this.form = {
returnDate: '',
returner: '',
department: '',
items: [
{ item: '', itemType: '', itemName: '', unit: '', pendingReturn: 0, returnQuantity: 0, remainingReturn: 0 }
],
approvalResult: '通过',
approvalReason: ''
};
this.editingId = null;
this.$refs.form.resetFields();
},
openItemSelectDialog(index) {
this.selectedRowIndex = index;
// 去掉 fetchItems 调用
this.showItemSelectDialog = true;
}
},
created() {
// 加载草稿
const draft = localStorage.getItem('materialReturnDraft');
if (draft) {
this.form = JSON.parse(draft);
this.$message.info('已加载草稿');
}
},
watch: {
'form.items': {
handler(newItems) {
newItems.forEach((item, index) => {
this.updateRemaining(index);
});
},
deep: true
}
},
computed: {
filteredItems() {
return this.itemsList.filter(item =>
item.applicant.includes(this.searchQuery) ||
item.itemName.includes(this.searchQuery) ||
item.itemType.includes(this.searchQuery) ||
item.unit.includes(this.searchQuery)
);
}
}
};
</script>
<style scoped>
/* 增加左边距 */
.form-container {
padding-left: 40px; /* 调整这个值以适应你的需求 */
}
.input-label {
display: block;
font-weight: bold;
margin-bottom: 10px;
}
/* 分割线样式 */
.sep-label {
border-radius: 0 8px;
width: 110px;
height: 12px;
overflow: hidden;
position: relative;
background-color: rgb(0, 137, 127);
}
.sep-bg {
width: 90%;
border-bottom: 4px solid;
border-color: rgb(0, 137, 127);
height: 2px;
opacity: .2;
margin-top: 6px; /* 调整此值以适应布局 */
}
.sep-wrapper {
display: flex;
align-items: center; /* 垂直居中 */
}
.header-wrapper {
margin-bottom: 20px;
}
/* 自定义文本按钮样式 */
.custom-text-button {
color: rgb(0, 137, 127);
margin-right: 10px;
}
.radio-item {
margin-bottom: 20px; /* 设置你想要的间隔大小 */
}
.pass .radio-label {
color: white;
background-color: #38b654;
padding: 5px 10px;
border-radius: 4px;
}
.unpass .radio-label {
color: white;
background-color: #fa575b;
padding: 5px 10px;
border-radius: 4px;
}
.custom-textarea {
margin-bottom: 10px;
height: 150px; /* 根据需要调整 */
}
/* 确保textarea内部的文字布局合理 */
.custom-textarea >>> .el-textarea__inner {
height: 100%;
line-height: normal;
padding: 10px; /* 可根据实际需求调整 */
box-sizing: border-box;
}
/* 增加行间距 */
.el-row + .el-row {
margin-top: 10px;
}
/* 提交和保存草稿按钮样式 */
.button-container {
text-align: left; /* 左对齐按钮 */
margin-top: 20px; /* 确保有足够的顶部间距 */
margin-bottom: 40px; /* 页面底部留出间隔 */
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment