From 88f5470dc4829e2bdde9dc4aeb79be85837c1c84 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期六, 16 五月 2026 10:08:22 +0800
Subject: [PATCH] 发货功能重构
---
src/pages/sales/salesAccount/goOut.vue | 976 +++++++++++++++++++++--------------------------------
src/api/inventoryManagement/stockInventory.js | 104 +++--
2 files changed, 441 insertions(+), 639 deletions(-)
diff --git a/src/api/inventoryManagement/stockInventory.js b/src/api/inventoryManagement/stockInventory.js
index c4115ea..328657c 100644
--- a/src/api/inventoryManagement/stockInventory.js
+++ b/src/api/inventoryManagement/stockInventory.js
@@ -1,70 +1,78 @@
import request from "@/utils/request";
// 鍒嗛〉鏌ヨ搴撳瓨璁板綍鍒楄〃
-export const getStockInventoryListPage = (params) => {
- return request({
- url: "/stockInventory/pagestockInventory",
- method: "get",
- params,
- });
+export const getStockInventoryListPage = params => {
+ return request({
+ url: "/stockInventory/pagestockInventory",
+ method: "get",
+ params,
+ });
};
// 鍒嗛〉鏌ヨ鑱斿悎搴撳瓨璁板綍鍒楄〃锛堝寘鍚晢鍝佷俊鎭級
-export const getStockInventoryListPageCombined = (params) => {
- return request({
- url: "/stockInventory/pageListCombinedStockInventory",
- method: "get",
- params,
- });
+export const getStockInventoryListPageCombined = params => {
+ return request({
+ url: "/stockInventory/pageListCombinedStockInventory",
+ method: "get",
+ params,
+ });
};
// 鍒涘缓搴撳瓨璁板綍
-export const createStockInventory = (params) => {
- return request({
- url: "/stockInventory/addstockInventory",
- method: "post",
- data: params,
- });
+export const createStockInventory = params => {
+ return request({
+ url: "/stockInventory/addstockInventory",
+ method: "post",
+ data: params,
+ });
};
// 鍑忓皯搴撳瓨璁板綍
-export const subtractStockInventory = (params) => {
- return request({
- url: "/stockInventory/subtractStockInventory",
- method: "post",
- data: params,
- });
+export const subtractStockInventory = params => {
+ return request({
+ url: "/stockInventory/subtractStockInventory",
+ method: "post",
+ data: params,
+ });
};
-export const getStockInventoryReportList = (params) => {
- return request({
- url: "/stockInventory/stockInventoryPage",
- method: "get",
- params,
- });
+export const getStockInventoryReportList = params => {
+ return request({
+ url: "/stockInventory/stockInventoryPage",
+ method: "get",
+ params,
+ });
};
-export const getStockInventoryInAndOutReportList = (params) => {
- return request({
- url: "/stockInventory/stockInAndOutRecord",
- method: "get",
- params,
- });
+export const getStockInventoryInAndOutReportList = params => {
+ return request({
+ url: "/stockInventory/stockInAndOutRecord",
+ method: "get",
+ params,
+ });
};
// 鍐荤粨搴撳瓨璁板綍
-export const frozenStockInventory = (params) => {
- return request({
- url: "/stockInventory/frozenStock",
- method: "post",
- data: params,
- });
+export const frozenStockInventory = params => {
+ return request({
+ url: "/stockInventory/frozenStock",
+ method: "post",
+ data: params,
+ });
};
// 瑙e喕搴撳瓨璁板綍
-export const thawStockInventory = (params) => {
- return request({
- url: "/stockInventory/thawStock",
- method: "post",
- data: params,
- });
+export const thawStockInventory = params => {
+ return request({
+ url: "/stockInventory/thawStock",
+ method: "post",
+ data: params,
+ });
+};
+
+export const getStockInventoryByModelId = productModelId => {
+ return request({
+ url: "/stockInventory/getByModelId",
+ method: "get",
+ params: { productModelId },
+ });
};
diff --git a/src/pages/sales/salesAccount/goOut.vue b/src/pages/sales/salesAccount/goOut.vue
index 9980e5f..42321c9 100644
--- a/src/pages/sales/salesAccount/goOut.vue
+++ b/src/pages/sales/salesAccount/goOut.vue
@@ -1,657 +1,451 @@
<template>
- <view class="account-detail">
+ <view class="shipment-page">
<PageHeader title="鍙戣揣"
@back="goBack" />
- <!-- 琛ㄥ崟鍖哄煙 -->
- <u-form ref="formRef"
- @submit="submitForm"
- :rules="rules"
- :model="form"
- label-width="140rpx">
- <u-form-item prop="typeValue"
- label="鍙戣揣绫诲瀷"
- required>
- <u-input v-model="typeValue"
- readonly
- placeholder="璇烽�夋嫨鍙戣揣鏂瑰紡"
- @click="showPicker = true" />
- <template #right>
- <up-icon name="arrow-right"
- @click="showPicker = true"></up-icon>
- </template>
- </u-form-item>
- </u-form>
- <!-- 閫夋嫨鍣ㄥ脊绐� -->
- <up-action-sheet :show="showPicker"
- :actions="productOptions"
- title="鍙戣揣鏂瑰紡"
- @select="onConfirm"
- @close="showPicker = false" />
- <!-- 瀹℃牳娴佺▼鍖哄煙 -->
- <view class="approval-process">
- <view class="approval-header">
- <text class="approval-title">瀹℃牳娴佺▼</text>
- <text class="approval-desc">姣忎釜姝ラ鍙兘閫夋嫨涓�涓鎵逛汉</text>
- </view>
- <view class="approval-steps">
- <view v-for="(step, stepIndex) in approverNodes"
- :key="stepIndex"
- class="approval-step">
- <view class="step-dot"></view>
- <view class="step-title">
- <text>瀹℃壒浜�</text>
+ <view class="form-container">
+ <up-form ref="formRef"
+ :model="form"
+ :rules="rules"
+ label-width="100"
+ input-align="right"
+ error-message-align="right">
+ <!-- 鍩烘湰淇℃伅 -->
+ <u-cell-group title="鍩烘湰淇℃伅"
+ class="form-section">
+ <up-form-item label="鍙戣揣鏂瑰紡"
+ prop="type"
+ required>
+ <up-input v-model="form.type"
+ readonly
+ placeholder="璇烽�夋嫨鍙戣揣鏂瑰紡"
+ @click="showTypePicker = true" />
+ <template #right>
+ <up-icon name="arrow-right"
+ @click="showTypePicker = true"></up-icon>
+ </template>
+ </up-form-item>
+ <block v-if="form.type === '璐ц溅'">
+ <up-form-item label="鍙戣揣杞︾墝"
+ prop="shippingCarNumber"
+ required>
+ <up-input v-model="form.shippingCarNumber"
+ placeholder="璇疯緭鍏ュ彂璐ц溅鐗屽彿"
+ clearable />
+ </up-form-item>
+ </block>
+ <block v-if="form.type === '蹇��'">
+ <up-form-item label="蹇�掑叕鍙�"
+ prop="expressCompany"
+ required>
+ <up-input v-model="form.expressCompany"
+ placeholder="璇疯緭鍏ュ揩閫掑叕鍙�"
+ clearable />
+ </up-form-item>
+ <up-form-item label="蹇�掑崟鍙�"
+ prop="expressNumber"
+ required>
+ <up-input v-model="form.expressNumber"
+ placeholder="璇疯緭鍏ュ揩閫掑崟鍙�"
+ clearable />
+ </up-form-item>
+ </block>
+ </u-cell-group>
+ <!-- 鎵规閫夋嫨 -->
+ <u-cell-group title="鎵规閫夋嫨"
+ class="form-section">
+ <view class="section-header-info">
+ <text class="subtitle">寰呭彂璐ф暟閲�: {{ goOutData.noQuantity || 0 }}</text>
</view>
- <view class="approver-container">
- <view v-if="step.nickName"
- class="approver-item">
- <view class="approver-avatar">
- <text class="avatar-text">{{ step.nickName.charAt(0) }}</text>
- <view class="status-dot"></view>
+ <view v-if="batchList.length === 0"
+ class="empty-text">
+ <text>鏆傛棤鍙敤搴撳瓨鎵规</text>
+ </view>
+ <view v-else
+ class="batch-list">
+ <view v-for="(item, index) in batchList"
+ :key="index"
+ class="batch-card">
+ <view class="batch-header">
+ <text class="batch-no">鎵瑰彿: {{ item.batchNo }}</text>
+ <text class="batch-qty">搴撳瓨: {{ getAvailableQty(item) }}</text>
</view>
- <view class="approver-info">
- <text class="approver-name">{{ step.nickName }}</text>
+ <up-divider></up-divider>
+ <view class="batch-body">
+ <up-form-item label="鍙戣揣鏁伴噺">
+ <up-input v-model="item.deliveryQuantity"
+ type="digit"
+ placeholder="0.00"
+ input-align="right"
+ @blur="onBatchQtyChange(item)" />
+ </up-form-item>
</view>
- <view class="delete-approver-btn"
- @click="removeApprover(stepIndex)">脳</view>
- </view>
- <view v-else
- class="add-approver-btn"
- @click="addApprover(stepIndex)">
- <view class="add-circle">+</view>
- <text class="add-label">閫夋嫨瀹℃壒浜�</text>
</view>
</view>
- <view class="step-line"
- v-if="stepIndex < approverNodes.length - 1"></view>
- <view class="delete-step-btn"
- v-if="approverNodes.length > 1"
- @click="removeApprovalStep(stepIndex)">鍒犻櫎鑺傜偣</view>
- </view>
- </view>
- <view class="add-step-btn">
- <u-button icon="plus"
- plain
- type="primary"
- style="width: 100%"
- @click="addApprovalStep">鏂板鑺傜偣</u-button>
- </view>
+ </u-cell-group>
+ <!-- 鍙戣揣鍥剧墖 -->
+ <u-cell-group title="鍙戣揣鍥剧墖"
+ class="form-section">
+ <view class="upload-container">
+ <up-upload :fileList="fileList"
+ @afterRead="afterRead"
+ @delete="deleteFile"
+ multiple
+ :maxCount="9"
+ width="160rpx"
+ height="160rpx" />
+ </view>
+ </u-cell-group>
+ </up-form>
</view>
<!-- 搴曢儴鎸夐挳 -->
- <view class="footer-btns">
- <u-button class="cancel-btn"
- @click="goBack">鍙栨秷</u-button>
- <u-button class="save-btn"
- @click="submitForm">鍙戣揣</u-button>
- </view>
+ <FooterButtons confirmText="纭鍙戣揣"
+ @cancel="goBack"
+ @confirm="submitForm" />
+ <!-- 鍙戣揣鏂瑰紡閫夋嫨鍣� -->
+ <up-action-sheet :show="showTypePicker"
+ :actions="typeActions"
+ title="鍙戣揣鏂瑰紡"
+ @select="onTypeSelect"
+ @close="showTypePicker = false" />
</view>
</template>
<script setup>
- import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
+ import config from "@/config";
+ import { ref, onMounted, reactive } from "vue";
import PageHeader from "@/components/PageHeader.vue";
+ import FooterButtons from "@/components/FooterButtons.vue";
import { addShippingInfo } from "@/api/salesManagement/salesLedger";
- const showToast = message => {
- uni.showToast({
- title: message,
- icon: "none",
- });
- };
- import { userListNoPageByTenantId } from "@/api/system/user";
+ import { getStockInventoryByModelId } from "@/api/inventoryManagement/stockInventory";
+ import { getToken } from "@/utils/auth";
- const data = reactive({
- form: {
- approveTime: "",
- approveId: "",
- approveUser: "",
- approveUserName: "",
- approveDeptName: "",
- approveDeptId: "",
- approveReason: "",
- checkResult: "",
- tempFileIds: [],
- approverList: [], // 鏂板瀛楁锛屽瓨鍌ㄦ墍鏈夎妭鐐圭殑瀹℃壒浜篿d
- startDate: "",
- endDate: "",
- location: "",
- price: "",
- },
- rules: {
- typeValue: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
- },
- });
- const { form, rules } = toRefs(data);
- const showPicker = ref(false);
- const productOptions = ref([
- {
- value: "璐ц溅",
- name: "璐ц溅",
- },
- {
- value: "蹇��",
- name: "蹇��",
- },
- ]);
- const operationType = ref("");
- const currentApproveStatus = ref("");
- const approverNodes = ref([]);
- const userList = ref([]);
- const formRef = ref(null);
- const approveType = ref(0);
const goOutData = ref({});
+ const batchList = ref([]);
+ const fileList = ref([]);
+ const showTypePicker = ref(false);
+ const typeActions = [
+ { name: "璐ц溅", value: "璐ц溅" },
+ { name: "蹇��", value: "蹇��" },
+ ];
+
+ const form = reactive({
+ type: "璐ц溅",
+ shippingCarNumber: "",
+ expressCompany: "",
+ expressNumber: "",
+ });
+
+ const rules = {
+ type: [{ required: true, message: "璇烽�夋嫨鍙戣揣鏂瑰紡", trigger: "change" }],
+ shippingCarNumber: [
+ {
+ required: true,
+ validator: (rule, value, callback) => {
+ if (form.type === "璐ц溅" && !value) {
+ return false;
+ }
+ return true;
+ },
+ message: "璇疯緭鍏ヨ溅鐗屽彿",
+ trigger: "blur",
+ },
+ ],
+ expressCompany: [
+ {
+ required: true,
+ validator: (rule, value, callback) => {
+ if (form.type === "蹇��" && !value) {
+ return false;
+ }
+ return true;
+ },
+ message: "璇疯緭鍏ュ揩閫掑叕鍙�",
+ trigger: "blur",
+ },
+ ],
+ expressNumber: [
+ {
+ required: true,
+ validator: (rule, value, callback) => {
+ if (form.type === "蹇��" && !value) {
+ return false;
+ }
+ return true;
+ },
+ message: "璇疯緭鍏ュ揩閫掑崟鍙�",
+ trigger: "blur",
+ },
+ ],
+ };
+
+ const formRef = ref(null);
+
onMounted(async () => {
- try {
- userListNoPageByTenantId().then(res => {
- userList.value = res.data;
- });
- // 浠庢湰鍦板瓨鍌ㄨ幏鍙栧彂璐ц鎯�
- goOutData.value = JSON.parse(uni.getStorageSync("goOutData"));
- console.log(goOutData.value, "goOutData.value");
-
- // 鍒濆鍖栧鎵规祦绋嬭妭鐐癸紝榛樿涓�涓妭鐐�
- approverNodes.value = [{ id: 1, userId: null }];
-
- // 鐩戝惉鑱旂郴浜洪�夋嫨浜嬩欢
- uni.$on("selectContact", handleSelectContact);
- } catch (error) {
- console.error("鑾峰彇澶辫触:", error);
+ const storedData = uni.getStorageSync("goOutData");
+ goOutData.value = JSON.parse(storedData || "{}");
+ if (goOutData.value.productModelId) {
+ loadBatches(goOutData.value.productModelId);
}
});
- onUnmounted(() => {
- // 绉婚櫎浜嬩欢鐩戝惉
- uni.$off("selectContact", handleSelectContact);
- });
- const typeValue = ref("璐ц溅");
- const onConfirm = item => {
- // 璁剧疆閫変腑鐨勯儴闂�
- typeValue.value = item.name;
- showPicker.value = false;
+ const loadBatches = async modelId => {
+ if (!modelId) return;
+ try {
+ const res = await getStockInventoryByModelId(modelId);
+ const rawList = Array.isArray(res?.data)
+ ? res.data
+ : res?.data?.records || res?.data?.rows || res || [];
+ const seenIds = new Set();
+ batchList.value = rawList
+ .filter(item => {
+ if (!item?.id || !item?.batchNo || seenIds.has(item.id)) {
+ return false;
+ }
+ seenIds.add(item.id);
+ return true;
+ })
+ .map(item => ({
+ ...item,
+ deliveryQuantity: "",
+ }));
+ } catch (e) {
+ console.error("鍔犺浇鎵规澶辫触", e);
+ }
};
- const goBack = () => {
- // 娓呴櫎鏈湴瀛樺偍鐨勬暟鎹�
- uni.removeStorageSync("operationType");
- uni.removeStorageSync("invoiceLedgerEditRow");
- uni.removeStorageSync("approveType");
- uni.navigateBack();
+ const getAvailableQty = item => {
+ const quantity =
+ item?.qualitity ??
+ item?.quantity ??
+ item?.unLockedQuantity ??
+ item?.qualifiedUnLockedQuantity ??
+ item?.qualifiedQuantity ??
+ item?.stockQuantity;
+ return quantity ?? 0;
};
- const submitForm = () => {
- // 妫�鏌ユ瘡涓鎵规楠ゆ槸鍚﹂兘鏈夊鎵逛汉
- const hasEmptyStep = approverNodes.value.some(step => !step.nickName);
- if (hasEmptyStep) {
- showToast("璇蜂负姣忎釜瀹℃壒姝ラ閫夋嫨瀹℃壒浜�");
+ const onBatchQtyChange = item => {
+ const val = parseFloat(item.deliveryQuantity);
+ if (isNaN(val) || val <= 0) {
+ item.deliveryQuantity = "";
return;
}
- formRef.value
- .validate()
- .then(valid => {
- if (valid) {
- // 琛ㄥ崟鏍¢獙閫氳繃锛屽彲浠ユ彁浜ゆ暟鎹�
- // 鏀堕泦鎵�鏈夎妭鐐圭殑瀹℃壒浜篿d
- console.log("approverNodes---", approverNodes.value);
- const approveUserIds = approverNodes.value
- .map(node => node.userId)
- .join(",");
- const params = {
- salesLedgerId: goOutData.value.salesLedgerId,
- salesLedgerProductId: goOutData.value.id,
- type: typeValue.value,
- approveUserIds,
- };
- console.log(params, "params");
- addShippingInfo(params).then(res => {
- showToast("鍙戣揣鎴愬姛");
- setTimeout(() => {
- goBack();
- }, 500);
- });
- }
- })
- .catch(error => {
- console.error("琛ㄥ崟鏍¢獙澶辫触:", error);
- // 灏濊瘯鑾峰彇鍏蜂綋鐨勯敊璇瓧娈�
- if (error && error.errors) {
- const firstError = error.errors[0];
- if (firstError) {
- uni.showToast({
- title: firstError.message || "琛ㄥ崟鏍¢獙澶辫触锛岃妫�鏌ュ繀濉」",
- icon: "none",
- });
- return;
+ const available = getAvailableQty(item);
+ if (val > available) {
+ uni.showToast({ title: "涓嶈兘瓒呰繃搴撳瓨鏁伴噺", icon: "none" });
+ item.deliveryQuantity = available.toString();
+ }
+
+ const totalToShip = Number(goOutData.value.noQuantity || 0);
+ const otherBatchesTotal = batchList.value.reduce((sum, b) => {
+ if (b.id === item.id) return sum;
+ return sum + Number(b.deliveryQuantity || 0);
+ }, 0);
+
+ if (val + otherBatchesTotal > totalToShip) {
+ uni.showToast({ title: "鎬绘暟涓嶈兘瓒呰繃寰呭彂璐ф暟閲�", icon: "none" });
+ item.deliveryQuantity = (totalToShip - otherBatchesTotal).toString();
+ }
+ };
+
+ const onTypeSelect = item => {
+ form.type = item.name;
+ showTypePicker.value = false;
+ };
+
+ const afterRead = async event => {
+ const { file } = event;
+ const lists = [].concat(file);
+ const token = getToken();
+
+ for (let i = 0; i < lists.length; i++) {
+ const item = lists[i];
+ const uploadIndex = fileList.value.length;
+ fileList.value.push({
+ ...item,
+ status: "uploading",
+ message: "涓婁紶涓�",
+ });
+
+ uni.uploadFile({
+ url: config.baseUrl + "/common/upload",
+ filePath: item.url,
+ name: "files",
+ header: {
+ Authorization: "Bearer " + token,
+ },
+ success: res => {
+ try {
+ const data = JSON.parse(res.data);
+ if (data.code === 200) {
+ const fileData = Array.isArray(data.data)
+ ? data.data[0]
+ : data.data || data;
+ fileList.value[uploadIndex].status = "success";
+ fileList.value[uploadIndex].message = "";
+ fileList.value[uploadIndex].url = fileData.url;
+ fileList.value[uploadIndex].storageBlobDTO = fileData;
+ } else {
+ fileList.value[uploadIndex].status = "failed";
+ fileList.value[uploadIndex].message = data.msg || "涓婁紶澶辫触";
+ }
+ } catch (e) {
+ fileList.value[uploadIndex].status = "failed";
+ fileList.value[uploadIndex].message = "瑙f瀽澶辫触";
}
- }
- // 鏄剧ず閫氱敤閿欒淇℃伅
- uni.showToast({
- title: "琛ㄥ崟鏍¢獙澶辫触锛岃妫�鏌ュ繀濉」",
- icon: "none",
- });
+ },
+ fail: () => {
+ fileList.value[uploadIndex].status = "failed";
+ fileList.value[uploadIndex].message = "缃戠粶寮傚父";
+ },
});
+ }
};
- // 澶勭悊鑱旂郴浜洪�夋嫨缁撴灉
- const handleSelectContact = data => {
- const { stepIndex, contact } = data;
- // 灏嗛�変腑鐨勮仈绯讳汉璁剧疆涓哄搴斿鎵规楠ょ殑瀹℃壒浜�
- approverNodes.value[stepIndex].userId = contact.userId;
- approverNodes.value[stepIndex].nickName = contact.nickName;
+ const deleteFile = event => {
+ fileList.value.splice(event.index, 1);
};
- const addApprover = stepIndex => {
- // 璺宠浆鍒拌仈绯讳汉閫夋嫨椤甸潰
- uni.setStorageSync("stepIndex", stepIndex);
- uni.navigateTo({
- url: "/pages/cooperativeOffice/collaborativeApproval/contactSelect",
- });
- };
+ const goBack = () => uni.navigateBack();
- const addApprovalStep = () => {
- // 娣诲姞鏂扮殑瀹℃壒姝ラ
- approverNodes.value.push({ userId: null, nickName: null });
- };
+ const submitForm = async () => {
+ const valid = await formRef.value.validate().catch(() => false);
+ if (!valid) return;
- const removeApprover = stepIndex => {
- // 绉婚櫎瀹℃壒浜�
- approverNodes.value[stepIndex].userId = null;
- approverNodes.value[stepIndex].nickName = null;
- };
+ const selectedBatches = batchList.value.filter(
+ b => parseFloat(b.deliveryQuantity) > 0
+ );
+ if (selectedBatches.length === 0) {
+ uni.showToast({ title: "璇疯嚦灏戝~鍐欎竴涓壒娆$殑鍙戣揣鏁伴噺", icon: "none" });
+ return;
+ }
- const removeApprovalStep = stepIndex => {
- // 纭繚鑷冲皯淇濈暀涓�涓鎵规楠�
- if (approverNodes.value.length > 1) {
- approverNodes.value.splice(stepIndex, 1);
- } else {
- uni.showToast({
- title: "鑷冲皯闇�瑕佷竴涓鎵规楠�",
- icon: "none",
- });
+ // Check if any file is still uploading
+ if (fileList.value.some(f => f.status === "uploading")) {
+ uni.showToast({ title: "璇风瓑寰呭浘鐗囦笂浼犲畬鎴�", icon: "none" });
+ return;
+ }
+
+ const payload = {
+ salesLedgerId: goOutData.value.salesLedgerId,
+ salesLedgerProductId: goOutData.value.id,
+ type: form.type,
+ shippingCarNumber: form.type === "璐ц溅" ? form.shippingCarNumber : "",
+ expressCompany: form.type === "蹇��" ? form.expressCompany : "",
+ expressNumber: form.type === "蹇��" ? form.expressNumber : "",
+ storageBlobDTOs: fileList.value
+ .filter(f => f.status === "success")
+ .map(f => f.storageBlobDTO),
+ batchNo: selectedBatches.map(b => b.id),
+ batchNoDetailList: selectedBatches.map(b => ({
+ stockInventoryId: b.id,
+ batchNo: b.batchNo,
+ quantity: parseFloat(b.deliveryQuantity),
+ productModelId: goOutData.value.productModelId,
+ })),
+ };
+
+ try {
+ uni.showLoading({ title: "鎻愪氦涓�..." });
+ const res = await addShippingInfo(payload);
+ uni.hideLoading();
+ uni.showToast({ title: "鍙戣揣鎴愬姛" });
+ setTimeout(() => goBack(), 500);
+ } catch (e) {
+ uni.hideLoading();
+ uni.showToast({ title: "鍙戣揣澶辫触", icon: "none" });
}
};
</script>
<style scoped lang="scss">
@import "@/static/scss/form-common.scss";
-
- .approval-process {
- background: #fff;
- margin: 16px;
- border-radius: 16px;
- padding: 16px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+ .shipment-page {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding-bottom: 100px;
}
- .approval-header {
- margin-bottom: 16px;
+ .form-container {
+ padding: 12px 12px 0;
}
- .approval-title {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- display: block;
- margin-bottom: 4px;
- }
-
- .approval-desc {
- font-size: 12px;
- color: #999;
- }
-
- /* 鏍峰紡澧炲己涓衡�滅畝娲佸皬鍦嗗湀椋庢牸鈥� */
- .approval-steps {
- padding-left: 22px;
- position: relative;
-
- &::before {
- content: "";
- position: absolute;
- left: 11px;
- top: 40px;
- bottom: 40px;
- width: 2px;
- background: linear-gradient(
- to bottom,
- #e6f7ff 0%,
- #bae7ff 50%,
- #91d5ff 100%
- );
- border-radius: 1px;
- }
- }
-
- .approval-step {
- position: relative;
- margin-bottom: 24px;
-
- &::before {
- content: "";
- position: absolute;
- left: -18px;
- top: 14px; // 浠� 8px 璋冩暣涓� 14px锛屼笌鏂囧瓧涓績瀵归綈
- width: 12px;
- height: 12px;
- background: #fff;
- border: 3px solid #006cfb;
- border-radius: 50%;
- z-index: 2;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- }
- }
-
- .step-title {
- top: 12px;
+ .form-section {
margin-bottom: 12px;
- position: relative;
- margin-left: 6px;
- }
-
- .step-title text {
- font-size: 14px;
- color: #666;
- background: #f0f0f0;
- padding: 4px 12px;
border-radius: 12px;
- position: relative;
- line-height: 1.4; // 纭繚鏂囧瓧琛岄珮涓�鑷�
+ overflow: hidden;
+ box-shadow: 0 2px 10px rgba(15, 35, 95, 0.05);
}
- .approver-item {
+ .section-header-info {
+ padding: 10px 18px;
+ background: #f8fbff;
display: flex;
- align-items: center;
- background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
- border-radius: 16px;
- padding: 16px;
+ justify-content: flex-end;
+
+ .subtitle {
+ font-size: 13px;
+ color: #7a8599;
+ }
+ }
+
+ .batch-list {
+ padding: 12px;
+ display: flex;
+ flex-direction: column;
gap: 12px;
- position: relative;
- border: 1px solid #e6f7ff;
- box-shadow: 0 4px 12px rgba(0, 108, 251, 0.08);
- transition: all 0.3s ease;
}
- .approver-avatar {
- width: 48px;
- height: 48px;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- position: relative;
- box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
- }
-
- .avatar-text {
- color: #fff;
- font-size: 18px;
- font-weight: 600;
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
- }
-
- .approver-info {
- flex: 1;
- position: relative;
- }
-
- .approver-name {
- display: block;
- font-size: 16px;
- color: #333;
- font-weight: 500;
- position: relative;
- }
-
- .approver-dept {
- font-size: 12px;
- color: #999;
- background: rgba(0, 108, 251, 0.05);
- padding: 2px 8px;
- border-radius: 8px;
- display: inline-block;
- position: relative;
-
- &::before {
- content: "";
- position: absolute;
- left: 4px;
- top: 50%;
- transform: translateY(-50%);
- width: 2px;
- height: 2px;
- background: #006cfb;
- border-radius: 50%;
- }
- }
-
- .delete-approver-btn {
- font-size: 16px;
- color: #ff4d4f;
- background: linear-gradient(
- 135deg,
- rgba(255, 77, 79, 0.1) 0%,
- rgba(255, 77, 79, 0.05) 100%
- );
- width: 28px;
- height: 28px;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.3s ease;
- position: relative;
- }
-
- .add-approver-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- background: linear-gradient(135deg, #f0f8ff 0%, #e6f7ff 100%);
- border: 2px dashed #006cfb;
- border-radius: 16px;
- padding: 20px;
- color: #006cfb;
- font-size: 14px;
- position: relative;
- transition: all 0.3s ease;
-
- &::before {
- content: "";
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- width: 32px;
- height: 32px;
- border: 2px solid #006cfb;
- border-radius: 50%;
- opacity: 0;
- transition: all 0.3s ease;
- }
- }
-
- .delete-step-btn {
- color: #ff4d4f;
- font-size: 12px;
- background: linear-gradient(
- 135deg,
- rgba(255, 77, 79, 0.1) 0%,
- rgba(255, 77, 79, 0.05) 100%
- );
- padding: 6px 12px;
- border-radius: 12px;
- display: inline-block;
- position: relative;
- transition: all 0.3s ease;
-
- &::before {
- content: "";
- position: absolute;
- left: 6px;
- top: 50%;
- transform: translateY(-50%);
- width: 4px;
- height: 4px;
- background: #ff4d4f;
- border-radius: 50%;
- }
- }
-
- .step-line {
- display: none; // 闅愯棌鍘熸潵鐨勭嚎鏉★紝浣跨敤浼厓绱犱唬鏇�
- }
-
- .add-step-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .footer-btns {
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
+ .batch-card {
background: #fff;
+ border-radius: 12px;
+ padding: 0 12px 12px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+ border: 1px solid #f0f3f7;
+ }
+
+ .batch-header {
+ padding: 12px 0;
display: flex;
- justify-content: space-around;
+ justify-content: space-between;
align-items: center;
- padding: 0.75rem 0;
- box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05);
- z-index: 1000;
- }
- .cancel-btn {
- font-weight: 400;
- font-size: 1rem;
- color: #ffffff;
- width: 6.375rem;
- background: #c7c9cc;
- box-shadow: 0 0.25rem 0.625rem 0 rgba(3, 88, 185, 0.2);
- border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
- }
-
- .save-btn {
- font-weight: 400;
- font-size: 1rem;
- color: #ffffff;
- width: 14rem;
- background: linear-gradient(140deg, #00baff 0%, #006cfb 100%);
- box-shadow: 0 0.25rem 0.625rem 0 rgba(3, 88, 185, 0.2);
- border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
- }
-
- // 鍔ㄧ敾瀹氫箟
- @keyframes pulse {
- 0% {
- transform: scale(1);
- opacity: 1;
+ .batch-no {
+ font-size: 14px;
+ font-weight: 600;
+ color: #22324d;
}
- 50% {
- transform: scale(1.2);
- opacity: 0.7;
- }
- 100% {
- transform: scale(1);
- opacity: 1;
+
+ .batch-qty {
+ font-size: 13px;
+ color: #2979ff;
+ background: #eef6ff;
+ padding: 2px 8px;
+ border-radius: 4px;
}
}
- @keyframes rotate {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
- }
-
- @keyframes ripple {
- 0% {
- transform: translate(-50%, -50%) scale(0.8);
- opacity: 1;
- }
- 100% {
- transform: translate(-50%, -50%) scale(1.6);
- opacity: 0;
- }
- }
-
- /* 濡傛灉宸叉湁 .step-line锛岃繖閲屾洿绮惧噯瀹氫綅鍒板乏渚т笌灏忓渾鐐瑰榻� */
- .step-line {
- position: absolute;
- left: 4px;
- top: 48px;
- width: 2px;
- height: calc(100% - 48px);
- background: #e5e7eb;
- }
-
- .approver-container {
- display: flex;
- align-items: center;
- background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
- border-radius: 16px;
- gap: 12px;
- padding: 10px 0;
- background: transparent;
- border: none;
- box-shadow: none;
- }
-
- .approver-item {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 8px 10px;
- background: transparent;
- border: none;
- box-shadow: none;
- border-radius: 0;
- }
-
- .approver-avatar {
- position: relative;
- width: 40px;
- height: 40px;
- border-radius: 50%;
- background: #f3f4f6;
- border: 2px solid #e5e7eb;
- display: flex;
- align-items: center;
- justify-content: center;
- animation: none; /* 绂佺敤鏃嬭浆绛夊姩鐢伙紝鍥炲綊绠�娲� */
- }
-
- .avatar-text {
- font-size: 14px;
- color: #374151;
- font-weight: 600;
- }
-
- .add-approver-btn {
- display: flex;
- align-items: center;
- gap: 8px;
- background: transparent;
- border: none;
- box-shadow: none;
- padding: 0;
- }
-
- .add-approver-btn .add-circle {
- width: 40px;
- height: 40px;
- border: 2px dashed #a0aec0;
- border-radius: 50%;
- color: #6b7280;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 22px;
- line-height: 1;
- }
-
- .add-approver-btn .add-label {
- color: #3b82f6;
+ .empty-text {
+ padding: 30px 12px;
+ text-align: center;
+ color: #999;
font-size: 14px;
}
-</style>
\ No newline at end of file
+
+ .upload-container {
+ padding: 12px 18px;
+ }
+
+ :deep(.u-cell-group__title) {
+ padding: 14px 18px 10px !important;
+ font-size: 15px !important;
+ font-weight: 600 !important;
+ color: #22324d !important;
+ background: #f8fbff !important;
+ }
+
+ :deep(.u-form-item) {
+ padding: 0 18px !important;
+ }
+</style>
--
Gitblit v1.9.3