20260719215738
This commit is contained in:
1 parent
35aa108a34
commit
cda7f16d3a
116 files changed
+11826
-3669
No files matched your search
@@ -2,7 +2,7 @@
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { Ellipsis, ListFilter, Plus, Search } from "@lucide/vue";
|
||||
import { loadDataApi } from "../services/api";
|
||||
import { loadDataApi, pageDataApi } from "../services/api";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -53,6 +53,9 @@ const advancedFilters = reactive(createEmptyAdvancedFilters());
|
||||
const draftFilterCount = computed(
|
||||
() => Object.values(advancedFilters).filter(isFilterValueFilled).length,
|
||||
);
|
||||
const hasActiveFilters = computed(
|
||||
() => Boolean(filters.keyword.trim()) || appliedFilterCount.value > 0,
|
||||
);
|
||||
|
||||
function createEmptyAdvancedFilters() {
|
||||
return {
|
||||
@@ -89,9 +92,22 @@ function getRowValue(row, candidates) {
|
||||
|
||||
function normalizeRow(row, index) {
|
||||
const id = getRowValue(row, ["id", "b_id", "user_id", "userid"]);
|
||||
const name = getRowValue(row, ["name", "b_name", "customer_name", "title"]);
|
||||
const state = getRowValue(row, ["state", "b_state", "status"]);
|
||||
const updatedAt = getRowValue(row, ["updated_at", "update_time", "updated_time", "b_updated_at"]);
|
||||
const name = getRowValue(row, [
|
||||
"name",
|
||||
"b_name",
|
||||
"customer_name",
|
||||
"v_customer_company",
|
||||
"b_ywno",
|
||||
"title",
|
||||
]);
|
||||
const state = getRowValue(row, ["state", "b_state", "status", "b_canuse"]);
|
||||
const updatedAt = getRowValue(row, [
|
||||
"updated_at",
|
||||
"b_updatedatetime",
|
||||
"update_time",
|
||||
"updated_time",
|
||||
"b_updated_at",
|
||||
]);
|
||||
|
||||
return {
|
||||
...row,
|
||||
@@ -176,7 +192,7 @@ function applyLocalFilters() {
|
||||
|
||||
function searchData() {
|
||||
pagination.current = 1;
|
||||
applyLocalFilters();
|
||||
loadData();
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
@@ -188,11 +204,27 @@ async function loadData() {
|
||||
loadError.value = "";
|
||||
|
||||
try {
|
||||
const response = await loadDataApi(viewName);
|
||||
const result = response.data;
|
||||
const response = hasActiveFilters.value
|
||||
? await loadDataApi(viewName)
|
||||
: await pageDataApi({
|
||||
viewName,
|
||||
orderBy: String(route.meta.orderBy || "b_id DESC"),
|
||||
pageNo: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
});
|
||||
if (currentSequence !== loadSequence) return;
|
||||
sourceRows.value = (Array.isArray(result) ? result : []).map(normalizeRow);
|
||||
applyLocalFilters();
|
||||
|
||||
if (hasActiveFilters.value) {
|
||||
sourceRows.value = (Array.isArray(response.data) ? response.data : []).map(normalizeRow);
|
||||
applyLocalFilters();
|
||||
} else {
|
||||
const result = response.data ?? {};
|
||||
sourceRows.value = [];
|
||||
rows.value = (Array.isArray(result.rows) ? result.rows : []).map(normalizeRow);
|
||||
total.value = Number(result.total) || 0;
|
||||
pagination.current = Number(result.page_no) || pagination.current;
|
||||
pagination.pageSize = Number(result.page_size) || pagination.pageSize;
|
||||
}
|
||||
} catch (error) {
|
||||
if (currentSequence !== loadSequence) return;
|
||||
sourceRows.value = [];
|
||||
@@ -211,7 +243,11 @@ function openDetail(record) {
|
||||
function changePage(page, pageSize) {
|
||||
pagination.current = page;
|
||||
pagination.pageSize = pageSize;
|
||||
applyLocalFilters();
|
||||
if (hasActiveFilters.value) {
|
||||
applyLocalFilters();
|
||||
} else {
|
||||
loadData();
|
||||
}
|
||||
}
|
||||
|
||||
function resetAdvancedFilters() {
|
||||
@@ -222,7 +258,7 @@ function applyAdvancedFilters() {
|
||||
pagination.current = 1;
|
||||
appliedFilterCount.value = draftFilterCount.value;
|
||||
advancedOpen.value = false;
|
||||
applyLocalFilters();
|
||||
loadData();
|
||||
}
|
||||
|
||||
function updateTableHeight() {
|
||||
@@ -593,13 +629,4 @@ watch(
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
.advanced-filter-form {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.filter-span-full {
|
||||
grid-column: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,33 +1,79 @@
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { ArrowLeft } from "@lucide/vue";
|
||||
import { mockRecords } from "../data/mockRecords";
|
||||
import { loadDataApi } from "../services/api";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const remark = ref("");
|
||||
const loading = ref(false);
|
||||
const loadError = ref("");
|
||||
const sourceRecord = ref(null);
|
||||
let loadSequence = 0;
|
||||
|
||||
const recordId = computed(() => String(route.params.id ?? ""));
|
||||
const detailTitle = computed(() => route.meta.listTitle || route.meta.title || "详情");
|
||||
const record = computed(
|
||||
() =>
|
||||
mockRecords.find((item) => item.id === recordId.value) ?? {
|
||||
id: recordId.value,
|
||||
name: `${detailTitle.value} ${recordId.value}`,
|
||||
state: "草稿",
|
||||
businessType: "未设置",
|
||||
owner: "未设置",
|
||||
customer: "未设置",
|
||||
amount: "0.00",
|
||||
currency: "CNY",
|
||||
updated_at: "--",
|
||||
},
|
||||
);
|
||||
|
||||
function getRowValue(row, candidates) {
|
||||
if (!row) return undefined;
|
||||
const keys = Object.keys(row);
|
||||
for (const candidate of candidates) {
|
||||
const matchedKey = keys.find((key) => key.toLowerCase() === candidate.toLowerCase());
|
||||
if (matchedKey !== undefined && row[matchedKey] != null) return row[matchedKey];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const record = computed(() => {
|
||||
const row = sourceRecord.value;
|
||||
return {
|
||||
id: recordId.value,
|
||||
name: getRowValue(row, ["name", "b_name", "v_customer_company", "b_ywno", "title"]) ?? "--",
|
||||
state: getRowValue(row, ["state", "b_state", "status", "b_canuse"]) ?? "--",
|
||||
businessType: getRowValue(row, ["business_type", "b_ywtype", "b_type"]) ?? "--",
|
||||
owner: getRowValue(row, ["owner", "owner_name", "v_sales_name", "b_owner_id"]) ?? "--",
|
||||
customer: getRowValue(row, ["customer", "customer_name", "v_customer_company"]) ?? "--",
|
||||
amount: getRowValue(row, ["amount", "total_amount", "b_amount"]) ?? "--",
|
||||
currency: getRowValue(row, ["currency", "currency_code", "b_currency"]) ?? "",
|
||||
updated_at:
|
||||
getRowValue(row, ["updated_at", "b_updatedatetime", "update_time", "updated_time"]) ?? "--",
|
||||
};
|
||||
});
|
||||
|
||||
function escapeSqlString(value) {
|
||||
return String(value).replaceAll("'", "''");
|
||||
}
|
||||
|
||||
async function loadDetail() {
|
||||
const currentSequence = ++loadSequence;
|
||||
const source = String(route.meta.source || "");
|
||||
if (!source || !recordId.value) {
|
||||
sourceRecord.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
loadError.value = "";
|
||||
sourceRecord.value = null;
|
||||
try {
|
||||
const response = await loadDataApi(source, `b_id = N'${escapeSqlString(recordId.value)}'`);
|
||||
if (currentSequence !== loadSequence) return;
|
||||
sourceRecord.value = Array.isArray(response.data) ? (response.data[0] ?? null) : null;
|
||||
if (!sourceRecord.value) loadError.value = "未找到对应记录";
|
||||
} catch (error) {
|
||||
if (currentSequence !== loadSequence) return;
|
||||
loadError.value = error.message || "详情加载失败";
|
||||
} finally {
|
||||
if (currentSequence === loadSequence) loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function backToList() {
|
||||
router.push(String(route.meta.listPath || "/dashboard"));
|
||||
}
|
||||
|
||||
watch([() => route.meta.source, recordId], loadDetail, { immediate: true });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -44,16 +90,24 @@ function backToList() {
|
||||
</header>
|
||||
|
||||
<main class="detail-content">
|
||||
<a-descriptions bordered size="small" :column="{ xs: 1, sm: 2, md: 3 }">
|
||||
<a-descriptions-item label="编号">{{ recordId }}</a-descriptions-item>
|
||||
<a-descriptions-item label="名称">{{ record.name }}</a-descriptions-item>
|
||||
<a-descriptions-item label="状态">{{ record.state }}</a-descriptions-item>
|
||||
<a-descriptions-item label="客户">{{ record.customer }}</a-descriptions-item>
|
||||
<a-descriptions-item label="业务类型">{{ record.businessType }}</a-descriptions-item>
|
||||
<a-descriptions-item label="负责人">{{ record.owner }}</a-descriptions-item>
|
||||
<a-descriptions-item label="金额">{{ record.amount }} {{ record.currency }}</a-descriptions-item>
|
||||
<a-descriptions-item label="更新时间">{{ record.updated_at }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<a-spin :spinning="loading">
|
||||
<a-alert v-if="loadError" type="error" show-icon :message="loadError">
|
||||
<template #action><a-button size="small" @click="loadDetail">重试</a-button></template>
|
||||
</a-alert>
|
||||
|
||||
<a-descriptions v-else bordered size="small" :column="3">
|
||||
<a-descriptions-item label="编号">{{ recordId }}</a-descriptions-item>
|
||||
<a-descriptions-item label="名称">{{ record.name }}</a-descriptions-item>
|
||||
<a-descriptions-item label="状态">{{ record.state }}</a-descriptions-item>
|
||||
<a-descriptions-item label="客户">{{ record.customer }}</a-descriptions-item>
|
||||
<a-descriptions-item label="业务类型">{{ record.businessType }}</a-descriptions-item>
|
||||
<a-descriptions-item label="负责人">{{ record.owner }}</a-descriptions-item>
|
||||
<a-descriptions-item label="金额">
|
||||
{{ record.amount }} {{ record.currency }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="更新时间">{{ record.updated_at }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-spin>
|
||||
|
||||
<section class="detail-remark">
|
||||
<div class="detail-remark__label">备注</div>
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user