fix: 更新搜索栏展示问题,以及销售订单的一些问题。
This commit is contained in:
@@ -49,5 +49,5 @@ const i18nLocale = computed(() => {
|
||||
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>
|
||||
|
||||
@@ -21,7 +21,15 @@ export const UserService = {
|
||||
},
|
||||
|
||||
checkIsLogined() {
|
||||
return get("/auth/user/me");
|
||||
return get("/open/check-login");
|
||||
},
|
||||
|
||||
/**
|
||||
* 检测登录状态
|
||||
* 用于前端页面刷新后检测当前token是否有效
|
||||
*/
|
||||
checkLogin() {
|
||||
return get("/open/check-login");
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
|
||||
@@ -21,6 +21,11 @@ const props = defineProps({
|
||||
});
|
||||
const emit = defineEmits<Emits>();
|
||||
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 pageSize = ref(30);
|
||||
const total = ref(0);
|
||||
@@ -62,6 +67,15 @@ const handleExpandChange = (row: any, expandedRows: any[]) => {
|
||||
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({
|
||||
reload: loadData,
|
||||
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>
|
||||
<template>
|
||||
<TableHeader
|
||||
v-if="searchers !== undefined"
|
||||
:searchers="searchers"
|
||||
:tool-buttons="toolButtons"
|
||||
v-model:searcher-params="searcherParams"
|
||||
:search-click="searchClick"
|
||||
>
|
||||
<template #tool-button><slot name="tool-button"></slot></template>
|
||||
</TableHeader>
|
||||
<TableMain
|
||||
ref="tableMainRef"
|
||||
:data="tableData"
|
||||
:total="total"
|
||||
:update-page="updatePage"
|
||||
v-model:page="page"
|
||||
v-model:page-size="pageSize"
|
||||
:expand-row-keys="expandRowKeys"
|
||||
:row-key="rowKey"
|
||||
@expand-change="handleExpandChange"
|
||||
>
|
||||
<template #columns><slot name="columns"></slot></template>
|
||||
</TableMain>
|
||||
<div ref="tableHeaderEl">
|
||||
<TableHeader
|
||||
v-if="searchers !== undefined"
|
||||
:searchers="searchers"
|
||||
:tool-buttons="toolButtons"
|
||||
v-model:searcher-params="searcherParams"
|
||||
:search-click="searchClick"
|
||||
>
|
||||
<template #tool-button><slot name="tool-button"></slot></template>
|
||||
</TableHeader>
|
||||
</div>
|
||||
<div ref="tableMainHostEl">
|
||||
<TableMain
|
||||
ref="tableMainRef"
|
||||
:data="tableData"
|
||||
:total="total"
|
||||
:update-page="updatePage"
|
||||
:container-height="tableMainHeight"
|
||||
:extra-offset="headerExtraOffset"
|
||||
v-model:page="page"
|
||||
v-model:page-size="pageSize"
|
||||
:expand-row-keys="expandRowKeys"
|
||||
:row-key="rowKey"
|
||||
@expand-change="handleExpandChange"
|
||||
>
|
||||
<template #columns><slot name="columns"></slot></template>
|
||||
</TableMain>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -15,16 +15,19 @@ const searcherParams = defineModel<Record<string, string>>("searcherParams");
|
||||
</script>
|
||||
<template>
|
||||
<div class="table-header">
|
||||
<SearchBar
|
||||
:searchers="searchers"
|
||||
:search-click="searchClick"
|
||||
v-model:searcher-params="searcherParams"
|
||||
:reset-click="resetClick"
|
||||
/>
|
||||
<!-- <TableToolBar class="table-tool-bar" :tool-buttons="toolButtons" /> -->
|
||||
<div>
|
||||
<slot name="tool-button"></slot>
|
||||
<div class="table-header__search">
|
||||
<SearchBar
|
||||
:searchers="searchers"
|
||||
:search-click="searchClick"
|
||||
v-model:searcher-params="searcherParams"
|
||||
:reset-click="resetClick"
|
||||
>
|
||||
<template #after-actions>
|
||||
<slot name="tool-button"></slot>
|
||||
</template>
|
||||
</SearchBar>
|
||||
</div>
|
||||
<!-- <TableToolBar class="table-tool-bar" :tool-buttons="toolButtons" /> -->
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
@@ -32,9 +35,15 @@ const searcherParams = defineModel<Record<string, string>>("searcherParams");
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.table-header__search {
|
||||
flex: 1 1 auto;
|
||||
min-width: 260px;
|
||||
}
|
||||
|
||||
.table-tool-bar {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,16 @@ defineProps({
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
// 由父组件按实际视口计算的可用高度(px)。传了则优先生效。
|
||||
containerHeight: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 表头等区域换行导致高度变化时的额外偏移量(px)
|
||||
extraOffset: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 新增:透传给 el-table 的展开行 key 列表
|
||||
expandRowKeys: {
|
||||
type: Array as PropType<(string | number)[]>,
|
||||
@@ -49,7 +59,15 @@ defineExpose({
|
||||
});
|
||||
</script>
|
||||
<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">
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
|
||||
@@ -41,6 +41,7 @@ function reset() {
|
||||
<el-date-picker
|
||||
v-model="searcherParams[searcher.name]"
|
||||
v-if="searcher.type === 'date-range-pick'"
|
||||
class="searcher"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
:start-placeholder="$t('_prop.common.startdate')"
|
||||
@@ -48,24 +49,43 @@ function reset() {
|
||||
value-format="YYYY-MM-DD"
|
||||
></el-date-picker>
|
||||
</div>
|
||||
<el-button v-if="searchClick !== undefined" :icon="Search" type="primary" @click="searchButtonClick">
|
||||
{{ $t("_button.search") }}
|
||||
</el-button>
|
||||
<el-button v-if="searchClick !== undefined" :icon="Refresh" @click="reset">{{ $t("_button.reset") }}</el-button>
|
||||
<div class="search-actions" v-if="searchClick !== undefined">
|
||||
<el-button :icon="Search" type="primary" @click="searchButtonClick">
|
||||
{{ $t("_button.search") }}
|
||||
</el-button>
|
||||
<el-button :icon="Refresh" @click="reset">{{ $t("_button.reset") }}</el-button>
|
||||
<slot name="after-actions"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.search-bar {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.searcher-box {
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
box-sizing: border-box;
|
||||
flex: 0 1 400px;
|
||||
min-width: 240px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.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>
|
||||
|
||||
@@ -6,11 +6,10 @@ import { usePage } from "@/composables/use-page";
|
||||
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
|
||||
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
|
||||
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 BaseSelect from "@/components/base/base-select/BaseSelect.vue";
|
||||
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 ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
|
||||
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 { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
|
||||
const { useAdd, useEdit, useRemove, useGeneralPageRef, useApprove, useReject } = usePage(tableRef);
|
||||
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
|
||||
const warehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
|
||||
const { getFormStatusLabel } = useStatus();
|
||||
@@ -162,35 +161,11 @@ const getFormStatusTagType = (code: number | null): string => {
|
||||
};
|
||||
|
||||
const approve = (row: any) => {
|
||||
ElMessageBox.confirm($t("_message.production.finishedproductshipment.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.production.finishedproductshipment.approve_success"));
|
||||
tableRef.value?.reload();
|
||||
} catch (err: any) {
|
||||
ElMessage.error($t("_message.production.finishedproductshipment.approve_fail") + err);
|
||||
}
|
||||
});
|
||||
useApprove(approveUrl, row.id, "_message.production.finishedproductshipment.approve_confirm");
|
||||
};
|
||||
|
||||
const reject = (row: any) => {
|
||||
ElMessageBox.confirm($t("_message.production.finishedproductshipment.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.production.finishedproductshipment.reject_success"));
|
||||
tableRef.value?.reload();
|
||||
} catch (err: any) {
|
||||
ElMessage.error($t("_message.production.finishedproductshipment.reject_fail") + err);
|
||||
}
|
||||
});
|
||||
useReject(rejectUrl, row.id, "_message.production.finishedproductshipment.reject_confirm");
|
||||
};
|
||||
|
||||
const showItem = (row: any) => {
|
||||
|
||||
@@ -5,11 +5,11 @@ import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultS
|
||||
import { usePage } from "@/composables/use-page";
|
||||
import { $t } from "@/common/languages";
|
||||
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 BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.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 { 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 { useAdd, useEdit, useRemove, useGeneralPageRef, useApprove, useReject } = usePage(tableRef);
|
||||
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
|
||||
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
|
||||
const { getFormStatusLabel } = useStatus();
|
||||
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
|
||||
@@ -156,11 +156,35 @@ const remove = (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) => {
|
||||
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) => {
|
||||
@@ -212,10 +236,12 @@ const operateButtonClick = (eventName: string, row: any) => {
|
||||
};
|
||||
|
||||
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
|
||||
if (row.formStatus === 1 && button.eventName === "approve") return false;
|
||||
if (row.formStatus === 0 && button.eventName === "reject") return false;
|
||||
if (row.formStatus === 1 && button.eventName === "edit") return false;
|
||||
if (row.formStatus === 1 && button.eventName === "remove") return false;
|
||||
// 已审核(status=1)时不显示审核按钮,显示反审按钮
|
||||
// 未审核(status=0)时显示审核按钮,不显示反审按钮
|
||||
if (row.status === 0 && button.eventName === "reject") 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;
|
||||
};
|
||||
|
||||
@@ -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.common.createDate')" prop="createDate" :formatter="formatDate" />
|
||||
<DefaultStatusSwitchColumn
|
||||
status-param-name="formStatus"
|
||||
status-param-name="status"
|
||||
:status-label-mapping="getFormStatusLabel"
|
||||
:tag-type-mapping="getFormStatusTagType"
|
||||
:switch-on-value="1"
|
||||
:switch-off-value="0"
|
||||
/>
|
||||
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
|
||||
</template>
|
||||
@@ -322,7 +346,7 @@ const getFormStatusTagType = (code: number | null): string => {
|
||||
:base-title="$t('_title.sale.saleorder.baseTitle')"
|
||||
:table-title="$t('_title.sale.saleorder.tableTitle')"
|
||||
item-array-name="saleOrderItems"
|
||||
upload-desc="销售明细"
|
||||
:upload-desc="$t('_title.sale.saleorder.tableTitle')"
|
||||
:mapping-config="mappingConfig"
|
||||
>
|
||||
<template #form-items>
|
||||
@@ -400,7 +424,7 @@ const getFormStatusTagType = (code: number | null): string => {
|
||||
<el-table-column :label="$t('_prop.sale.saleorder.saleMark')" width="150">
|
||||
<template #default="{ row, $index }">
|
||||
<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>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
Reference in New Issue
Block a user