From b58f53769f004fb0ba6b5aedf55ef602850c7c97 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期日, 20 九月 2026 15:46:05 +0800
Subject: [PATCH] 天津豹鸣app 1.部署修改
---
src/pages/projectManagement/project/_components/ProductRow.vue | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 363 insertions(+), 0 deletions(-)
diff --git a/src/pages/projectManagement/project/_components/ProductRow.vue b/src/pages/projectManagement/project/_components/ProductRow.vue
new file mode 100644
index 0000000..83e6fbe
--- /dev/null
+++ b/src/pages/projectManagement/project/_components/ProductRow.vue
@@ -0,0 +1,363 @@
+<!--
+ 椤圭洰浜у搧淇℃伅瀛愯〃鐨勪竴琛�
+
+ row 鐢辩埗绾� productList 鐨勫厓绱犵洿鎺ヤ紶鍏ワ紙鍚屼竴涓搷搴斿紡瀵硅薄锛夛紝
+ 缁勪欢鍐呯洿鎺ユ敼 row.xxx 鍗冲彲锛屼笉闇�瑕� emit 鍥炵埗绾у悎骞躲��
+ 浜у搧澶х被 / 瑙勬牸鍨嬪彿璧� up-action-sheet锛岄�夐」鐢辨湰缁勪欢鑷繁鎷夊彇銆�
+-->
+<template>
+ <view class="product-card">
+ <view class="product-header">
+ <text class="product-title">浜у搧 {{ index + 1 }}</text>
+ <up-icon name="trash"
+ color="#ee0a24"
+ size="18"
+ @click="$emit('remove')"></up-icon>
+ </view>
+ <up-divider></up-divider>
+
+ <view class="product-body">
+ <view class="field-row"
+ @click="openCategory">
+ <text class="field-label">浜у搧澶х被</text>
+ <text :class="['field-value', row.productCategory ? '' : 'placeholder']">
+ {{ row.productCategory || "璇烽�夋嫨浜у搧澶х被" }}
+ </text>
+ <up-icon name="arrow-right"
+ size="14"
+ color="#c0c4cc"></up-icon>
+ </view>
+
+ <view class="field-row"
+ @click="openModel">
+ <text class="field-label">瑙勬牸鍨嬪彿</text>
+ <text :class="['field-value', row.specificationModel ? '' : 'placeholder']">
+ {{ row.specificationModel || "璇烽�夋嫨瑙勬牸鍨嬪彿" }}
+ </text>
+ <up-icon name="arrow-right"
+ size="14"
+ color="#c0c4cc"></up-icon>
+ </view>
+
+ <view class="field-row">
+ <text class="field-label">鍗曚綅</text>
+ <u-input v-model="row.unit"
+ placeholder="璇疯緭鍏ュ崟浣�"
+ border="none"
+ inputAlign="right" />
+ </view>
+
+ <view class="field-row">
+ <text class="field-label">鏁伴噺</text>
+ <u-input v-model="row.quantity"
+ type="number"
+ placeholder="璇疯緭鍏ユ暟閲�"
+ border="none"
+ inputAlign="right" />
+ </view>
+
+ <view class="field-row"
+ @click="openTaxRate">
+ <text class="field-label">绋庣巼(%)</text>
+ <text :class="['field-value', row.taxRate ? '' : 'placeholder']">
+ {{ taxRateText || "璇烽�夋嫨绋庣巼" }}
+ </text>
+ <up-icon name="arrow-right"
+ size="14"
+ color="#c0c4cc"></up-icon>
+ </view>
+
+ <view class="field-row">
+ <text class="field-label">鍚◣鍗曚环</text>
+ <u-input v-model="row.taxInclusiveUnitPrice"
+ type="number"
+ placeholder="璇疯緭鍏ュ惈绋庡崟浠�"
+ border="none"
+ inputAlign="right" />
+ </view>
+
+ <view class="field-row">
+ <text class="field-label">鍚◣鎬讳环</text>
+ <text class="field-value readonly">{{ formatAmount(inclusiveTotal) }}</text>
+ </view>
+
+ <view class="field-row">
+ <text class="field-label">涓嶅惈绋庢�讳环</text>
+ <u-input v-model="row.taxExclusiveTotalPrice"
+ type="number"
+ placeholder="璇疯緭鍏ヤ笉鍚◣鎬讳环"
+ border="none"
+ inputAlign="right" />
+ </view>
+
+ <view class="field-row"
+ @click="openInvoiceType">
+ <text class="field-label">鍙戠エ绫诲瀷</text>
+ <text :class="['field-value', row.invoiceType ? '' : 'placeholder']">
+ {{ row.invoiceType || "璇烽�夋嫨鍙戠エ绫诲瀷" }}
+ </text>
+ <up-icon name="arrow-right"
+ size="14"
+ color="#c0c4cc"></up-icon>
+ </view>
+ </view>
+
+ <up-action-sheet :show="showCategorySheet"
+ title="閫夋嫨浜у搧澶х被"
+ :actions="categoryActions"
+ @select="onSelectCategory"
+ @close="showCategorySheet = false"></up-action-sheet>
+
+ <up-action-sheet :show="showModelSheet"
+ title="閫夋嫨瑙勬牸鍨嬪彿"
+ :actions="modelActions"
+ @select="onSelectModel"
+ @close="showModelSheet = false"></up-action-sheet>
+
+ <up-action-sheet :show="showTaxRateSheet"
+ title="閫夋嫨绋庣巼"
+ :actions="taxRateActions"
+ @select="onSelectTaxRate"
+ @close="showTaxRateSheet = false"></up-action-sheet>
+
+ <up-action-sheet :show="showInvoiceSheet"
+ title="閫夋嫨鍙戠エ绫诲瀷"
+ :actions="INVOICE_TYPE_ACTIONS"
+ @select="onSelectInvoiceType"
+ @close="showInvoiceSheet = false"></up-action-sheet>
+ </view>
+</template>
+
+<script setup>
+ import { computed, onMounted, ref } from "vue";
+ import { modelList, productTreeList } from "@/api/basicData/product";
+ import { productInclusiveTotal } from "../_utils/mapper";
+
+ const INVOICE_TYPE_ACTIONS = [
+ { name: "澧炴櫘绁�", value: "澧炴櫘绁�" },
+ { name: "澧炰笓绁�", value: "澧炰笓绁�" },
+ ];
+
+ const props = defineProps({
+ row: {
+ type: Object,
+ required: true,
+ },
+ index: {
+ type: Number,
+ default: 0,
+ },
+ // 绋庣巼瀛楀吀锛坲seDict('tax_rate') 鐨勮繑鍥炲�硷級
+ taxRateOptions: {
+ type: Array,
+ default: () => [],
+ },
+ });
+
+ defineEmits(["remove"]);
+
+ const categoryActions = ref([]);
+ const modelActions = ref([]);
+ const showCategorySheet = ref(false);
+ const showModelSheet = ref(false);
+ const showTaxRateSheet = ref(false);
+ const showInvoiceSheet = ref(false);
+
+ const inclusiveTotal = computed(() => productInclusiveTotal(props.row));
+
+ const taxRateActions = computed(() =>
+ (props.taxRateOptions || []).map(item => ({
+ name: item.label,
+ value: item.value,
+ }))
+ );
+
+ const taxRateText = computed(() => {
+ const matched = (props.taxRateOptions || []).find(
+ item => String(item.value) === String(props.row.taxRate)
+ );
+ return matched ? matched.label : "";
+ });
+
+ const formatAmount = value => Number(value || 0).toFixed(2);
+
+ const flattenTree = nodes => {
+ const result = [];
+ const walk = list => {
+ (list || []).forEach(item => {
+ if (item.children && item.children.length) {
+ walk(item.children);
+ } else {
+ result.push({
+ name: item.label || item.productName || "",
+ value: item.id || item.value,
+ });
+ }
+ });
+ };
+ walk(nodes);
+ return result;
+ };
+
+ const loadCategories = () => {
+ productTreeList()
+ .then(res => {
+ const nodes = Array.isArray(res) ? res : res?.data || [];
+ categoryActions.value = flattenTree(nodes);
+ })
+ .catch(() => {
+ categoryActions.value = [];
+ });
+ };
+
+ const openCategory = () => {
+ if (!categoryActions.value.length) loadCategories();
+ showCategorySheet.value = true;
+ };
+
+ const openModel = () => {
+ if (!props.row.productCategoryId) {
+ uni.showToast({ title: "璇峰厛閫夋嫨浜у搧澶х被", icon: "none" });
+ return;
+ }
+ if (!modelActions.value.length) {
+ uni.showToast({ title: "鏆傛棤瑙勬牸鍨嬪彿", icon: "none" });
+ return;
+ }
+ showModelSheet.value = true;
+ };
+
+ const openTaxRate = () => {
+ if (!taxRateActions.value.length) {
+ uni.showToast({ title: "鏆傛棤绋庣巼閫夐」", icon: "none" });
+ return;
+ }
+ showTaxRateSheet.value = true;
+ };
+
+ const openInvoiceType = () => {
+ showInvoiceSheet.value = true;
+ };
+
+ const onSelectCategory = action => {
+ showCategorySheet.value = false;
+ props.row.productCategoryId = action.value;
+ props.row.productCategory = action.name;
+ props.row.productModelId = "";
+ props.row.specificationModel = "";
+ props.row.unit = "";
+ modelActions.value = [];
+ modelList({ id: action.value })
+ .then(res => {
+ const rows = res?.data?.records || res?.data || res?.records || res || [];
+ modelActions.value = (Array.isArray(rows) ? rows : []).map(item => ({
+ name: item.model || item.specification || "",
+ value: item.id,
+ unit: item.unit,
+ }));
+ })
+ .catch(() => {
+ modelActions.value = [];
+ });
+ };
+
+ const onSelectModel = action => {
+ showModelSheet.value = false;
+ props.row.productModelId = action.value;
+ props.row.specificationModel = action.name;
+ if (action.unit) props.row.unit = action.unit;
+ };
+
+ const onSelectTaxRate = action => {
+ showTaxRateSheet.value = false;
+ props.row.taxRate = action.value;
+ };
+
+ const onSelectInvoiceType = action => {
+ showInvoiceSheet.value = false;
+ props.row.invoiceType = action.value;
+ };
+
+ // 鎵撳紑鍨嬪彿闈㈡澘鍓嶅厛鎶婂凡鏈夊ぇ绫诲搴旂殑鍨嬪彿鎹炲洖鏉ワ紙缂栬緫鍥炴樉鍦烘櫙锛�
+ onMounted(() => {
+ if (!props.row.productCategoryId) return;
+ modelList({ id: props.row.productCategoryId })
+ .then(res => {
+ const rows = res?.data?.records || res?.data || res?.records || res || [];
+ modelActions.value = (Array.isArray(rows) ? rows : []).map(item => ({
+ name: item.model || item.specification || "",
+ value: item.id,
+ unit: item.unit,
+ }));
+ // 鍙瓨浜嗗瀷鍙峰悕绉版椂鍙嶆煡 id锛屼繚璇侀�夋嫨鍣ㄨ兘鍛戒腑
+ if (!props.row.productModelId && props.row.specificationModel) {
+ const matched = modelActions.value.find(
+ item => item.name === props.row.specificationModel
+ );
+ if (matched) props.row.productModelId = matched.value;
+ }
+ })
+ .catch(() => {});
+ });
+</script>
+
+<style scoped lang="scss">
+ .product-card {
+ background: #fff;
+ border-radius: 12px;
+ padding: 0 12px 12px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+ }
+
+ .product-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 0;
+ }
+
+ .product-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: #22324d;
+ }
+
+ .product-body {
+ padding-top: 4px;
+ }
+
+ .field-row {
+ display: flex;
+ align-items: center;
+ min-height: 44px;
+ border-bottom: 1px solid #f5f6fa;
+ }
+
+ .field-row:last-child {
+ border-bottom: none;
+ }
+
+ .field-label {
+ width: 96px;
+ flex-shrink: 0;
+ font-size: 14px;
+ color: #606266;
+ }
+
+ .field-value {
+ flex: 1;
+ min-width: 0;
+ font-size: 14px;
+ color: #303133;
+ text-align: right;
+ word-break: break-all;
+ }
+
+ .field-value.placeholder {
+ color: #c0c4cc;
+ }
+
+ .field-value.readonly {
+ color: #909399;
+ }
+</style>
--
Gitblit v1.9.3