fix: 更新搜索栏展示问题,以及销售订单的一些问题。

This commit is contained in:
c
2026-03-18 15:30:04 +08:00
parent 88aef44583
commit bf83b5e3b6
8 changed files with 181 additions and 85 deletions

View File

@@ -49,5 +49,5 @@ const i18nLocale = computed(() => {
return document.documentElement.lang === "zh-CN" ? zhCn : en; return document.documentElement.lang === "zh-CN" ? zhCn : en;
}); });
if (isFunction(log.success)) log.success(__APP_INFO__.pkg.version, "欢迎使用 Teek Design Vue3 系统"); if (isFunction(log.success)) log.success(__APP_INFO__.pkg.version, "欢迎使用牛安管理系统");
</script> </script>

View File

@@ -21,7 +21,15 @@ export const UserService = {
}, },
checkIsLogined() { checkIsLogined() {
return get("/auth/user/me"); return get("/open/check-login");
},
/**
* 检测登录状态
* 用于前端页面刷新后检测当前token是否有效
*/
checkLogin() {
return get("/open/check-login");
}, },
// 获取用户信息 // 获取用户信息

View File

@@ -21,6 +21,11 @@ const props = defineProps({
}); });
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
const tableMainRef = ref<InstanceType<typeof TableMain> | null>(null); const tableMainRef = ref<InstanceType<typeof TableMain> | null>(null);
const tableHeaderEl = ref<HTMLElement | null>(null);
const tableMainHostEl = ref<HTMLElement | null>(null);
const headerBaseHeight = ref(0);
const headerExtraOffset = ref(0);
const tableMainHeight = ref(0);
const page = ref(1); const page = ref(1);
const pageSize = ref(30); const pageSize = ref(30);
const total = ref(0); const total = ref(0);
@@ -62,6 +67,15 @@ const handleExpandChange = (row: any, expandedRows: any[]) => {
emit("expand-change", row, expandedRows); emit("expand-change", row, expandedRows);
}; };
const recomputeTableHeight = () => {
if (!tableMainHostEl.value) return;
const top = tableMainHostEl.value.getBoundingClientRect().top;
// 预留一点底部空隙,避免贴边导致分页视觉上“出屏”
const paddingBottom = 12;
const h = Math.floor(window.innerHeight - top - paddingBottom);
tableMainHeight.value = Math.max(240, h);
};
defineExpose({ defineExpose({
reload: loadData, reload: loadData,
tableMainRef, tableMainRef,
@@ -73,31 +87,59 @@ defineExpose({
}, },
}); });
onMounted(loadData); onMounted(async () => {
await loadData();
await nextTick();
if (tableHeaderEl.value) {
headerBaseHeight.value = tableHeaderEl.value.getBoundingClientRect().height;
}
recomputeTableHeight();
if (tableHeaderEl.value && "ResizeObserver" in window) {
const ro = new ResizeObserver(entries => {
const h = entries[0]?.contentRect?.height ?? 0;
headerExtraOffset.value = Math.max(0, Math.round(h - headerBaseHeight.value));
// 表头换行会影响 TableMain 的 top需要同步重算可用高度
requestAnimationFrame(recomputeTableHeight);
});
ro.observe(tableHeaderEl.value);
onBeforeUnmount(() => ro.disconnect());
}
window.addEventListener("resize", recomputeTableHeight);
onBeforeUnmount(() => window.removeEventListener("resize", recomputeTableHeight));
});
</script> </script>
<template> <template>
<TableHeader <div ref="tableHeaderEl">
v-if="searchers !== undefined" <TableHeader
:searchers="searchers" v-if="searchers !== undefined"
:tool-buttons="toolButtons" :searchers="searchers"
v-model:searcher-params="searcherParams" :tool-buttons="toolButtons"
:search-click="searchClick" v-model:searcher-params="searcherParams"
> :search-click="searchClick"
<template #tool-button><slot name="tool-button"></slot></template> >
</TableHeader> <template #tool-button><slot name="tool-button"></slot></template>
<TableMain </TableHeader>
ref="tableMainRef" </div>
:data="tableData" <div ref="tableMainHostEl">
:total="total" <TableMain
:update-page="updatePage" ref="tableMainRef"
v-model:page="page" :data="tableData"
v-model:page-size="pageSize" :total="total"
:expand-row-keys="expandRowKeys" :update-page="updatePage"
:row-key="rowKey" :container-height="tableMainHeight"
@expand-change="handleExpandChange" :extra-offset="headerExtraOffset"
> v-model:page="page"
<template #columns><slot name="columns"></slot></template> v-model:page-size="pageSize"
</TableMain> :expand-row-keys="expandRowKeys"
:row-key="rowKey"
@expand-change="handleExpandChange"
>
<template #columns><slot name="columns"></slot></template>
</TableMain>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@@ -15,16 +15,19 @@ const searcherParams = defineModel<Record<string, string>>("searcherParams");
</script> </script>
<template> <template>
<div class="table-header"> <div class="table-header">
<SearchBar <div class="table-header__search">
:searchers="searchers" <SearchBar
:search-click="searchClick" :searchers="searchers"
v-model:searcher-params="searcherParams" :search-click="searchClick"
:reset-click="resetClick" v-model:searcher-params="searcherParams"
/> :reset-click="resetClick"
<!-- <TableToolBar class="table-tool-bar" :tool-buttons="toolButtons" /> --> >
<div> <template #after-actions>
<slot name="tool-button"></slot> <slot name="tool-button"></slot>
</template>
</SearchBar>
</div> </div>
<!-- <TableToolBar class="table-tool-bar" :tool-buttons="toolButtons" /> -->
</div> </div>
</template> </template>
<style> <style>
@@ -32,9 +35,15 @@ const searcherParams = defineModel<Record<string, string>>("searcherParams");
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 10px; gap: 10px;
align-items: flex-start;
margin-bottom: 10px; margin-bottom: 10px;
} }
.table-header__search {
flex: 1 1 auto;
min-width: 260px;
}
.table-tool-bar { .table-tool-bar {
padding-left: 10px; padding-left: 10px;
} }

