Merge branch 'dev_New' of http://114.132.189.42:9002/r/product-inventory-management into dev_New
| | |
| | | data: query, |
| | | }); |
| | | } |
| | | // 修改发货台账 |
| | | export function deductStock(query) { |
| | | return request({ |
| | | url: "/shippingInfo/deductStock", |
| | | method: "post", |
| | | data: query, |
| | | }); |
| | | } |
| | | |
| | | // 删除发货台账 |
| | | export function delDeliveryLedger(query) { |
| | |
| | | </div> |
| | | |
| | | <!-- 新增/编辑知识弹窗 --> |
| | | <el-dialog |
| | | <FormDialog |
| | | v-model="dialogVisible" |
| | | :title="dialogTitle" |
| | | width="800px" |
| | | :close-on-click-modal="false" |
| | | :width="'800px'" |
| | | @close="closeKnowledgeDialog" |
| | | @confirm="submitForm" |
| | | @cancel="closeKnowledgeDialog" |
| | | > |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="创建人" prop="creator"> |
| | | <el-input v-model="form.creator" placeholder="请输入创建人" /> |
| | | <el-select v-model="form.creator" placeholder="请选择创建人" style="width: 100%" filterable> |
| | | <el-option |
| | | v-for="user in userList" |
| | | :key="user.userId" |
| | | :label="user.nickName" |
| | | :value="user.nickName" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">取消</el-button> |
| | | <el-button type="primary" @click="submitForm">确定</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | |
| | | <!-- 查看知识详情弹窗 --> |
| | | <el-dialog |
| | | <FormDialog |
| | | v-model="viewDialogVisible" |
| | | title="知识详情" |
| | | width="900px" |
| | | :close-on-click-modal="false" |
| | | :width="'900px'" |
| | | @close="closeViewDialog" |
| | | @confirm="handleViewDialogConfirm" |
| | | @cancel="closeViewDialog" |
| | | > |
| | | <div class="knowledge-detail"> |
| | | <el-descriptions :column="2" border> |
| | |
| | | <h4>关键要点</h4> |
| | | <div class="key-points"> |
| | | <el-tag |
| | | v-for="(point, index) in currentKnowledge.keyPoints.split(',')" |
| | | v-for="(point, index) in currentKnowledge.keyPoints?.split(',') || []" |
| | | :key="index" |
| | | type="success" |
| | | style="margin-right: 8px; margin-bottom: 8px;" |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="viewDialogVisible = false">关闭</el-button> |
| | | <el-button type="primary" @click="copyKnowledge">复制知识</el-button> |
| | | <!-- <el-button type="success" @click="markAsFavorite">收藏@</el-button> --> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { onMounted, ref, reactive, toRefs, getCurrentInstance, computed } from "vue"; |
| | | import { onMounted, ref, reactive, toRefs, getCurrentInstance, computed, watch } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue'; |
| | | import { listKnowledgeBase, delKnowledgeBase,addKnowledgeBase,updateKnowledgeBase } from "@/api/collaborativeApproval/knowledgeBase.js"; |
| | | import useUserStore from '@/store/modules/user'; |
| | | import { userListNoPageByTenantId } from '@/api/system/user.js'; |
| | | |
| | | // 表单验证规则 |
| | | const rules = { |
| | |
| | | |
| | | // 表单引用 |
| | | const formRef = ref(); |
| | | // 用户相关 |
| | | const userStore = useUserStore(); |
| | | const userList = ref([]); |
| | | |
| | | // 表格列配置 |
| | | const tableColumn = ref([ |
| | |
| | | } |
| | | ]); |
| | | |
| | | // 监听对话框打开,获取用户列表 |
| | | watch(dialogVisible, (newVal) => { |
| | | if (newVal) { |
| | | userListNoPageByTenantId().then((res) => { |
| | | userList.value = res.data || []; |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | // 生命周期 |
| | | onMounted(() => { |
| | | getList(); |
| | |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records |
| | | page.total = res.data.total; |
| | | page.value.total = res.data.total; |
| | | }).catch(err => { |
| | | tableLoading.value = false; |
| | | }) |
| | |
| | | dialogType.value = type; |
| | | if (type === "add") { |
| | | dialogTitle.value = "新增知识"; |
| | | // 重置表单 |
| | | // 重置表单,默认创建人为当前用户 |
| | | Object.assign(form.value, { |
| | | title: "", |
| | | type: "", |
| | |
| | | problem: "", |
| | | solution: "", |
| | | keyPoints: "", |
| | | creator: "", |
| | | creator: userStore.nickName || "", |
| | | usageCount: 0 |
| | | }); |
| | | } else if (type === "edit" && row) { |
| | |
| | | }); |
| | | }; |
| | | |
| | | // 关闭知识表单对话框 |
| | | const closeKnowledgeDialog = () => { |
| | | // 清空表单数据,默认创建人为当前用户 |
| | | Object.assign(form.value, { |
| | | id: undefined, |
| | | title: "", |
| | | type: "", |
| | | scenario: "", |
| | | efficiency: "", |
| | | problem: "", |
| | | solution: "", |
| | | keyPoints: "", |
| | | creator: userStore.nickName || "", |
| | | usageCount: 0 |
| | | }); |
| | | // 清除表单验证状态 |
| | | if (formRef.value) { |
| | | formRef.value.clearValidate(); |
| | | } |
| | | dialogVisible.value = false; |
| | | }; |
| | | |
| | | // 关闭查看详情对话框 |
| | | const closeViewDialog = () => { |
| | | viewDialogVisible.value = false; |
| | | }; |
| | | |
| | | // 处理查看详情对话框确认(执行复制操作) |
| | | const handleViewDialogConfirm = () => { |
| | | copyKnowledge(); |
| | | closeViewDialog(); |
| | | }; |
| | | |
| | | // 提交知识表单 |
| | | const submitForm = async () => { |
| | | try { |
| | |
| | | addKnowledgeBase({...form.value}).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("添加成功"); |
| | | dialogVisible.value = false; |
| | | closeKnowledgeDialog(); |
| | | getList(); |
| | | } |
| | | }).catch(err => { |
| | |
| | | updateKnowledgeBase({...form.value}).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("更新成功"); |
| | | dialogVisible.value = false; |
| | | closeKnowledgeDialog(); |
| | | getList(); |
| | | } |
| | | }).catch(err => { |
| | |
| | | <el-option |
| | | v-for="person in employees" |
| | | :key="person.id" |
| | | :label="`${person.staffName} (${person.postName})`" |
| | | :label="`${person.staffName}${person.postName ? ` (${person.postName})` : ''}`" |
| | | :value="person.id" |
| | | /> |
| | | </el-select> |
| | |
| | | size: -1, |
| | | staffState: 1 |
| | | }).then(res => { |
| | | employees.value = res.data.records.sort((a, b) => a.postName.localeCompare(b.postName)) |
| | | employees.value = res.data.records.sort((a, b) => (a.postName || '').localeCompare(b.postName || '')) |
| | | }) |
| | | }) |
| | | </script> |
| | |
| | | it.participants = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postName})` |
| | | name: `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}` |
| | | } |
| | | }) |
| | | |
| | |
| | | it.participants = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postName})` |
| | | name: `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}` |
| | | } |
| | | }) |
| | | |
| | |
| | | it.participants = staffList.value.filter(staff => staffs.some(id => id === staff.id)).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postName})` |
| | | name: `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}` |
| | | } |
| | | }) |
| | | |
| | |
| | | </el-card> |
| | | |
| | | <!-- 用印申请对话框 --> |
| | | <el-dialog v-model="showSealApplyDialog" title="申请用印" width="600px"> |
| | | <FormDialog |
| | | v-model="showSealApplyDialog" |
| | | title="申请用印" |
| | | :width="'600px'" |
| | | @close="closeSealApplyDialog" |
| | | @confirm="submitSealApplication" |
| | | @cancel="closeSealApplyDialog" |
| | | > |
| | | <el-form :model="sealForm" :rules="sealRules" ref="sealFormRef" label-width="100px"> |
| | | <el-form-item label="申请编号" prop="applicationNum"> |
| | | <el-input v-model="sealForm.applicationNum" placeholder="请输入申请编号" /> |
| | |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="showSealApplyDialog = false">取消</el-button> |
| | | <el-button type="primary" @click="submitSealApplication">提交申请</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | |
| | | <!-- 规章制度发布对话框 --> |
| | | <!-- <el-dialog v-model="showRegulationDialog" :title="operationType === 'add' ? '发布制度' : '编辑制度'" width="800px"> |
| | |
| | | </el-dialog> --> |
| | | |
| | | <!-- 用印详情对话框 --> |
| | | <el-dialog v-model="showSealDetailDialog" title="用印申请详情" width="700px"> |
| | | <FormDialog |
| | | v-model="showSealDetailDialog" |
| | | title="用印申请详情" |
| | | :width="'700px'" |
| | | @close="closeSealDetailDialog" |
| | | @confirm="closeSealDetailDialog" |
| | | @cancel="closeSealDetailDialog" |
| | | > |
| | | <div v-if="currentSealDetail" class="mb10"> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="申请编号">{{ currentSealDetail.id }}</el-descriptions-item> |
| | | <el-descriptions-item label="申请编号">{{ currentSealDetail.applicationNum }}</el-descriptions-item> |
| | | <el-descriptions-item label="申请标题">{{ currentSealDetail.title }}</el-descriptions-item> |
| | | <el-descriptions-item label="申请人">{{ currentSealDetail.createUserName }}</el-descriptions-item> |
| | | <el-descriptions-item label="所属部门">{{ currentSealDetail.department }}</el-descriptions-item> |
| | |
| | | <el-descriptions-item label="申请原因" :span="2">{{ currentSealDetail.reason }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | |
| | | <!-- 规章制度详情对话框 --> |
| | | <el-dialog v-model="showRegulationDetailDialog" title="规章制度详情" width="800px"> |
| | | <FormDialog |
| | | v-model="showRegulationDetailDialog" |
| | | title="规章制度详情" |
| | | :width="'800px'" |
| | | @close="closeRegulationDetailDialog" |
| | | @confirm="handleRegulationDetailConfirm" |
| | | @cancel="closeRegulationDetailDialog" |
| | | > |
| | | <div v-if="currentRegulationDetail"> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="制度编号">{{ currentRegulationDetail.id }}</el-descriptions-item> |
| | |
| | | <el-button type="success" @click="resetForm(currentRegulationDetail)">确认查看</el-button> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | |
| | | <!-- 版本历史对话框 --> |
| | | <el-dialog v-model="showVersionHistoryDialog" title="版本历史" width="800px"> |
| | | <FormDialog |
| | | v-model="showVersionHistoryDialog" |
| | | title="版本历史" |
| | | :width="'800px'" |
| | | @close="closeVersionHistoryDialog" |
| | | @confirm="closeVersionHistoryDialog" |
| | | @cancel="closeVersionHistoryDialog" |
| | | > |
| | | <el-table :data="versionHistory" style="width: 100%;margin-bottom: 10px"> |
| | | <el-table-column prop="version" label="版本号" width="100" /> |
| | | <el-table-column prop="updateTime" label="更新时间" width="180" /> |
| | |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | |
| | | <!-- 阅读状态对话框 --> |
| | | <el-dialog v-model="showReadStatusDialog" title="阅读状态" width="800px"> |
| | | <FormDialog |
| | | v-model="showReadStatusDialog" |
| | | title="阅读状态" |
| | | :width="'800px'" |
| | | @close="closeReadStatusDialog" |
| | | @confirm="closeReadStatusDialog" |
| | | @cancel="closeReadStatusDialog" |
| | | > |
| | | <el-table :data="readStatusList" style="width: 100%;margin-bottom: 10px"> |
| | | <el-table-column prop="employee" label="员工姓名" width="120" /> |
| | | <el-table-column prop="department" label="所属部门" width="150" /> |
| | |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { getUserProfile, userListNoPageByTenantId } from '@/api/system/user.js' |
| | | import useUserStore from '@/store/modules/user' |
| | | import { userLoginFacotryList } from "@/api/system/user.js" |
| | | import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js"; |
| | | import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js" |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue' |
| | | |
| | | // 响应式数据 |
| | | const currentUser = ref(null) |
| | |
| | | addSealApplication(sealForm).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success('申请提交成功') |
| | | showSealApplyDialog.value = false |
| | | closeSealApplyDialog() |
| | | getSealApplicationList() |
| | | Object.assign(sealForm, { |
| | | applicationNum: '', |
| | |
| | | }) |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg) |
| | | console.log(err.msg) |
| | | }) |
| | | |
| | | } catch (error) { |
| | | ElMessage.error('请完善申请信息') |
| | | } |
| | | } |
| | | // 关闭用印申请对话框 |
| | | const closeSealApplyDialog = () => { |
| | | // 清空表单数据 |
| | | Object.assign(sealForm, { |
| | | applicationNum: '', |
| | | title: '', |
| | | sealType: '', |
| | | reason: '', |
| | | approveUserId: '', |
| | | urgency: 'normal', |
| | | status: 'pending' |
| | | }) |
| | | // 清除表单验证状态 |
| | | if (sealFormRef.value) { |
| | | sealFormRef.value.clearValidate() |
| | | } |
| | | showSealApplyDialog.value = false |
| | | } |
| | | // 关闭用印详情对话框 |
| | | const closeSealDetailDialog = () => { |
| | | showSealDetailDialog.value = false |
| | | } |
| | | // 关闭规章制度详情对话框 |
| | | const closeRegulationDetailDialog = () => { |
| | | showRegulationDetailDialog.value = false |
| | | } |
| | | // 处理规章制度详情确认 |
| | | const handleRegulationDetailConfirm = () => { |
| | | // 如果tableData>0,执行确认查看操作 |
| | | if (currentRegulationDetail.value && tableData.value && tableData.value.length > 0) { |
| | | resetForm(currentRegulationDetail.value) |
| | | } |
| | | closeRegulationDetailDialog() |
| | | } |
| | | // 关闭版本历史对话框 |
| | | const closeVersionHistoryDialog = () => { |
| | | showVersionHistoryDialog.value = false |
| | | } |
| | | // 关闭阅读状态对话框 |
| | | const closeReadStatusDialog = () => { |
| | | showReadStatusDialog.value = false |
| | | } |
| | | // 新增 |
| | | const handleAdd = () => { |
| | |
| | | }) |
| | | } |
| | | |
| | | // 分页变化处理 |
| | | const paginationChange = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getSealApplicationList(); |
| | | }; |
| | | |
| | | // 监听对话框打开,获取用户列表 |
| | | watch(showSealApplyDialog, (newVal) => { |
| | | if (newVal) { |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">生产日期:</span> |
| | | <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" |
| | | placeholder="请选择" clearable @change="changeDaterange" /> |
| | | <span class="search_title ml10">生产人:</span> |
| | | <el-input |
| | | v-model="searchForm.schedulingUserName" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | @change="handleQuery" |
| | | clearable |
| | | prefix-icon="Search" |
| | | /> |
| | | <span class="search_title ml10">合同号:</span> |
| | | <el-input |
| | | v-model="searchForm.salesContractNo" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | @change="handleQuery" |
| | | clearable |
| | | prefix-icon="Search" |
| | | /> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >搜索</el-button |
| | | > |
| | | <div class="content-layout"> |
| | | <!-- 左侧台账 + 顶部筛选 --> |
| | | <div class="left-panel"> |
| | | <div class="left-header"> |
| | | <!-- <div class="left-title">生产台账</div> --> |
| | | <el-radio-group v-model="dateType" size="small" @change="handleDateTypeChange"> |
| | | <el-radio-button label="day">日</el-radio-button> |
| | | <el-radio-button label="month">月</el-radio-button> |
| | | </el-radio-group> |
| | | |
| | | </div> |
| | | <div> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="leftTableColumn" |
| | | :tableData="leftTableData" |
| | | :tableLoading="tableLoading" |
| | | @rowClick="handleLeftRowClick" |
| | | ></PIMTable> |
| | | </div> |
| | | |
| | | <!-- 右侧明细(原有内容) --> |
| | | <div class="right-panel"> |
| | | <div class="header-filters"> |
| | | <el-button @click="handleOut" class="ml10">导出</el-button> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :tableLoading="tableLoading" |
| | | style="margin-right: 20px;" |
| | | @pagination="pagination" |
| | | ></PIMTable> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | width: 100, |
| | | }, |
| | | ]); |
| | | |
| | | // 左侧汇总台账列(生产人、产量、工资、合格率) |
| | | const leftTableColumn = ref([ |
| | | { |
| | | label: "生产人", |
| | | prop: "schedulingUserName", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "产量", |
| | | prop: "finishedNum", |
| | | width: 100, |
| | | }, |
| | | { |
| | | label: "工资", |
| | | prop: "wages", |
| | | width: 100, |
| | | }, |
| | | { |
| | | label: "合格率", |
| | | prop: "qualifiedRate", |
| | | width: 100, |
| | | }, |
| | | ]); |
| | | |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const leftTableData = ref([]); |
| | | // 日 / 月 切换(默认按日) |
| | | const dateType = ref("day"); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const params = { ...searchForm.value, ...page }; |
| | | params.dateType = dateType.value; |
| | | params.entryDate = undefined |
| | | productionAccountingListPage(params).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | const records = res.data.records || []; |
| | | tableData.value = records; |
| | | page.total = res.data.total || 0; |
| | | buildLeftTableData(records); |
| | | }); |
| | | }; |
| | | |
| | | // 构建左侧汇总台账(按生产人汇总产量、工资等) |
| | | const buildLeftTableData = (records) => { |
| | | const map = {}; |
| | | records.forEach((item) => { |
| | | const key = item.schedulingUserName || "未知"; |
| | | if (!map[key]) { |
| | | map[key] = { |
| | | id: key, |
| | | schedulingUserName: key, |
| | | finishedNum: 0, |
| | | wages: 0, |
| | | qualifiedRate: item.qualifiedRate ?? null, |
| | | }; |
| | | } |
| | | map[key].finishedNum += Number(item.finishedNum || 0); |
| | | map[key].wages += Number(item.wages || 0); |
| | | if (item.qualifiedRate != null) { |
| | | map[key].qualifiedRate = item.qualifiedRate; |
| | | } |
| | | }); |
| | | leftTableData.value = Object.values(map); |
| | | }; |
| | | |
| | | // 左侧日/月切换 |
| | | const handleDateTypeChange = () => { |
| | | // 这里只作为筛选条件的一部分,直接重新查询列表 |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // 点击左侧行,刷右侧明细(按生产人过滤) |
| | | const handleLeftRowClick = (row) => { |
| | | searchForm.value.schedulingUserName = row.schedulingUserName || ""; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // 导出 |
| | |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
| | | <style scoped lang="scss"> |
| | | .content-layout { |
| | | display: flex; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .left-panel { |
| | | flex: 0 0 50%; |
| | | max-width: 50%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .right-panel { |
| | | flex: 0 0 50%; |
| | | max-width: 49%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .left-header { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .left-title { |
| | | font-size: 16px; |
| | | color: #ffffff; |
| | | } |
| | | |
| | | .header-filters { |
| | | display: flex; |
| | | align-items: center; |
| | | flex: 1; |
| | | justify-content: flex-end; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .search_title { |
| | | color: #ffffff; |
| | | } |
| | | |
| | | .ml10 { |
| | | margin-left: 10px; |
| | | } |
| | | </style> |
| | |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :tableLoading="tableLoading" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="paginationSearch" |
| | | height="500" |
| | | > |
| | | </PIMTable> |
| | | <pagination |
| | | style="margin: 10px 0" |
| | | v-show="total > 0" |
| | | @pagination="paginationSearch" |
| | | :total="total" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="closeDia">取消</el-button> |
| | |
| | | qualityInspectFileDel, |
| | | qualityInspectFileListPage |
| | | } from "@/api/qualityManagement/qualityInspectFile.js"; |
| | | import Pagination from "@/components/PIMTable/Pagination.vue"; |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits(['close']) |
| | | |
| | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const total = ref(0); |
| | | const tableData = ref([]); |
| | | const fileList = ref([]); |
| | | const tableLoading = ref(false); |
| | |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | qualityInspectFileListPage({inspectId: currentId.value}).then(res => { |
| | | qualityInspectFileListPage({inspectId: currentId.value, ...page}).then(res => { |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | page.total = res.data.total; |
| | | }) |
| | | } |
| | | // 表格选择数据 |
| | |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :tableLoading="tableLoading" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="paginationSearch" |
| | | height="500" |
| | | > |
| | | </PIMTable> |
| | | <pagination |
| | | style="margin: 10px 0" |
| | | v-show="total > 0" |
| | | @pagination="paginationSearch" |
| | | :total="total" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="closeDia">取消</el-button> |
| | |
| | | qualityInspectFileDel, |
| | | qualityInspectFileListPage |
| | | } from "@/api/qualityManagement/qualityInspectFile.js"; |
| | | import Pagination from "@/components/PIMTable/Pagination.vue"; |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits(['close']) |
| | | |
| | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const total = ref(0); |
| | | const tableData = ref([]); |
| | | const fileList = ref([]); |
| | | const tableLoading = ref(false); |
| | |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | qualityInspectFileListPage({inspectId: currentId.value}).then(res => { |
| | | qualityInspectFileListPage({inspectId: currentId.value, ...page}).then(res => { |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | page.total = res.data.total; |
| | | }) |
| | | } |
| | | // 表格选择数据 |
| | |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :tableLoading="tableLoading" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="paginationSearch" |
| | | height="500" |
| | | > |
| | | </PIMTable> |
| | | <pagination |
| | | style="margin: 10px 0" |
| | | v-show="total > 0" |
| | | @pagination="paginationSearch" |
| | | :total="total" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="closeDia">取消</el-button> |
| | |
| | | qualityInspectFileDel, |
| | | qualityInspectFileListPage |
| | | } from "@/api/qualityManagement/qualityInspectFile.js"; |
| | | import Pagination from "@/components/PIMTable/Pagination.vue"; |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits(['close']) |
| | | |
| | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const total = ref(0); |
| | | const tableData = ref([]); |
| | | const fileList = ref([]); |
| | | const tableLoading = ref(false); |
| | |
| | | const getList = () => { |
| | | qualityInspectFileListPage({inspectId: currentId.value, ...page}).then(res => { |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | page.total = res.data.total; |
| | | }) |
| | | } |
| | | // 表格选择数据 |
| | |
| | | <template> |
| | | <div> |
| | | <PanelHeader title="产品采购金额分析" /> |
| | | <PanelHeader title="采购品分布" /> |
| | | <div class="main-panel panel-item-customers"> |
| | | <CarouselCards :items="cardItems" :visible-count="3" /> |
| | | <div class="pie-chart-wrapper"> |
| | |
| | | <template> |
| | | <div> |
| | | <PanelHeader title="产品销售金额分析" /> |
| | | <PanelHeader title="销售品分布" /> |
| | | <div class="main-panel panel-item-customers"> |
| | | <CarouselCards :items="cardItems" :visible-count="3" /> |
| | | <div class="pie-chart-wrapper"> |
| | |
| | | <template> |
| | | <div> |
| | | <PanelHeader title="客户金额贡献排名" /> |
| | | <PanelHeader title="客户贡献排名" /> |
| | | <div class="panel-item-customers"> |
| | | <div class="switch-container"> |
| | | <DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" /> |
| | |
| | | </div> |
| | | <div class="card-right"> |
| | | <div class="metric-row"> |
| | | <span class="metric-label">净利润</span> |
| | | <span class="metric-label">付款率</span> |
| | | <span class="metric-value metric-down">{{ expense.netProfit }}</span> |
| | | </div> |
| | | <div class="metric-row"> |
| | |
| | | type="primary" |
| | | size="small" |
| | | :disabled="isApproving(scope.row.status)" |
| | | @click="openForm('edit', scope.row)">编辑</el-button> |
| | | @click="openForm('edit', scope.row)">补充发货信息</el-button> |
| | | <el-button |
| | | link |
| | | type="danger" |
| | |
| | | import { |
| | | deliveryLedgerListPage, |
| | | addOrUpdateDeliveryLedger, |
| | | delDeliveryLedger, |
| | | delDeliveryLedger, deductStock, |
| | | } from "@/api/salesManagement/deliveryLedger.js"; |
| | | import { delLedgerFile } from "@/api/salesManagement/salesLedger.js"; |
| | | |
| | |
| | | expressNumber: form.value.type === "快递" ? form.value.expressNumber : "", |
| | | tempFileIds: tempFileIds, |
| | | }; |
| | | addOrUpdateDeliveryLedger(payload).then((res) => { |
| | | deductStock(payload).then((res) => { |
| | | proxy.$modal.msgSuccess("操作成功"); |
| | | closeDia(); |
| | | getList(); |
| | |
| | | height="calc(100vh - 22em)" |
| | | > |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column prop="quotationNo" label="报价单号" width="150" /> |
| | | <el-table-column prop="quotationNo" label="报价单号" /> |
| | | <el-table-column prop="customer" label="客户名称" /> |
| | | <el-table-column prop="salesperson" label="业务员" width="100" /> |
| | | <el-table-column prop="quotationDate" label="报价日期" width="120" /> |
| | |
| | | @change="getProductModel($event, scope.row)" |
| | | > |
| | | <el-option |
| | | v-for="item in modelOptions" |
| | | v-for="item in scope.row.modelOptions || []" |
| | | :key="item.id" |
| | | :label="item.model" |
| | | :value="item.id" |
| | |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | | <div style="margin-top: 20px;"> |
| | | <div style="margin: 20px 0;"> |
| | | <h4>产品明细</h4> |
| | | <el-table :data="currentQuotation.products" border style="width: 100%"> |
| | | <el-table-column prop="product" label="产品名称" /> |
| | |
| | | if (!value) { |
| | | row.productId = ''; |
| | | row.product = ''; |
| | | modelOptions.value = []; |
| | | row.modelOptions = []; |
| | | row.specificationId = ''; |
| | | row.specification = ''; |
| | | row.unit = ''; |
| | |
| | | if (label) { |
| | | row.product = label; |
| | | } |
| | | // 获取规格型号列表 |
| | | // 获取规格型号列表,设置到当前行的 modelOptions |
| | | modelList({ id: value }).then((res) => { |
| | | modelOptions.value = res || []; |
| | | row.modelOptions = res || []; |
| | | }); |
| | | }; |
| | | const getProductModel = (value, row) => { |
| | |
| | | } |
| | | // 更新 specificationId(v-model 已经自动更新,这里确保一致性) |
| | | row.specificationId = value; |
| | | const index = modelOptions.value.findIndex((item) => item.id === value); |
| | | const modelOptions = row.modelOptions || []; |
| | | const index = modelOptions.findIndex((item) => item.id === value); |
| | | if (index !== -1) { |
| | | row.specification = modelOptions.value[index].model; |
| | | row.unit = modelOptions.value[index].unit; |
| | | row.specification = modelOptions[index].model; |
| | | row.unit = modelOptions[index].unit; |
| | | } else { |
| | | row.specification = ''; |
| | | row.unit = ''; |
| | |
| | | form.paymentMethod = row.paymentMethod || '' |
| | | form.status = row.status || '草稿' |
| | | form.remark = row.remark || '' |
| | | form.products = row.products ? row.products.map(product => { |
| | | form.products = row.products ? await Promise.all(row.products.map(async (product) => { |
| | | const productName = product.product || product.productName || '' |
| | | // 优先用 productId;如果只有名称,尝试反查 id 以便树选择器反显 |
| | | const resolvedId = product.productId |
| | | const resolvedProductId = product.productId |
| | | ? Number(product.productId) |
| | | : findNodeIdByLabel(productOptions.value, productName) || '' |
| | | |
| | | // 如果有产品ID,加载对应的规格型号列表 |
| | | let modelOptions = []; |
| | | let resolvedSpecificationId = product.specificationId || ''; |
| | | |
| | | if (resolvedProductId) { |
| | | try { |
| | | const res = await modelList({ id: resolvedProductId }); |
| | | modelOptions = res || []; |
| | | |
| | | // 如果返回的数据没有 specificationId,但有 specification 名称,根据名称查找 ID |
| | | if (!resolvedSpecificationId && product.specification) { |
| | | const foundModel = modelOptions.find(item => item.model === product.specification); |
| | | if (foundModel) { |
| | | resolvedSpecificationId = foundModel.id; |
| | | } |
| | | } |
| | | } catch (error) { |
| | | console.error('加载规格型号失败:', error); |
| | | } |
| | | } |
| | | |
| | | return { |
| | | productId: resolvedId, |
| | | productId: resolvedProductId, |
| | | product: productName, |
| | | specificationId: product.specificationId || '', |
| | | specificationId: resolvedSpecificationId, |
| | | specification: product.specification || '', |
| | | quantity: product.quantity || 0, |
| | | unit: product.unit || '', |
| | | unitPrice: product.unitPrice || 0, |
| | | amount: product.amount || 0 |
| | | amount: product.amount || 0, |
| | | modelOptions: modelOptions // 为每行添加独立的规格型号列表 |
| | | } |
| | | }) : [] |
| | | })) : [] |
| | | form.subtotal = row.subtotal || 0 |
| | | form.freight = row.freight || 0 |
| | | form.otherFee = row.otherFee || 0 |
| | |
| | | quantity: 1, |
| | | unit: '', |
| | | unitPrice: 0, |
| | | amount: 0 |
| | | amount: 0, |
| | | modelOptions: [] // 为每行添加独立的规格型号列表 |
| | | }) |
| | | } |
| | | |