三方接口对接
This commit is contained in:
@@ -50,12 +50,13 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th><th>全名称</th><th>清单编号</th><th>清单名称</th><th>单位</th><th>合同数量</th><th>合同金额</th><th>填报日期</th><th>完成数量</th><th>完成金额</th><th>累计完成数量</th>
|
||||
<!-- <th>序号</th><th>全名称</th><th>清单编号</th><th>清单名称</th><th>单位</th><th>合同数量</th><th>合同金额</th><th>填报日期</th><th>完成数量</th><th>完成金额</th><th>累计完成数量</th>-->
|
||||
<th>序号</th><th>全名称</th><th>清单编号</th><th>清单名称</th><th>单位</th><th>合同数量</th><th>合同金额</th><th>合同金额不含税</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="r in progressRows" :key="r.no">
|
||||
<td>{{ r.no }}</td><td>{{ r.fullName }}</td><td>{{ r.code }}</td><td>{{ r.name }}</td><td>{{ r.unit }}</td><td>{{ formatNumber(r.contractQty,2) }}</td><td>{{ formatMoney(r.contractAmt) }}</td><td>{{ r.reportDate }}</td><td>{{ formatNumber(r.doneQty,2) }}</td><td>{{ formatMoney(r.doneAmt) }}</td><td>{{ formatNumber(r.cumDoneQty,2) }}</td>
|
||||
<td>{{ r.no }}</td><td>{{ r.fullName }}</td><td>{{ r.workCode }}</td><td>{{ r.name }}</td><td>{{ r.workUnit }}</td><td>{{ formatNumber(r.meteringNum,2) }}</td><td>{{ formatMoney(r.meteringAmt) }}</td><td>{{ formatMoney(r.meteringNotaxAmt) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -66,31 +67,22 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { computed, onMounted, reactive, ref } from "vue";
|
||||
import ModelPlaceholder from "../../components/model-placeholder/index.vue";
|
||||
import { progressApi } from "../../service/api/progress.js";
|
||||
|
||||
const structures = [
|
||||
{ id: "S-001", name: "主桥-0#墩" }, { id: "S-002", name: "主桥-1#墩" }, { id: "S-003", name: "主桥-2#墩" },
|
||||
{ id: "S-004", name: "引桥-桩基" }, { id: "S-005", name: "引桥-承台" }, { id: "S-006", name: "引桥-盖梁" },
|
||||
{ id: "S-007", name: "路基-填筑" }, { id: "S-008", name: "路面-基层" }, { id: "S-009", name: "路面-面层" },
|
||||
];
|
||||
|
||||
const elementTree = [
|
||||
{ id: "E-G-bridge", name: "桥梁工程", children: [
|
||||
{ id: "E-G-main-bridge", name: "主桥", children: ["S-001", "S-002", "S-003"].map((id) => ({ id, name: structures.find((s) => s.id === id)?.name || id })) },
|
||||
{ id: "E-G-approach", name: "引桥", children: ["S-004", "S-005", "S-006"].map((id) => ({ id, name: structures.find((s) => s.id === id)?.name || id })) },
|
||||
] },
|
||||
{ id: "E-G-road", name: "道路工程", children: ["S-007", "S-008", "S-009"].map((id) => ({ id, name: structures.find((s) => s.id === id)?.name || id })) },
|
||||
];
|
||||
|
||||
const structures = ref([]);
|
||||
const elementTree = ref([]);
|
||||
const progressData = ref([]);
|
||||
const sideCollapsed = ref(false);
|
||||
const bottomCollapsed = ref(false);
|
||||
const selectedStructureId = ref("S-001");
|
||||
const expanded = ref(new Set(["E-G-bridge", "E-G-main-bridge", "E-G-approach", "E-G-road"]));
|
||||
const selectedStructureId = ref("");
|
||||
const expanded = ref(new Set());
|
||||
const loading = ref(false);
|
||||
|
||||
const timeStatMode = ref("cutoff");
|
||||
const baselineDate = ref(todayISODate());
|
||||
const baselineOverallPercent = ref(61.54);
|
||||
const baselineOverallPercent = ref(0);
|
||||
const cutoffDate = ref(todayISODate());
|
||||
const cutoffDateDraft = ref(cutoffDate.value);
|
||||
|
||||
@@ -99,45 +91,119 @@ const percentFilters = reactive({ all: true, p0: false, p0_50: false, p50_100: f
|
||||
const visibleTreeRows = computed(() => {
|
||||
const rows = [];
|
||||
const walk = (node, level) => {
|
||||
const leaf = !node.children || node.children.length === 0;
|
||||
const leaf = node.isLeaf === true;
|
||||
const open = expanded.value.has(node.id);
|
||||
rows.push({ id: node.id, name: node.name, level, leaf, open });
|
||||
if (!leaf && open) node.children.forEach((c) => walk(c, level + 1));
|
||||
rows.push({ id: node.id, name: node.name, level, leaf, open, createDate: node.createDate });
|
||||
if (!leaf && open && node.children) {
|
||||
node.children.forEach((c) => walk(c, level + 1));
|
||||
}
|
||||
};
|
||||
elementTree.forEach((n) => walk(n, 0));
|
||||
elementTree.value.forEach((n) => walk(n, 0));
|
||||
return rows;
|
||||
});
|
||||
|
||||
const selectedStructureName = computed(() => structures.find((s) => s.id === selectedStructureId.value)?.name || "");
|
||||
const selectedStructureName = computed(() => {
|
||||
const findById = (nodes) => {
|
||||
for (const n of nodes) {
|
||||
if (n.id === selectedStructureId.value) return n.name;
|
||||
if (n.children) {
|
||||
const found = findById(n.children);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
};
|
||||
return findById(elementTree.value) || "";
|
||||
});
|
||||
|
||||
const selectedStructureNode = computed(() => {
|
||||
return findNode(elementTree.value, selectedStructureId.value);
|
||||
});
|
||||
|
||||
const overallPercent = computed(() => {
|
||||
const deltaDays = daysBetweenISO(baselineDate.value, cutoffDate.value);
|
||||
return clamp(baselineOverallPercent.value + deltaDays * 0.06, 0, 100);
|
||||
if (!selectedStructureNode.value) return 0;
|
||||
return 0;
|
||||
});
|
||||
|
||||
const progressRows = computed(() => {
|
||||
const reportDate = cutoffDate.value;
|
||||
return Array.from({ length: 16 }, (_, i) => {
|
||||
const contractQty = 30 + i * 2.2;
|
||||
const unitPrice = 860 + i * 30;
|
||||
const contractAmt = contractQty * unitPrice;
|
||||
const doneQty = contractQty * (0.03 + (i % 6) * 0.06);
|
||||
const doneAmt = doneQty * unitPrice;
|
||||
const cumDoneQty = contractQty * (0.18 + (i % 5) * 0.14);
|
||||
return {
|
||||
no: i + 1,
|
||||
fullName: selectedStructureName.value || structures[i % structures.length].name,
|
||||
code: `BOQ-${String(5001 + i)}`,
|
||||
name: ["混凝土浇筑", "钢筋制安", "模板工程", "土方开挖", "路基填筑", "防水层"][i % 6],
|
||||
unit: ["m³", "t", "㎡", "m³", "m³", "㎡"][i % 6],
|
||||
contractQty,
|
||||
contractAmt,
|
||||
reportDate,
|
||||
doneQty,
|
||||
doneAmt,
|
||||
cumDoneQty,
|
||||
};
|
||||
});
|
||||
if (!selectedStructureId.value) return [];
|
||||
return progressData.value.map((item, index) => ({
|
||||
no: index + 1,
|
||||
fullName: item.fullName || "",
|
||||
workCode: item.workCode || "",
|
||||
name: item.name || "",
|
||||
workUnit: item.workUnit || "-",
|
||||
meteringAmt: item.meteringAmt || 0,
|
||||
meteringNotaxAmt: item.meteringNotaxAmt || 0,
|
||||
meteringNum: item.meteringNum || 0,
|
||||
doneQty: item.doneQty || 0,
|
||||
doneAmt: item.doneAmt || 0,
|
||||
cumDoneQty: item.cumDoneQty || 0,
|
||||
}));
|
||||
});
|
||||
|
||||
async function loadWbsTree(parentId) {
|
||||
loading.value = true;
|
||||
try {
|
||||
const data = await progressApi.getTree(parentId);
|
||||
console.log(7777,data)
|
||||
if (!parentId) {
|
||||
elementTree.value = data.map((item) => ({
|
||||
...item,
|
||||
children: item.isLeaf ? [] : [],
|
||||
isLeaf: !!item.isLeaf,
|
||||
}));
|
||||
if (data.length > 0) {
|
||||
const firstLeaf = findFirstLeaf(elementTree.value);
|
||||
if (firstLeaf) selectedStructureId.value = firstLeaf.id;
|
||||
}
|
||||
} else {
|
||||
updateChildren(elementTree.value, parentId, data);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("加载WBS树失败:", e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function findFirstLeaf(nodes) {
|
||||
for (const n of nodes) {
|
||||
if (n.isLeaf) return n;
|
||||
if (n.children && n.children.length > 0) {
|
||||
const found = findFirstLeaf(n.children);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateChildren(nodes, parentId, children) {
|
||||
for (const n of nodes) {
|
||||
if (n.id === parentId) {
|
||||
n.children = children.map((item) => ({
|
||||
...item,
|
||||
children: item.isLeaf ? [] : [],
|
||||
isLeaf: !!item.isLeaf,
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
if (n.children && updateChildren(n.children, parentId, children)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function findNode(nodes, id) {
|
||||
for (const n of nodes) {
|
||||
if (n.id === id) return n;
|
||||
if (n.children) {
|
||||
const found = findNode(n.children, id);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadWbsTree();
|
||||
});
|
||||
|
||||
function todayISODate() {
|
||||
@@ -193,8 +259,46 @@ function applyAllExclusive(key, checked) {
|
||||
|
||||
function togglePercentFilter(key, checked) { applyAllExclusive(key, checked); }
|
||||
|
||||
function toggleTreeExpand(row) { if (!row.leaf) (expanded.value.has(row.id) ? expanded.value.delete(row.id) : expanded.value.add(row.id)); }
|
||||
function onTreeRowClick(row) { if (row.leaf) selectedStructureId.value = row.id; else toggleTreeExpand(row); }
|
||||
function toggleTreeExpand(row) {
|
||||
if (row.leaf) return;
|
||||
if (expanded.value.has(row.id)) {
|
||||
expanded.value.delete(row.id);
|
||||
} else {
|
||||
expanded.value.add(row.id);
|
||||
const node = findNode(elementTree.value, row.id);
|
||||
if (node && (!node.children || node.children.length === 0)) {
|
||||
loadWbsTree(row.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onTreeRowClick(row) {
|
||||
console.log(8888,row)
|
||||
if (row.leaf) {
|
||||
selectedStructureId.value = row.id;
|
||||
loadProgressData(row.id,row.createDate);
|
||||
} else {
|
||||
toggleTreeExpand(row);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadProgressData(positionId,time) {
|
||||
loading.value = true;
|
||||
try {
|
||||
const data = await progressApi.getPjProgress({
|
||||
projectId: "12e3c0eb186243869d94e214363ba083",
|
||||
positionIds: positionId,
|
||||
period: time,
|
||||
});
|
||||
progressData.value = data;
|
||||
console.log("进度数据:", data);
|
||||
} catch (e) {
|
||||
console.error("加载进度明细失败:", e);
|
||||
progressData.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
58
src/service/api/api.js
Normal file
58
src/service/api/api.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const BASE_URL = import.meta.env.VITE_API_BASE;
|
||||
|
||||
const MOCK_DELAY = 300;
|
||||
|
||||
const mock = (data, delay = MOCK_DELAY) =>
|
||||
new Promise((resolve) => setTimeout(() => resolve(data), delay));
|
||||
|
||||
export const fetchApi = async (url, options = {}) => {
|
||||
const fullUrl = url.startsWith("http") ? url : BASE_URL + url;
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
...options.headers,
|
||||
},
|
||||
...options,
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await fetch(fullUrl, config);
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
throw new Error(data.message || `请求失败: ${res.status}`);
|
||||
}
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`[API] ${options.method || "GET"} ${fullUrl}`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const get = (url, params, options = {}) => {
|
||||
const query = params
|
||||
? "?" + new URLSearchParams(params).toString()
|
||||
: "";
|
||||
return fetchApi(url + query, { ...options, method: "GET" });
|
||||
};
|
||||
|
||||
export const post = (url, data, options = {}) =>
|
||||
fetchApi(url, {
|
||||
...options,
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
export const put = (url, data, options = {}) =>
|
||||
fetchApi(url, {
|
||||
...options,
|
||||
method: "PUT",
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
export const del = (url, options = {}) =>
|
||||
fetchApi(url, { ...options, method: "DELETE" });
|
||||
|
||||
export { mock };
|
||||
25
src/service/api/progress.js
Normal file
25
src/service/api/progress.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { get, post } from "./api.js";
|
||||
|
||||
export const FILTER_NAMES = ["隧道工程", "桥梁工程", "道路工程"];
|
||||
|
||||
export const DEFAULT_PROJECT_ID = "12e3c0eb186243869d94e214363ba083";
|
||||
|
||||
export const progressApi = {
|
||||
getTree(parentId) {
|
||||
const params = { projectId: DEFAULT_PROJECT_ID };
|
||||
if (parentId) params.parentId = parentId;
|
||||
return get("/api/bim/wbs", params).then((res) => {
|
||||
const raw = res?.data?.data || [];
|
||||
if (!parentId) {
|
||||
return raw.filter((item) => FILTER_NAMES.includes(item.name));
|
||||
}
|
||||
return raw;
|
||||
});
|
||||
},
|
||||
|
||||
getPjProgress({ projectId, positionIds, period }) {
|
||||
return post("/api/bim/getPjDayListByPositionId", { projectId, positionIds, period }).then((res) => {
|
||||
return res?.data?.data || [];
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user