View File

@@ -17,6 +17,16 @@ defineProps({
type: Function, type: Function,
required: true, required: true,
}, },
// 由父组件按实际视口计算的可用高度px。传了则优先生效。
containerHeight: {
type: Number,
default: 0,
},
// 表头等区域换行导致高度变化时的额外偏移量px
extraOffset: {
type: Number,
default: 0,
},
// 新增:透传给 el-table 的展开行 key 列表 // 新增:透传给 el-table 的展开行 key 列表
expandRowKeys: { expandRowKeys: {
type: Array as PropType<(string | number)[]>, type: Array as PropType<(string | number)[]>,
@@ -49,7 +59,15 @@ defineExpose({
}); });
</script> </script>
<template> <template>
<div style="display: flex; flex-direction: column; height: calc(100vh - 157px); overflow: hidden"> <div
:style="{
display: 'flex',
flexDirection: 'column',
height:
containerHeight && containerHeight > 0 ? `${containerHeight}px` : `calc(100vh - ${157 + (extraOffset || 0)}px)`,
overflow: 'hidden',
}"
>
<div style="flex: 1; overflow: hidden"> <div style="flex: 1; overflow: hidden">
<el-table <el-table
ref="tableRef" ref="tableRef"

View File

@@ -41,6 +41,7 @@ function reset() {
<el-date-picker <el-date-picker
v-model="searcherParams[searcher.name]" v-model="searcherParams[searcher.name]"
v-if="searcher.type === 'date-range-pick'" v-if="searcher.type === 'date-range-pick'"
class="searcher"
type="daterange" type="daterange"
range-separator="-" range-separator="-"
:start-placeholder="$t('_prop.common.startdate')" :start-placeholder="$t('_prop.common.startdate')"
@@ -48,24 +49,43 @@ function reset() {
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
></el-date-picker> ></el-date-picker>
</div> </div>
<el-button v-if="searchClick !== undefined" :icon="Search" type="primary" @click="searchButtonClick"> <div class="search-actions" v-if="searchClick !== undefined">
{{ $t("_button.search") }} <el-button :icon="Search" type="primary" @click="searchButtonClick">
</el-button> {{ $t("_button.search") }}
<el-button v-if="searchClick !== undefined" :icon="Refresh" @click="reset">{{ $t("_button.reset") }}</el-button> </el-button>
<el-button :icon="Refresh" @click="reset">{{ $t("_button.reset") }}</el-button>
<slot name="after-actions"></slot>
</div>
</div> </div>
</template> </template>
<style> <style>
.search-bar { .search-bar {
box-sizing: border-box;
display: flex; display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: flex-start;
padding-right: 20px; padding-right: 20px;
} }
.searcher-box { .searcher-box {
padding-right: 5px; box-sizing: border-box;
padding-left: 5px; flex: 0 1 400px;
min-width: 240px;
max-width: 400px;
} }
.searcher { .searcher {
width: 400px; box-sizing: border-box;
width: 100%;
}
.search-actions {
box-sizing: border-box;
display: flex;
flex: 0 0 auto;
gap: 10px;
align-items: center;
padding-left: 5px;
} }
</style> </style>

View File

@@ -6,11 +6,10 @@ import { usePage } from "@/composables/use-page";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue"; import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue"; import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
import { $t } from "@/common/languages"; import { $t } from "@/common/languages";
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus"; import { type FormInstance, type FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils"; import { formatDate } from "@/common/utils/format-utils";
import BaseSelect from "@/components/base/base-select/BaseSelect.vue"; import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator"; import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
import { get, post } from "@/common/http/request";
import { useStatus } from "@/common/languages/mapping/base-info-mapping"; import { useStatus } from "@/common/languages/mapping/base-info-mapping";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue"; import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type"; import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type";
@@ -87,7 +86,7 @@ const mappingConfig: FieldMappingConfig = {
* 基本不变通用变量 * 基本不变通用变量
*/ */
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null); const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef); const { useAdd, useEdit, useRemove, useGeneralPageRef, useApprove, useReject } = usePage(tableRef);
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef(); const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
const warehouseSelectRef = ref<InstanceType<typeof BaseSelect>>(); const warehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
const { getFormStatusLabel } = useStatus(); const { getFormStatusLabel } = useStatus();
@@ -162,35 +161,11 @@ const getFormStatusTagType = (code: number | null): string => {
}; };
const approve = (row: any) => { const approve = (row: any) => {
ElMessageBox.confirm($t("_message.production.finishedproductshipment.approve_confirm"), $t("_level.warning"), { useApprove(approveUrl, row.id, "_message.production.finishedproductshipment.approve_confirm");
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(approveUrl, { id: row.id });
ElMessage.success($t("_message.production.finishedproductshipment.approve_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.production.finishedproductshipment.approve_fail") + err);
}
});
}; };
const reject = (row: any) => { const reject = (row: any) => {
ElMessageBox.confirm($t("_message.production.finishedproductshipment.reject_confirm"), $t("_level.warning"), { useReject(rejectUrl, row.id, "_message.production.finishedproductshipment.reject_confirm");
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(rejectUrl, { id: row.id });
ElMessage.success($t("_message.production.finishedproductshipment.reject_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.production.finishedproductshipment.reject_fail") + err);
}
});
}; };
const showItem = (row: any) => { const showItem = (row: any) => {

View File

@@ -5,11 +5,11 @@ import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultS
import { usePage } from "@/composables/use-page"; import { usePage } from "@/composables/use-page";
import { $t } from "@/common/languages"; import { $t } from "@/common/languages";
import { formatDate } from "@/common/utils/format-utils"; import { formatDate } from "@/common/utils/format-utils";
import { ElMessage, type FormInstance, type FormRules } from "element-plus"; import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue"; import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue"; import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue"; import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import { get } from "@/common/http/request"; import { get, post } from "@/common/http/request";
import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type"; import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type";
import { useStatus } from "@/common/languages/mapping/base-info-mapping"; import { useStatus } from "@/common/languages/mapping/base-info-mapping";
@@ -77,7 +77,7 @@ const getDetailUrl = "/sale/saleorder/getSaleOrderItemList";
* 基本不变通用变量 * 基本不变通用变量
*/ */
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null); const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef, useApprove, useReject } = usePage(tableRef); const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef(); const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
const { getFormStatusLabel } = useStatus(); const { getFormStatusLabel } = useStatus();
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>(); const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
@@ -156,11 +156,35 @@ const remove = (row: any) => {
}; };
const approve = (row: any) => { const approve = (row: any) => {
useApprove(approveUrl, row.id); ElMessageBox.confirm($t("_message.sale.saleorder.approve_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(approveUrl, { id: row.id });
ElMessage.success($t("_message.sale.saleorder.approve_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.sale.saleorder.approve_fail") + err);
}
});
}; };
const reject = (row: any) => { const reject = (row: any) => {
useReject(rejectUrl, row.id); ElMessageBox.confirm($t("_message.sale.saleorder.reject_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(rejectUrl, { id: row.id });
ElMessage.success($t("_message.sale.saleorder.reject_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.sale.saleorder.reject_fail") + err);
}
});
}; };
const showItem = (row: any) => { const showItem = (row: any) => {
@@ -212,10 +236,12 @@ const operateButtonClick = (eventName: string, row: any) => {
}; };
const authShowFunc = (row: any, button: globalThis.ButtonProp) => { const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.formStatus === 1 && button.eventName === "approve") return false; // 已审核(status=1)时不显示审核按钮,显示反审按钮
if (row.formStatus === 0 && button.eventName === "reject") return false; // 未审核(status=0)时显示审核按钮,不显示反审按钮
if (row.formStatus === 1 && button.eventName === "edit") return false; if (row.status === 0 && button.eventName === "reject") return false;
if (row.formStatus === 1 && button.eventName === "remove") return false; if (row.status === 1 && button.eventName === "approve") return false;
// 已审核后不能编辑和删除
if (row.status === 1 && (button.eventName === "edit" || button.eventName === "remove")) return false;
return true; return true;
}; };
@@ -294,11 +320,9 @@ const getFormStatusTagType = (code: number | null): string => {
<el-table-column :label="$t('_prop.sale.saleorder.formMark')" prop="formMark" show-overflow-tooltip /> <el-table-column :label="$t('_prop.sale.saleorder.formMark')" prop="formMark" show-overflow-tooltip />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" /> <el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultStatusSwitchColumn <DefaultStatusSwitchColumn
status-param-name="formStatus" status-param-name="status"
:status-label-mapping="getFormStatusLabel" :status-label-mapping="getFormStatusLabel"
:tag-type-mapping="getFormStatusTagType" :tag-type-mapping="getFormStatusTagType"
:switch-on-value="1"
:switch-off-value="0"
/> />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" /> <DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
</template> </template>
@@ -322,7 +346,7 @@ const getFormStatusTagType = (code: number | null): string => {
:base-title="$t('_title.sale.saleorder.baseTitle')" :base-title="$t('_title.sale.saleorder.baseTitle')"
:table-title="$t('_title.sale.saleorder.tableTitle')" :table-title="$t('_title.sale.saleorder.tableTitle')"
item-array-name="saleOrderItems" item-array-name="saleOrderItems"
upload-desc="销售明细" :upload-desc="$t('_title.sale.saleorder.tableTitle')"
:mapping-config="mappingConfig" :mapping-config="mappingConfig"
> >
<template #form-items> <template #form-items>
@@ -400,7 +424,7 @@ const getFormStatusTagType = (code: number | null): string => {
<el-table-column :label="$t('_prop.sale.saleorder.saleMark')" width="150"> <el-table-column :label="$t('_prop.sale.saleorder.saleMark')" width="150">
<template #default="{ row, $index }"> <template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.saleMark`"> <el-form-item :prop="`${itemArrayName}.${$index}.saleMark`">
<el-input v-model="row.saleMark" placeholder="请输入备注" size="small" /> <el-input v-model="row.saleMark" :placeholder="$t('_message.sale.saleorder.input_saleMark')" size="small" />
</el-form-item> </el-form-item>
</template> </template>
</el-table-column> </el-table-column>