fix: 0.1.1 修正问题如下:

1. 修正了部分开发页面以及开源时的展示问题。
2. 修正了成品入库单模块出货功能行选择框缓存没清除的问题。
3. 修正了角色管理级联选中问题。
4. 修正了表格行按钮的宽度不够展示不全的问题。
5. 对 Excel 解析进行了兼容。
This commit is contained in:
c
2026-04-03 14:46:13 +08:00
parent cc87985576
commit ac3756f199
17 changed files with 81 additions and 105 deletions

21
LICENSE
View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 Brian Liu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,10 +1,9 @@
{ {
"name": "erp-frontend", "name": "erp-frontend",
"version": "2.0.0", "version": "0.1.1",
"private": true, "private": true,
"description": "牛安后台管理系统", "description": "牛安后台管理系统",
"author": "Teeker <2456019588@qq.com>", "author": "Teeker <2456019588@qq.com>",
"license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --mode development", "dev": "vite --mode development",

View File

@@ -40,7 +40,7 @@ export const useStatus = () => {
}; };
const finishedProductReceiptStatusKeyMap: Record<number, string> = { const finishedProductReceiptStatusKeyMap: Record<number, string> = {
1: "_base_info.finished_product_receipt_status.pending_outstock", 0: "_base_info.finished_product_receipt_status.pending_outstock",
3: "_base_info.finished_product_receipt_status.outstocking", 3: "_base_info.finished_product_receipt_status.outstocking",
4: "_base_info.finished_product_receipt_status.completed", 4: "_base_info.finished_product_receipt_status.completed",
}; };

View File

@@ -8,6 +8,9 @@ import { get } from "@/common/http/request";
interface Emits { interface Emits {
(e: "data-loaded", data: any[]): void; (e: "data-loaded", data: any[]): void;
(e: "expand-change", row: any, expandedRows: any[]): void; (e: "expand-change", row: any, expandedRows: any[]): void;
(e: "select", selection: any[], row: any): void;
(e: "select-all", selection: any[]): void;
(e: "selection-change", selection: any[]): void;
} }
const props = defineProps({ const props = defineProps({
@@ -18,6 +21,16 @@ const props = defineProps({
parse: Function, parse: Function,
expandRowKeys: Array as PropType<(string | number)[]>, expandRowKeys: Array as PropType<(string | number)[]>,
rowKey: { type: String, default: "id" }, rowKey: { type: String, default: "id" },
// 树形数据配置
treeProps: {
type: Object as PropType<{ children: string; hasChildren?: string }>,
default: () => ({ children: "children" }),
},
// 是否显示为树形表格
isTreeTable: {
type: Boolean,
default: false,
},
}); });
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
const tableMainRef = ref<InstanceType<typeof TableMain> | null>(null); const tableMainRef = ref<InstanceType<typeof TableMain> | null>(null);
@@ -67,6 +80,18 @@ const handleExpandChange = (row: any, expandedRows: any[]) => {
emit("expand-change", row, expandedRows); emit("expand-change", row, expandedRows);
}; };
const handleSelect = (selection: any[], row: any) => {
emit("select", selection, row);
};
const handleSelectAll = (selection: any[]) => {
emit("select-all", selection);
};
const handleSelectionChange = (selection: any[]) => {
emit("selection-change", selection);
};
const recomputeTableHeight = () => { const recomputeTableHeight = () => {
if (!tableMainHostEl.value) return; if (!tableMainHostEl.value) return;
const top = tableMainHostEl.value.getBoundingClientRect().top; const top = tableMainHostEl.value.getBoundingClientRect().top;
@@ -85,6 +110,11 @@ defineExpose({
sort: (field: string, order: string) => { sort: (field: string, order: string) => {
tableMainRef.value?.tableRef?.sort(field, order); tableMainRef.value?.tableRef?.sort(field, order);
}, },
toggleRowSelection: (row: any, selected?: boolean) => {
tableMainRef.value?.toggleRowSelection(row, selected);
},
getSelectionRows: () => tableMainRef.value?.getSelectionRows() || [],
clearSelection: () => tableMainRef.value?.tableRef?.clearSelection(),
}); });
onMounted(async () => { onMounted(async () => {
@@ -135,7 +165,12 @@ onMounted(async () => {
v-model:page-size="pageSize" v-model:page-size="pageSize"
:expand-row-keys="expandRowKeys" :expand-row-keys="expandRowKeys"
:row-key="rowKey" :row-key="rowKey"
:tree-props="treeProps"
:is-tree-table="isTreeTable"
@expand-change="handleExpandChange" @expand-change="handleExpandChange"
@select="handleSelect"
@select-all="handleSelectAll"
@selection-change="handleSelectionChange"
> >
<template #columns><slot name="columns"></slot></template> <template #columns><slot name="columns"></slot></template>
</TableMain> </TableMain>

View File

@@ -94,6 +94,8 @@ watch(
if (!val) { if (!val) {
// 关闭时清空选中 // 关闭时清空选中
selectedRows.value = []; selectedRows.value = [];
// 清空表格内部的选择状态,避免下次打开时残留
tableRef.value?.clearSelection();
} }
} }
); );
@@ -129,7 +131,7 @@ defineExpose({
</script> </script>
<template> <template>
<el-dialog v-model="visible" :title="title" :close-on-click-modal="false" width="80%"> <el-dialog v-model="visible" :title="title" :close-on-click-modal="false" :lock-scroll="false" width="80%">
<!-- 1. 顶部筛选区域 (Slot) --> <!-- 1. 顶部筛选区域 (Slot) -->
<div class="dialog-filter-area"> <div class="dialog-filter-area">
<slot name="filter" :refresh="() => emit('filter-refresh')" :selected-rows="selectedRows"> <slot name="filter" :refresh="() => emit('filter-refresh')" :selected-rows="selectedRows">
@@ -151,7 +153,7 @@ defineExpose({
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<!-- 勾选列 --> <!-- 勾选列 -->
<el-table-column type="selection" width="55" :reserve-selection="true" v-if="selectable" /> <el-table-column type="selection" width="55" v-if="selectable" />
<!-- 父组件自定义列 --> <!-- 父组件自定义列 -->
<slot name="table-columns"></slot> <slot name="table-columns"></slot>
@@ -253,6 +255,11 @@ defineExpose({
border-radius: 8px; border-radius: 8px;
} }
:deep(.el-dialog__body) {
overflow-y: auto;
scrollbar-gutter: stable;
}
:deep(.el-dialog__header) { :deep(.el-dialog__header) {
padding: 16px 20px; padding: 16px 20px;
margin-right: 0; margin-right: 0;

View File

@@ -9,6 +9,8 @@ const props = defineProps({
param: URLSearchParams, param: URLSearchParams,
selectUrl: String, selectUrl: String,
showCheckbox: { default: false }, showCheckbox: { default: false },
// 是否启用级联选择:勾选父节点自动勾选子节点,部分勾选子节点时父节点显示半选状态
cascade: { type: Boolean, default: false },
}); });
const treeCheck = defineModel<number[]>(); const treeCheck = defineModel<number[]>();
const treeSelect = defineModel("current-node"); const treeSelect = defineModel("current-node");
@@ -79,7 +81,7 @@ defineExpose({
highlight-current highlight-current
:show-checkbox="showCheckbox" :show-checkbox="showCheckbox"
:default-checked-keys="treeCheck" :default-checked-keys="treeCheck"
check-strictly :check-strictly="!cascade"
@check="checkHandle" @check="checkHandle"
@node-click="clickHandle" @node-click="clickHandle"
/> />

View File

@@ -57,7 +57,7 @@ const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
<style scoped> <style scoped>
.operate-buttons { .operate-buttons {
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: wrap;
gap: 4px; gap: 4px;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@@ -101,19 +101,14 @@ const resetForm = () => {
<template> <template>
<el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" size="large" :class="ns.b()"> <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" size="large" :class="ns.b()">
<el-form-item prop="username"> <el-form-item prop="username">
<el-input <el-input v-model="loginForm.username" placeholder="用户名" :prefix-icon="User" @keydown.enter="login"></el-input>
v-model="loginForm.username"
placeholder="用户名(任意)"
:prefix-icon="User"
@keydown.enter="login"
></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input <el-input
type="password" type="password"
v-model="loginForm.password" v-model="loginForm.password"
placeholder="密码(任意)" placeholder="密码"
show-password show-password
autocomplete="new-password" autocomplete="new-password"
:prefix-icon="Lock" :prefix-icon="Lock"

View File

@@ -191,7 +191,7 @@ const mappingConfig: FieldMappingConfig = {
}, },
}, },
createDate: { createDate: {
sourceKey: ["生产日期", "createDate"], sourceKey: ["生产日期", "时间", "createDate"],
header: $t("_prop.production.finishedproductreceipt.createDate"), header: $t("_prop.production.finishedproductreceipt.createDate"),
width: 15, width: 15,
defaultValue: "", defaultValue: "",
@@ -234,7 +234,7 @@ const remove = (row: any) => {
// 成品入库状态标签类型映射 // 成品入库状态标签类型映射
const getFinishedProductReceiptStatusTagType = (code: number | null): string => { const getFinishedProductReceiptStatusTagType = (code: number | null): string => {
const tagTypeMap: Record<number, string> = { const tagTypeMap: Record<number, string> = {
1: "warning", // 出货 0: "warning", // 出货
3: "primary", // 出货中 3: "primary", // 出货中
4: "success", // 已完成 4: "success", // 已完成
}; };
@@ -242,9 +242,9 @@ const getFinishedProductReceiptStatusTagType = (code: number | null): string =>
}; };
const outstock = async (row: any) => { const outstock = async (row: any) => {
// 检查单据状态,只有待出货和出货中状态才能出货 // 检查单据状态,已完成状态不能出货0=未出货, 3=出货中, 4=已完成)
if (row.formStatus !== 1 && row.formStatus !== 3) { if (row.formStatus === 4) {
ElMessage.warning($t("_message.production.finishedproductreceipt.only_pending_outstocking_can_outstock")); ElMessage.warning($t("_message.production.finishedproductreceipt.completed_cannot_outstock"));
return; return;
} }
@@ -253,9 +253,10 @@ const outstock = async (row: any) => {
try { try {
const outstockData = await get(getOutstockDataUrl, { id: row.id }).then(res => res.data); const outstockData = await get(getOutstockDataUrl, { id: row.id }).then(res => res.data);
outstockTableData.value = outstockData.map((item: any) => ({ outstockTableData.value = outstockData.map((item: any, index: number) => ({
...item, ...item,
selected: false, selected: false,
rowId: item.id || `${item.productSn}_${index}`,
})); }));
// 重置出货表单 // 重置出货表单
@@ -363,8 +364,15 @@ const operateButtonClick = (eventName: string, row: any) => {
}; };
const authShowFunc = (row: any, button: globalThis.ButtonProp) => { const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
// 只有已完成的入库单不能出货formStatus === 4 // 已完成状态不能出货
if (row.formStatus === 4 && button.eventName === "outstock") return false; if (button.eventName === "outstock") {
return row.formStatus !== 4;
}
// 只有未出货状态才能编辑和删除
if (row.formStatus !== 0 && (button.eventName === "edit" || button.eventName === "remove")) {
return false;
}
// 其他按钮根据业务需求显示 // 其他按钮根据业务需求显示
return true; return true;
@@ -641,6 +649,7 @@ const handleReset = () => {
:tableData="outstockTableData" :tableData="outstockTableData"
:selectable="true" :selectable="true"
:useAuth="false" :useAuth="false"
rowKey="rowId"
@selection-change="handleOutstockSelectionChange" @selection-change="handleOutstockSelectionChange"
> >
<template #filter> <template #filter>

View File

@@ -65,13 +65,13 @@ const outStockTypeOptions = [
const mappingConfig: FieldMappingConfig = { const mappingConfig: FieldMappingConfig = {
partNumber: { partNumber: {
sourceKey: ["物料编号", "partNumber"], sourceKey: ["物料编号", "商品编号", "partNumber"],
header: $t("_prop.production.finishedproductshipment.partNumber"), header: $t("_prop.production.finishedproductshipment.partNumber"),
width: 20, width: 20,
defaultValue: "", defaultValue: "",
}, },
productSpecs: { productSpecs: {
sourceKey: ["型号", "物料型号", "productSpecs", "productSpec"], sourceKey: ["型号", "物料型号", "商品型号", "规格", "productSpecs", "productSpec"],
header: $t("_prop.production.finishedproductshipment.productSpecs"), header: $t("_prop.production.finishedproductshipment.productSpecs"),
width: 20, width: 20,
defaultValue: "", defaultValue: "",

View File

@@ -119,11 +119,11 @@ const mappingConfig: FieldMappingConfig = {
defaultValue: "", defaultValue: "",
}, },
productSpecs: { productSpecs: {
sourceKey: "物料型号", sourceKey: ["物料型号", "商品型号", "型号", "规格"],
defaultValue: "", defaultValue: "",
}, },
purchaseCount: { purchaseCount: {
sourceKey: "采购数量", sourceKey: ["采购数量", "数量"],
defaultValue: 0, defaultValue: 0,
transform: (val: any) => { transform: (val: any) => {
const num = Number(val); const num = Number(val);

View File

@@ -366,7 +366,7 @@ const generatePurchaseOrder = async () => {
const mappingConfig: FieldMappingConfig = { const mappingConfig: FieldMappingConfig = {
partNumber: { partNumber: {
sourceKey: "物料编号", sourceKey: ["物料编号", "商品编号"],
defaultValue: "", defaultValue: "",
}, },

View File

@@ -239,7 +239,7 @@ const mappingConfig: FieldMappingConfig = {
defaultValue: "", defaultValue: "",
}, },
productSpecs: { productSpecs: {
sourceKey: ["物料型号", "productSpecs"], sourceKey: ["物料型号", "productSpecs", "型号", "规格"],
header: $t("_prop.sale.saleorder.productSpecs"), header: $t("_prop.sale.saleorder.productSpecs"),
width: 20, width: 20,
defaultValue: "", defaultValue: "",

View File

@@ -137,7 +137,7 @@ const getCommonStatusTagType = (code: number | null): string => {
</el-row> </el-row>
<br /> <br />
<el-form-item style="max-height: 400px; overflow: auto"> <el-form-item style="max-height: 400px; overflow: auto">
<BaseTree ref="treeRef" :url="treeUrl" :show-checkbox="true" v-model="form.permissionIds" /> <BaseTree ref="treeRef" :url="treeUrl" :show-checkbox="true" :cascade="true" v-model="form.permissionIds" />
</el-form-item> </el-form-item>
</template> </template>
</BaseForm> </BaseForm>

View File

@@ -135,11 +135,11 @@ const operateButtonClick = (eventName: string, row: any) => {
// Excel导入配置 // Excel导入配置
const mappingConfig: FieldMappingConfig = { const mappingConfig: FieldMappingConfig = {
partNumber: { partNumber: {
sourceKey: "物料编号", sourceKey: ["物料编号", "商品编号"],
defaultValue: "", defaultValue: "",
}, },
productSpec: { productSpec: {
sourceKey: "物料型号", sourceKey: ["物料型号", "商品型号", "型号", "规格"],
defaultValue: "", defaultValue: "",
}, },
productCount: { productCount: {

View File

@@ -128,12 +128,12 @@ const itemArrayName = "transferOrderItems";
const mappingConfig: FieldMappingConfig = { const mappingConfig: FieldMappingConfig = {
partNumber: { partNumber: {
sourceKey: "物料编号", sourceKey: ["物料编号", "商品编号"],
defaultValue: "", defaultValue: "",
}, },
productCount: { productCount: {
sourceKey: "调拨数量", sourceKey: ["调拨数量", "数量"],
defaultValue: 0, defaultValue: 0,
transform: (val: any) => { transform: (val: any) => {
const num = Number(val); const num = Number(val);

View File

@@ -1,53 +1,3 @@
<script setup lang="ts" name="Home"></script> <script setup lang="ts" name="Home"></script>
<template> <template></template>
<div class="tk-card-minimal">
<el-descriptions class="margin-top" :column="1" border>
<el-descriptions-item label="完整版 GitHub 地址">
<el-link type="primary" href="https://github.com/Kele-Bingtang/teek-design-vue3" target="_blank">
https://github.com/Kele-Bingtang/teek-design-vue3
</el-link>
</el-descriptions-item>
<el-descriptions-item label="精简版 GitHub 地址">
<el-link type="primary" href="https://github.com/Kele-Bingtang/teek-design-vue3-template" target="_blank">
https://github.com/Kele-Bingtang/teek-design-vue3-template
</el-link>
</el-descriptions-item>
<el-descriptions-item label="精简版 monorepo 架构 GitHub 地址v1.5.1">
<el-link
type="primary"
href="https://github.com/Kele-Bingtang/teek-design-vue3-template/tree/monorepo"
target="_blank"
>
https://github.com/Kele-Bingtang/teek-design-vue3-template/tree/monorepo
</el-link>
</el-descriptions-item>
<el-descriptions-item label="使用文档">
<el-link type="primary" href="https://vue3-design-docs.teek.top/" target="_blank">
https://vue3-design-docs.teek.top/
</el-link>
</el-descriptions-item>
<el-descriptions-item label="效果预览地址">
<el-link type="primary" href="https://vue3-design.teek.top/" target="_blank">
https://vue3-design.teek.top/
</el-link>
</el-descriptions-item>
<el-descriptions-item label="Vue2 完整版 Github 地址">
<el-link type="primary" href="https://github.com/Kele-Bingtang/teek-design-vue2" target="_blank">
https://github.com/Kele-Bingtang/teek-design-vue2
</el-link>
</el-descriptions-item>
<el-descriptions-item label="Vue2 精简版 Github 地址">
<el-link type="primary" href="https://github.com/Kele-Bingtang/teek-design-vue2-template" target="_blank">
https://github.com/Kele-Bingtang/teek-design-vue3-template
</el-link>
</el-descriptions-item>
<el-descriptions-item label="Vue2 效果预览地址">
<el-link type="primary" href="https://vue2-design.teek.top/" target="_blank">
https://vue2-design.teek.top/
</el-link>
</el-descriptions-item>
</el-descriptions>
</div>
</template>