From f9608b880eb17ed232b1dc9c216ae57a7fb5b4a9 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 21 九月 2026 18:06:58 +0800
Subject: [PATCH] 新疆-融邦环保 1.「油品出库就生成出库台账,不用区分出库类别了」+「代储出库也需要出库扣库存,选批号,生成发货台账」 2.车辆管理与出库残油联动
---
src/components/AttachmentUpload/image/index.vue | 10 ++
src/views/basicData/product/index.vue | 3
src/views/basicData/vehicle/index.vue | 38 ++++++++++++
src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue | 125 +++++++++++++++++++++--------------------
4 files changed, 109 insertions(+), 67 deletions(-)
diff --git a/src/components/AttachmentUpload/image/index.vue b/src/components/AttachmentUpload/image/index.vue
index 8243f9c..00b1582 100644
--- a/src/components/AttachmentUpload/image/index.vue
+++ b/src/components/AttachmentUpload/image/index.vue
@@ -1,6 +1,6 @@
<script setup>
import {Plus} from '@element-plus/icons-vue'
-import {uploadFile} from '@/api/basicData/common'
+import {uploadFile, uploadPublicFile} from '@/api/basicData/common'
const props = defineProps({
fileList: {
@@ -38,6 +38,12 @@
uploadFieldName: {
type: String,
default: 'files',
+ },
+ // 涓绘暟鎹暱鏈熷彲鐪嬬殑鍥剧墖璧� /common/public/upload锛坧ublicKey 姘镐箙鍦板潃锛夛紝
+ // 榛樿浠嶈蛋 /common/upload锛堝甫 2 灏忔椂澶辨晥鐨� token锛変互淇濇寔鏃㈡湁琛屼负
+ permanent: {
+ type: Boolean,
+ default: false,
},
})
@@ -204,7 +210,7 @@
proxy.$modal.loading('鍥剧墖涓婁紶涓紝璇风◢鍊�...')
try {
- const response = await uploadFile(formData)
+ const response = await (props.permanent ? uploadPublicFile(formData) : uploadFile(formData))
const responseList = extractResponseArray(response).map((item, index) => normalizeResponseItem(item, index))
if (!responseList.length) {
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index b05b215..542c8a0 100644
--- a/src/views/basicData/product/index.vue
+++ b/src/views/basicData/product/index.vue
@@ -9,8 +9,7 @@
@clear="searchFilter"
clearable
prefix-icon="Search" />
- <el-button v-if="false"
- type="primary"
+ <el-button type="primary"
@click="openProDia('addOne')"
style="margin-left: 10px">鏂板浜у搧澶х被</el-button>
</div>
diff --git a/src/views/basicData/vehicle/index.vue b/src/views/basicData/vehicle/index.vue
index 26e2200..81c6904 100644
--- a/src/views/basicData/vehicle/index.vue
+++ b/src/views/basicData/vehicle/index.vue
@@ -83,6 +83,19 @@
</el-tag>
</template>
</el-table-column>
+ <el-table-column label="杞﹁締鐓х墖"
+ min-width="100"
+ align="center">
+ <template #default="scope">
+ <el-image v-if="scope.row.vehiclePhotos && scope.row.vehiclePhotos.length"
+ :src="scope.row.vehiclePhotos[0]"
+ :preview-src-list="scope.row.vehiclePhotos"
+ preview-teleported
+ fit="cover"
+ style="width: 60px; height: 44px; border-radius: 4px" />
+ <span v-else>--</span>
+ </template>
+ </el-table-column>
<el-table-column label="澶囨敞"
prop="remark"
min-width="160"
@@ -196,6 +209,16 @@
</el-form-item>
</el-col>
</el-row>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="杞﹁締鐓х墖锛�"
+ prop="vehiclePhotos">
+ <ImageUpload v-model:file-list="form.vehiclePhotos"
+ :limit="10"
+ permanent />
+ </el-form-item>
+ </el-col>
+ </el-row>
</el-form>
</FormDialog>
</div>
@@ -203,6 +226,7 @@
<script setup>
import FormDialog from "@/components/Dialog/FormDialog.vue";
+ import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref, reactive, toRefs, getCurrentInstance } from "vue";
import { ElMessageBox } from "element-plus";
@@ -239,6 +263,7 @@
loadCapacity: null,
status: "鍚敤",
remark: "",
+ vehiclePhotos: [],
},
rules: {
plateNumber: [{ required: true, message: "璇疯緭鍏ヨ溅鐗屽彿", trigger: "blur" }],
@@ -299,6 +324,8 @@
loadCapacity,
status: status || "鍚敤",
remark,
+ // 鎺ュ彛杩斿洖鐨勫氨鏄� URL 瀛楃涓叉暟缁勶紝鐩存帴鍠傜粰 el-upload 鍥炴樉
+ vehiclePhotos: Array.isArray(row.vehiclePhotos) ? [...row.vehiclePhotos] : [],
};
} else {
form.value = {
@@ -309,6 +336,7 @@
loadCapacity: null,
status: "鍚敤",
remark: "",
+ vehiclePhotos: [],
};
}
};
@@ -317,7 +345,15 @@
proxy.$refs["formRef"].validate(valid => {
if (valid) {
const api = form.value.id ? updateVehicle : addVehicle;
- api(form.value).then(() => {
+ // 鍚庣 vehiclePhotos 鏄� List<String>锛屽彧瀛� URL锛涗笂浼犵粍浠剁粰鐨勬槸 {name, url} 瀵硅薄鏁扮粍锛�
+ // 鐩存帴浼犲璞′細 JSON 瑙f瀽澶辫触鎶� 400銆傚彟澶栦紶 null 涓嶆洿鏂帮紝鎯冲垹鍏夊繀椤绘樉寮忎紶 []
+ const payload = {
+ ...form.value,
+ vehiclePhotos: (form.value.vehiclePhotos || [])
+ .map(item => (typeof item === "string" ? item : item?.url || item?.previewURL || ""))
+ .filter(Boolean),
+ };
+ api(payload).then(() => {
proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
closeDia();
getList();
diff --git a/src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue b/src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue
index 7b361a9..4272035 100644
--- a/src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue
+++ b/src/views/inventoryManagement/stockManagement/OilStockOutDialog.vue
@@ -32,56 +32,54 @@
</el-form-item>
</el-col>
</el-row>
- <template v-if="!isStorageBound">
- <el-row :gutter="30">
- <el-col :span="24">
- <el-form-item label="浜у搧鍚嶇О"
- prop="productModelId"
- :rules="[
- {
- required: true,
- message: '璇烽�夋嫨浜у搧',
- trigger: 'change',
- }
- ]">
- <!-- 缁戝畾鍗栨补鍙拌处鍚庯紝浜у搧鍙兘浠庤鍙拌处鏄庣粏閲岄�夛紙浠e偍鍙拌处娌℃湁鏄庣粏锛� -->
- <el-select v-if="hasBoundLedger"
- v-model="formState.productModelId"
- placeholder="璇烽�夋嫨鍙拌处浜у搧"
- filterable
- clearable
- style="width: 100%"
- @change="handleLedgerProductChange">
- <el-option v-for="(item, index) in ledgerProductOptions"
- :key="`${item.productModelId}-${index}`"
- :label="ledgerProductLabel(item)"
- :value="item.productModelId" />
- </el-select>
- <el-button v-else
- type="primary"
- @click="showProductSelectDialog = true">
- {{ formState.productName ? formState.productName : '閫夋嫨浜у搧' }}
- </el-button>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="瑙勬牸"
- prop="model">
- <el-input v-model="formState.model"
- disabled />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鍗曚綅"
- prop="unit">
- <el-input v-model="formState.unit"
- disabled />
- </el-form-item>
- </el-col>
- </el-row>
- </template>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="浜у搧鍚嶇О"
+ prop="productModelId"
+ :rules="[
+ {
+ required: true,
+ message: '璇烽�夋嫨浜у搧瑙勬牸',
+ trigger: 'change',
+ }
+ ]">
+ <!-- 缁戝畾鍗栨补鍙拌处鍚庝骇鍝佸彧鑳戒粠璇ュ彴璐︽槑缁嗛噷閫夛紱浠e偍鍙拌处娌℃湁鏄庣粏锛屼粛璧颁骇鍝侀�夋嫨寮圭獥 -->
+ <el-select v-if="useLedgerProducts"
+ v-model="formState.productModelId"
+ placeholder="璇烽�夋嫨鍙拌处浜у搧"
+ filterable
+ clearable
+ style="width: 100%"
+ @change="handleLedgerProductChange">
+ <el-option v-for="(item, index) in ledgerProductOptions"
+ :key="`${item.productModelId}-${index}`"
+ :label="ledgerProductLabel(item)"
+ :value="item.productModelId" />
+ </el-select>
+ <el-button v-else
+ type="primary"
+ @click="showProductSelectDialog = true">
+ {{ formState.productName ? formState.productName : '閫夋嫨浜у搧' }}
+ </el-button>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="瑙勬牸"
+ prop="model">
+ <el-input v-model="formState.model"
+ disabled />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍗曚綅"
+ prop="unit">
+ <el-input v-model="formState.unit"
+ disabled />
+ </el-form-item>
+ </el-col>
+ </el-row>
<div class="form-section-title">鍑哄簱淇℃伅</div>
<el-row :gutter="30">
<el-col :span="8">
@@ -105,9 +103,7 @@
<el-col :span="8">
<el-form-item label="鍑哄簱鎵规"
prop="batchNo"
- :rules="isSalesOut
- ? [{ required: true, message: '閿�鍞被鍑哄簱蹇呴』閫夋嫨鍑哄簱鎵规', trigger: 'change' }]
- : []">
+ :rules="[{ required: true, message: '娌瑰搧鍑哄簱蹇呴』閫夋嫨鍑哄簱鎵规', trigger: 'change' }]">
<el-select v-model="formState.batchNo"
placeholder="璇烽�夋嫨"
clearable
@@ -396,7 +392,9 @@
<el-col :span="12">
<el-form-item label="杞︽寕鐗屽彿"
prop="trailerPlateNo"
- :rules="[{ required: true, message: '璇疯緭鍏ヨ溅鎸傜墝鍙�', trigger: 'blur' }]">
+ :rules="isSalesOut
+ ? [{ required: true, message: '璇疯緭鍏ヨ溅鎸傜墝鍙�', trigger: 'blur' }]
+ : []">
<el-input v-model="formState.trailerPlateNo"
:readonly="!!formState.vehicleId"
placeholder="璇疯緭鍏�"
@@ -455,7 +453,7 @@
</el-col>
</el-row>
<el-row :gutter="30"
- v-if="isSalesOut">
+ v-if="formState.productModelId">
<el-col :span="24">
<el-form-item label="鍙敤閲�">
<div class="available-qty-tip">
@@ -567,8 +565,10 @@
const productModelCache = ref(null);
const hasBoundLedger = computed(() => !!formState.value.salesLedgerId);
- // 缁戜唬鍌ㄥ彴璐︼細涓嶇敤閫変骇鍝侊紝娌瑰簱/鍌ㄧ綈鐢卞彴璐﹀甫鍏�
+ // 缁戜唬鍌ㄥ彴璐︼細娌瑰簱/鍌ㄧ綈鐢卞彴璐﹀甫鍏ワ紝浣嗕骇鍝佷粛瑕侀�夛紙浠e偍鍑哄簱涔熻鎵e簱瀛橈級
const isStorageBound = computed(() => boundLedgerRow.value?.ledgerType === "浠e偍");
+ // 鍙湁鍗栨补鍙拌处鏈変骇鍝佹槑缁嗗彲鎸戯紱浠e偍鍙拌处娌℃槑缁嗭紝璧颁骇鍝侀�夋嫨寮圭獥
+ const useLedgerProducts = computed(() => hasBoundLedger.value && !isStorageBound.value);
const fetchBatchNoOptions = () => {
batchNoOptions.value = [];
@@ -588,14 +588,15 @@
});
};
- // 閿�鍞被鍑哄簱蹇呴』缁欏嚭搴撴壒娆★紙鍚庣鏂板鏃跺嵆鏍¢獙锛屼笖瀹℃壒閫氳繃浼氭寜鎵规鎵e簱瀛橈級
+ // 杞﹁締鍙湁閿�鍞被鍑哄簱蹇呭~锛堥攢鍞被鎵嶆寜杞︾畻銆屼笂娆″墿浣欐补閲忋�嶏紝浠e偍/瀹㈠瓨娈嬫补鎸� 0锛�
const isSalesOut = computed(() => formState.value.outCategory === "閿�鍞�");
- // 鍙敤閲忔彁绀猴細杞﹁締 + 瑙勬牸锛�+鎵规锛夌‘瀹氬悗鍚戝悗绔彇銆屼笂娆″墿浣� / 褰撳墠搴撳瓨 / 鍙敤閲忋��
+ // 鍙敤閲忔彁绀猴細瑙勬牸锛�+鎵规+杞﹁締锛夌‘瀹氬悗鍚戝悗绔彇銆屼笂娆″墿浣� / 褰撳墠搴撳瓨 / 鍙敤閲忋�嶃��
+ // 浠e偍/瀹㈠瓨娌℃湁杞﹁締锛屼笉浼� vehicleId锛屽悗绔寜涓婃鍓╀綑 0 澶勭悊锛屽彲鐢ㄩ噺 = 褰撳墠搴撳瓨
const fetchAvailableQty = () => {
availableQty.value = null;
const { vehicleId, productModelId, batchNo } = formState.value;
- if (!isSalesOut.value || !vehicleId || !productModelId) {
+ if (!productModelId) {
return;
}
getOilOutAvailableQty({ vehicleId, productModelId, batchNo })
@@ -911,9 +912,9 @@
const handleSubmit = () => {
proxy.$refs["formRef"].validate(valid => {
if (valid) {
- // 缁戜唬鍌ㄥ彴璐︿笉鐢ㄩ�変骇鍝侊紙浠e偍鍙拌处娌℃湁浜у搧鏄庣粏锛�
- if (!formState.value.productModelId && !isStorageBound.value) {
- proxy.$modal.msgError("璇烽�夋嫨浜у搧");
+ // 閿�鍞�/浠e偍/瀹㈠瓨閮借鎵e簱瀛橈紝涓�寰嬪繀椤婚�夎鏍硷紙浠e偍鍙拌处娌℃槑缁嗭紝浠庝骇鍝佸脊绐楅�夛級
+ if (!formState.value.productModelId) {
+ proxy.$modal.msgError("璇烽�夋嫨浜у搧瑙勬牸");
return;
}
// 璁$畻缁撴灉闅忚〃鍗曟彁浜�
--
Gitblit v1.9.3