fix SalesOrderPayment.vue style
This commit is contained in:
@@ -143,7 +143,7 @@
|
||||
<t-textarea v-model.trim="remark" class="textarea" borderless autosize maxlength="500" placeholder="记录本单需要注意的内容" />
|
||||
</t-form-item>
|
||||
<div class="photo-part">
|
||||
<package-photo-field v-model="photoItems" title="订单照片(选填)" />
|
||||
<photo-scroller :model-value="photoUrlList" v-model:photo-items="photoItems" :upload="uploadPhotoList" :edit-mode="true" title="订单照片(选填)" />
|
||||
</div>
|
||||
</t-form>
|
||||
<div class="submit-wrap glass-white bg-white">
|
||||
@@ -178,7 +178,7 @@ import SalesOrderAPI from "@/api/SalesOrderAPI";
|
||||
import CodeScanner from "@/components/CodeScanner.vue";
|
||||
import CustomerProfileCard from "@/components/CustomerProfileCard.vue";
|
||||
import CustomerSelector from "@/components/CustomerSelector.vue";
|
||||
import PackagePhotoField from "@/components/PackagePhotoField.vue";
|
||||
import PhotoScroller from "@/components/PhotoScroller.vue";
|
||||
import type { Customer } from "@/types/Customer";
|
||||
import type { Product, ProductUnit } from "@/types/Product";
|
||||
import type { PhotoItem } from "@/types/Photo";
|
||||
@@ -188,6 +188,7 @@ import { formatProductAmount } from "@/utils/product";
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import { Message } from "@/utils/message";
|
||||
import { permissionCodes } from "@/utils/permission";
|
||||
import { uploadPhotoList } from "@/utils/photo";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import { useSettingStore } from "@/store/settingStore";
|
||||
|
||||
@@ -208,6 +209,7 @@ const draftTime = ref("");
|
||||
const pickerVisible = ref(false);
|
||||
const isSaving = ref(false);
|
||||
const photoItems = ref<PhotoItem[]>([]);
|
||||
const photoUrlList = computed(() => photoItems.value.map(item => item.url));
|
||||
const maxQuantity = Number.MAX_SAFE_INTEGER;
|
||||
const productCache = new Map<string, Product>();
|
||||
const requestNo = ref("");
|
||||
|
||||
@@ -2,29 +2,78 @@
|
||||
<div v-can="permissionCodes.fundReceive.create" class="sales-order-operation">
|
||||
<t-cell-group v-if="order" title="销售订单" theme="card"><t-cell title="订单号" :note="order.orderNo || order.id" /><t-cell title="剩余待收款" :note="formatPackageAmount(order.unpaidAmount)" /></t-cell-group>
|
||||
<t-form v-if="order" class="form" label-align="left" label-width="6rem">
|
||||
<t-form-item label="收款金额(元)" required-mark><t-input v-model.trim="amountText" type="number" align="right" borderless placeholder="请输入本次收款金额" /></t-form-item>
|
||||
<t-form-item label="收款时间" arrow @click="pickerVisible = true"><span class="picker-text" v-text="occurredAtText || '使用当前时间'" /></t-form-item>
|
||||
<t-form-item label="收款金额" required-mark>
|
||||
<t-input
|
||||
v-model.trim="amountText"
|
||||
type="number"
|
||||
align="right"
|
||||
borderless
|
||||
placeholder="请输入本次收款金额"
|
||||
/>
|
||||
<template #help>
|
||||
<div class="help">
|
||||
<t-button
|
||||
size="extra-small"
|
||||
theme="primary"
|
||||
variant="outline"
|
||||
@click="fillUnpaidAmount"
|
||||
>全额收款</t-button>
|
||||
</div>
|
||||
</template>
|
||||
</t-form-item>
|
||||
<t-form-item label="收款时间" content-align="right">
|
||||
<div class="time-actions">
|
||||
<t-button
|
||||
theme="primary"
|
||||
variant="outline"
|
||||
size="extra-small"
|
||||
:content="occurredAtText || '此刻'"
|
||||
@click="openOccurredAtPicker"
|
||||
/>
|
||||
<t-button
|
||||
v-if="occurredAtText"
|
||||
theme="primary"
|
||||
variant="text"
|
||||
size="extra-small"
|
||||
content="此刻"
|
||||
@click="resetOccurredAt"
|
||||
/>
|
||||
</div>
|
||||
</t-form-item>
|
||||
<t-form-item label="备注"><t-textarea v-model.trim="remark" borderless autosize maxlength="500" /></t-form-item>
|
||||
<t-form-item label-width="0">
|
||||
<photo-scroller
|
||||
v-if="order"
|
||||
:model-value="photoUrlList"
|
||||
v-model:photo-items="photoItems"
|
||||
class="photo-field"
|
||||
:upload="uploadPhotoList"
|
||||
:edit-mode="true"
|
||||
required
|
||||
title="收款凭证照片"
|
||||
/>
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
<package-photo-field v-if="order" v-model="photoItems" required title="收款凭证照片" />
|
||||
<t-empty v-if="!order" :description="loading ? '正在加载订单' : '订单不存在'" />
|
||||
<t-popup v-model="pickerVisible" placement="bottom">
|
||||
<t-date-time-picker v-model="draftTime" format="YYYY-MM-DD HH:mm" :mode="['date', 'minute']" title="收款时间" @cancel="pickerVisible = false" @confirm="confirmTime" />
|
||||
<t-date-time-picker v-if="pickerVisible" v-model="draftTime" format="YYYY-MM-DD HH:mm" :mode="['date', 'minute']" title="收款时间" @cancel="pickerVisible = false" @confirm="confirmOccurredAt" />
|
||||
</t-popup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStore, type Attachment } from "timi-web-api";
|
||||
import PackagePhotoField from "@/components/PackagePhotoField.vue";
|
||||
import { Time } from "timi-web";
|
||||
import PhotoScroller from "@/components/PhotoScroller.vue";
|
||||
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { SalesOrder } from "@/types/SalesOrder";
|
||||
import type { PhotoItem } from "@/types/Photo";
|
||||
import { createPackageRequestNo, formatPackageAmount, parsePackageAmount } from "@/utils/package";
|
||||
import { createPackageRequestNo, formatPackageAmount, formatPackageAmountInput, parsePackageAmount } from "@/utils/package";
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import { Message } from "@/utils/message";
|
||||
import { permissionCodes } from "@/utils/permission";
|
||||
import { uploadPhotoList } from "@/utils/photo";
|
||||
|
||||
defineOptions({ name: "SalesOrderPayment" });
|
||||
const route = useRoute();
|
||||
@@ -40,25 +89,68 @@ const draftTime = ref("");
|
||||
const pickerVisible = ref(false);
|
||||
const remark = ref("");
|
||||
const photoItems = ref<PhotoItem[]>([]);
|
||||
const photoUrlList = computed(() => photoItems.value.map(item => item.url));
|
||||
const requestNo = ref("");
|
||||
function confirmTime(value: string | number): void { occurredAtText.value = String(value); pickerVisible.value = false; }
|
||||
function resolveTimestamp(value: string): number | undefined { if (!value) return undefined; const timestamp = new Date(value.replace(" ", "T")).getTime(); return Number.isFinite(timestamp) ? timestamp : undefined; }
|
||||
function buildAttachments(): Partial<Attachment>[] { return photoItems.value.flatMap(item => item.tempFileId ? [{ tempFileId: item.tempFileId, attachType: "PHOTO" }] : []); }
|
||||
|
||||
function openOccurredAtPicker(): void {
|
||||
draftTime.value = occurredAtText.value || Time.formatDateTime(new Date());
|
||||
pickerVisible.value = true;
|
||||
}
|
||||
|
||||
function confirmOccurredAt(value?: string | number): void {
|
||||
occurredAtText.value = String(value || draftTime.value);
|
||||
pickerVisible.value = false;
|
||||
}
|
||||
|
||||
function resetOccurredAt(): void {
|
||||
occurredAtText.value = "";
|
||||
draftTime.value = "";
|
||||
}
|
||||
|
||||
function fillUnpaidAmount(): void {
|
||||
amountText.value = formatPackageAmountInput(order.value?.unpaidAmount);
|
||||
}
|
||||
|
||||
function resolveTimestamp(value: string): number | undefined {
|
||||
if (!value) return undefined;
|
||||
const timestamp = new Date(value.replace(" ", "T")).getTime();
|
||||
return Number.isFinite(timestamp) ? timestamp : undefined;
|
||||
}
|
||||
|
||||
function buildAttachments(): Partial<Attachment>[] {
|
||||
return photoItems.value.flatMap(item => item.tempFileId ? [{
|
||||
tempFileId: item.tempFileId,
|
||||
attachType: "PHOTO"
|
||||
}] : []);
|
||||
}
|
||||
|
||||
async function loadData(): Promise<void> {
|
||||
const id = String(route.params.id || "");
|
||||
if (!id) return;
|
||||
loading.value = true;
|
||||
try { order.value = await SalesOrderAPI.detail(id); }
|
||||
catch (error) { Message.error(getErrorMessage(error, "订单加载失败")); }
|
||||
finally { loading.value = false; }
|
||||
try {
|
||||
order.value = await SalesOrderAPI.detail(id);
|
||||
} catch (error) {
|
||||
Message.error(getErrorMessage(error, "订单加载失败"));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function save(): Promise<void> {
|
||||
if (saving.value || !order.value?.id) return;
|
||||
const amount = parsePackageAmount(amountText.value);
|
||||
const attachmentList = buildAttachments();
|
||||
if (amount === undefined || amount === 0) { Message.warning("请输入合法的正金额"); return; }
|
||||
if (!attachmentList.length) { Message.warning("收款必须上传至少一张照片"); return; }
|
||||
if (!requestNo.value) requestNo.value = createPackageRequestNo(); saving.value = true;
|
||||
if (amount === undefined || amount === 0) {
|
||||
Message.warning("请输入合法的正金额");
|
||||
return;
|
||||
}
|
||||
if (!attachmentList.length) {
|
||||
Message.warning("收款必须上传至少一张照片");
|
||||
return;
|
||||
}
|
||||
if (!requestNo.value) requestNo.value = createPackageRequestNo();
|
||||
saving.value = true;
|
||||
try {
|
||||
await SalesOrderAPI.receivePayment({
|
||||
salesOrderId: order.value.id,
|
||||
@@ -70,17 +162,52 @@ async function save(): Promise<void> {
|
||||
});
|
||||
Message.success("收款登记已提交");
|
||||
await router.replace(`/management/sales-orders/${order.value.id}`);
|
||||
} catch (error) { Message.error(getErrorMessage(error, "收款登记失败,重试会复用同一请求号")); }
|
||||
finally { saving.value = false; }
|
||||
} catch (error) {
|
||||
Message.error(getErrorMessage(error, "收款登记失败,重试会复用同一请求号"));
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
onMounted(async () => { if (!userStore.hasPermissions(permissionCodes.fundReceive.create)) return; navBarStore.setRightText("提交收款", "var(--td-brand-color)", save); await loadData(); });
|
||||
|
||||
onMounted(async () => {
|
||||
if (!userStore.hasPermissions(permissionCodes.fundReceive.create)) return;
|
||||
navBarStore.setRightText("提交", "var(--td-brand-color)", save);
|
||||
await loadData();
|
||||
});
|
||||
onUnmounted(() => navBarStore.clearRight());
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.sales-order-operation { gap: 1rem; padding: calc(var(--app-nav-height) + 1rem) 0 2rem; display: flex; flex-direction: column;
|
||||
.form { margin: 0 1rem; padding: 0 .5rem; background: var(--td-bg-color-container); box-shadow: var(--td-shadow-1); border-radius: 1rem; overflow: hidden; }
|
||||
.picker-text { width: 100%; text-align: right; }
|
||||
.package-photo-field { padding: 0 1rem; }
|
||||
.sales-order-operation {
|
||||
gap: 1rem;
|
||||
padding: calc(var(--app-nav-height) + 1rem) 0 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.form {
|
||||
|
||||
.help {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
margin-top: .5rem;
|
||||
justify-content: end;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.time-actions {
|
||||
gap: .5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.photo-field {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,16 @@
|
||||
<t-form-item label="退款时间" arrow @click="pickerVisible = true"><span class="picker-text" v-text="occurredAtText || '使用当前时间'" /></t-form-item>
|
||||
<t-form-item label="备注"><t-textarea v-model.trim="remark" borderless autosize maxlength="500" /></t-form-item>
|
||||
</t-form>
|
||||
<package-photo-field v-if="order" v-model="photoItems" required title="退款凭证照片" />
|
||||
<photo-scroller
|
||||
v-if="order"
|
||||
:model-value="photoUrlList"
|
||||
v-model:photo-items="photoItems"
|
||||
class="photo-field"
|
||||
:upload="uploadPhotoList"
|
||||
:edit-mode="true"
|
||||
required
|
||||
title="退款凭证照片"
|
||||
/>
|
||||
<t-empty v-if="!order" :description="loading ? '正在加载订单' : '订单不存在'" />
|
||||
<t-popup v-model="pickerVisible" placement="bottom">
|
||||
<t-date-time-picker v-model="draftTime" format="YYYY-MM-DD HH:mm" :mode="['date', 'minute']" title="退款时间" @cancel="pickerVisible = false" @confirm="confirmTime" />
|
||||
@@ -20,7 +29,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStore, type Attachment } from "timi-web-api";
|
||||
import PackagePhotoField from "@/components/PackagePhotoField.vue";
|
||||
import PhotoScroller from "@/components/PhotoScroller.vue";
|
||||
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { SalesOrder } from "@/types/SalesOrder";
|
||||
@@ -29,6 +38,7 @@ import { createPackageRequestNo, formatPackageAmount, parsePackageAmount } from
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import { Message } from "@/utils/message";
|
||||
import { permissionCodes } from "@/utils/permission";
|
||||
import { uploadPhotoList } from "@/utils/photo";
|
||||
|
||||
defineOptions({ name: "SalesOrderRefund" });
|
||||
const route = useRoute();
|
||||
@@ -45,6 +55,7 @@ const draftTime = ref("");
|
||||
const pickerVisible = ref(false);
|
||||
const remark = ref("");
|
||||
const photoItems = ref<PhotoItem[]>([]);
|
||||
const photoUrlList = computed(() => photoItems.value.map(item => item.url));
|
||||
const requestNo = ref("");
|
||||
function confirmTime(value: string | number): void { occurredAtText.value = String(value); pickerVisible.value = false; }
|
||||
function resolveTimestamp(value: string): number | undefined { if (!value) return undefined; const timestamp = new Date(value.replace(" ", "T")).getTime(); return Number.isFinite(timestamp) ? timestamp : undefined; }
|
||||
@@ -86,6 +97,6 @@ onUnmounted(() => navBarStore.clearRight());
|
||||
.sales-order-operation { gap: 1rem; padding: calc(var(--app-nav-height) + 1rem) 0 2rem; display: flex; flex-direction: column;
|
||||
.form { margin: 0 1rem; padding: 0 .5rem; background: var(--td-bg-color-container); box-shadow: var(--td-shadow-1); border-radius: 1rem; overflow: hidden; }
|
||||
.picker-text { width: 100%; text-align: right; }
|
||||
.package-photo-field { padding: 0 1rem; }
|
||||
.photo-field { padding: 0 1rem; }
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user