add occurredAt

This commit is contained in:
Timi
2026-09-09 13:14:20 +08:00
parent b09b430334
commit eb07b068aa
2 changed files with 71 additions and 0 deletions
@@ -21,6 +21,25 @@
<t-form-item label="数量" required-mark> <t-form-item label="数量" required-mark>
<t-input v-model="quantity" type="number" align="right" borderless /> <t-input v-model="quantity" type="number" align="right" borderless />
</t-form-item> </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="备注" required-mark> <t-form-item label="备注" required-mark>
<div class="remark-wrap"> <div class="remark-wrap">
<t-textarea <t-textarea
@@ -53,6 +72,18 @@
</t-form> </t-form>
</div> </div>
</bottom-popup> </bottom-popup>
<t-popup v-model="occurredAtPickerVisible" placement="bottom">
<t-date-time-picker
v-if="occurredAtPickerVisible"
v-model="occurredAtDraftText"
:start="minimumDateTimeText"
:mode="['date', 'minute']"
format="YYYY-MM-DD HH:mm"
title="库存发生时间"
@cancel="occurredAtPickerVisible = false"
@confirm="confirmOccurredAt"
/>
</t-popup>
<t-popup <t-popup
v-model="unitPickerVisible" v-model="unitPickerVisible"
placement="bottom" placement="bottom"
@@ -66,6 +97,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { watch } from "vue"; import { watch } from "vue";
import { BottomPopup } from "timi-tdesign-mobile"; import { BottomPopup } from "timi-tdesign-mobile";
import { Time } from "timi-web";
import ProductAPI from "@/api/ProductAPI"; import ProductAPI from "@/api/ProductAPI";
import PhotoScroller from "@/components/PhotoScroller.vue"; import PhotoScroller from "@/components/PhotoScroller.vue";
import type { import type {
@@ -100,6 +132,9 @@ const isSaving = ref(false);
const quantity = ref(""); const quantity = ref("");
const remark = ref(""); const remark = ref("");
const requestNo = ref(""); const requestNo = ref("");
const occurredAtText = ref("");
const occurredAtDraftText = ref("");
const occurredAtPickerVisible = ref(false);
const photoItems = ref<PhotoItem[]>([]); const photoItems = ref<PhotoItem[]>([]);
const photoUrlList = computed(() => photoItems.value.map(item => item.url)); const photoUrlList = computed(() => photoItems.value.map(item => item.url));
const selectedUnitId = ref(""); const selectedUnitId = ref("");
@@ -107,6 +142,7 @@ const unitPickerVisible = ref(false);
const unitDraft = ref<PickerValue[]>([]); const unitDraft = ref<PickerValue[]>([]);
const unitPickerZIndex = 12001; const unitPickerZIndex = 12001;
const unitPickerOverlayZIndex = unitPickerZIndex - 1; const unitPickerOverlayZIndex = unitPickerZIndex - 1;
const minimumDateTimeText = "1970-01-01 00:00";
const isInbound = computed(() => props.operation === "MANUAL_IN" || props.operation === "STOCKTAKE_GAIN"); const isInbound = computed(() => props.operation === "MANUAL_IN" || props.operation === "STOCKTAKE_GAIN");
const selectableUnits = computed(() => (props.sku.unitList || []).filter(unit => isInbound.value ? unit.allowPurchase : unit.allowSale)); const selectableUnits = computed(() => (props.sku.unitList || []).filter(unit => isInbound.value ? unit.allowPurchase : unit.allowSale));
@@ -118,10 +154,28 @@ function resetForm(): void {
quantity.value = ""; quantity.value = "";
remark.value = ""; remark.value = "";
requestNo.value = ""; requestNo.value = "";
occurredAtText.value = "";
occurredAtDraftText.value = "";
occurredAtPickerVisible.value = false;
photoItems.value = []; photoItems.value = [];
selectedUnitId.value = selectableUnits.value[0]?.id || ""; selectedUnitId.value = selectableUnits.value[0]?.id || "";
} }
function openOccurredAtPicker(): void {
occurredAtDraftText.value = occurredAtText.value || Time.formatDateTime(new Date());
occurredAtPickerVisible.value = true;
}
function confirmOccurredAt(value?: string | number): void {
occurredAtText.value = String(value || occurredAtDraftText.value);
occurredAtPickerVisible.value = false;
}
function resetOccurredAt(): void {
occurredAtText.value = "";
occurredAtDraftText.value = "";
}
function openUnitPicker(): void { function openUnitPicker(): void {
if (selectableUnits.value.length) { if (selectableUnits.value.length) {
unitDraft.value = [selectedUnitId.value]; unitDraft.value = [selectedUnitId.value];
@@ -170,11 +224,20 @@ function buildRequest(): ProductStockChangeRequest {
skuId: props.sku.id || "", skuId: props.sku.id || "",
skuUnitId: selectedUnitId.value, skuUnitId: selectedUnitId.value,
quantity: quantity.value, quantity: quantity.value,
occurredAt: resolveTimestamp(occurredAtText.value),
remark: remark.value.trim(), remark: remark.value.trim(),
attachmentList: photoItems.value.flatMap(item => item.tempFileId ? [{ tempFileId: item.tempFileId, attachType: item.attachType || "PHOTO" }] : []) attachmentList: photoItems.value.flatMap(item => item.tempFileId ? [{ tempFileId: item.tempFileId, attachType: item.attachType || "PHOTO" }] : [])
}; };
} }
function resolveTimestamp(value: string): number | undefined {
if (!value) {
return undefined;
}
const timestamp = new Date(value.replace(" ", "T")).getTime();
return Number.isFinite(timestamp) ? timestamp : undefined;
}
async function submit(): Promise<void> { async function submit(): Promise<void> {
if (isSaving.value || !validate()) { if (isSaving.value || !validate()) {
return; return;
@@ -227,5 +290,12 @@ watch(() => [visible.value, props.operation] as const, ([isVisible]) => {
align-items: start; align-items: start;
justify-content: space-between; justify-content: space-between;
} }
.time-actions {
gap: .5rem;
display: flex;
align-items: center;
justify-content: flex-end;
}
} }
</style> </style>
+1
View File
@@ -195,6 +195,7 @@ export type ProductStockChangeRequest = {
skuId: string; skuId: string;
skuUnitId: string; skuUnitId: string;
quantity: number | string; quantity: number | string;
occurredAt?: number;
remark: string; remark: string;
attachmentList: Partial<Attachment>[]; attachmentList: Partial<Attachment>[];
}; };