- Rial wage and gram-debt arithmetic matched to the reference; order corrections keep debt in sync - Document confirm/un-confirm is a compare-and-swap (no double-applied cache under concurrency) - Settlement document and expert inputs validated (400 instead of 500) - Expert: edit / activate-deactivate own customers, adjust raw weights only - Made-to-order flow in the app, PreOrder.quantity migration - Order grids: customer column, sort keys; panel select search; pre-order quantity save - Rebuilt release artifacts Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
198 lines
5.7 KiB
Vue
198 lines
5.7 KiB
Vue
<!--
|
|
"سفارش ساخت" — ask for a piece to be made.
|
|
|
|
Ported from henza_pwa/src/views/user/src/components/makeOrder.vue (route
|
|
/makeOrder, name makeOrderList), restyled into this app's design language.
|
|
|
|
Kept from the reference:
|
|
- the header title "سفارش ساخت"
|
|
- the photo of the piece first, then the questions: رنگ محصول، سایز محصول،
|
|
رنگ مینا، رنگ سنگ، تعداد، توضیحات (the last one optional)
|
|
- every field but the description required, with the reference's own messages
|
|
- POST create-custom-order -> customer/me/pre-orders here; the customer is the
|
|
token's, nothing about WHO is sent
|
|
The reference then sent the customer home; this goes to «وضعیت سفارش» so the
|
|
request just placed is the first thing seen.
|
|
-->
|
|
<template>
|
|
<div class="mko">
|
|
<PageBar title="سفارش ساخت" back-to="userPage::hasSubRoute" />
|
|
|
|
<Spinner :spinning="submitting" tip="در حال ثبت اطلاعات">
|
|
<container class="mko__body">
|
|
<form class="mko__form" novalidate @submit.prevent="submit">
|
|
<SingleImageUploader
|
|
upload-text="بارگذاری عکس سفارش"
|
|
purpose="preorder-design"
|
|
@done="(id: string) => (form.file_id = id)"
|
|
/>
|
|
|
|
<p class="mko__lead">لطفا به سوالات زیر پاسخ دهید</p>
|
|
|
|
<label class="mko__field">
|
|
<span>رنگ محصول</span>
|
|
<input v-model.trim="form.color" type="text" maxlength="100" />
|
|
</label>
|
|
<label class="mko__field">
|
|
<span>سایز محصول</span>
|
|
<input v-model.trim="form.size" type="text" maxlength="100" />
|
|
</label>
|
|
<label class="mko__field">
|
|
<span>رنگ مینا</span>
|
|
<input v-model.trim="form.color_mina" type="text" maxlength="100" />
|
|
</label>
|
|
<label class="mko__field">
|
|
<span>رنگ سنگ</span>
|
|
<input v-model.trim="form.color_stone" type="text" maxlength="100" />
|
|
</label>
|
|
<label class="mko__field">
|
|
<span>تعداد</span>
|
|
<input v-model.number="form.sum" type="number" inputmode="numeric" min="1" step="1" />
|
|
</label>
|
|
<label class="mko__field">
|
|
<span>توضیحات</span>
|
|
<textarea v-model.trim="form.description" rows="3" maxlength="1000" />
|
|
</label>
|
|
|
|
<p v-if="error" class="mko__error">{{ error }}</p>
|
|
|
|
<button type="submit" class="mko__submit" :disabled="submitting">ارسال اطلاعات</button>
|
|
</form>
|
|
</container>
|
|
</Spinner>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { reactive, ref, watch } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { toast } from '../../composables/useToast'
|
|
import PageBar from '../../components/ui/PageBar.vue'
|
|
import Spinner from '../../components/Spinner.vue'
|
|
import SingleImageUploader from '../../components/upload/SingleImageUploader.vue'
|
|
import { api } from '../../api/client'
|
|
|
|
const router = useRouter()
|
|
|
|
const form = reactive({
|
|
file_id: null as string | null,
|
|
color: '',
|
|
size: '',
|
|
color_mina: '',
|
|
color_stone: '',
|
|
sum: 1,
|
|
description: '',
|
|
})
|
|
|
|
const submitting = ref(false)
|
|
const error = ref<string | null>(null)
|
|
/** A message about a missing field must not outlive the fix (e.g. the photo being uploaded). */
|
|
watch(form, () => (error.value = null))
|
|
|
|
/** The reference's required-field messages, in the order it asked. */
|
|
function firstMissing(): string | null {
|
|
if (!form.file_id) return 'لطفا تصویر سفارش را آپلود کنید'
|
|
if (!form.color) return 'لطفا رنگ محصول را وارد کنید'
|
|
if (!form.size) return 'لطفا سایز محصول را وارد کنید'
|
|
if (!form.color_mina) return 'لطفا رنگ مینا را وارد کنید'
|
|
if (!form.color_stone) return 'لطفا رنگ سنگ را وارد کنید'
|
|
if (!Number.isInteger(form.sum) || form.sum < 1) return 'لطفا تعداد را وارد کنید'
|
|
return null
|
|
}
|
|
|
|
async function submit() {
|
|
error.value = firstMissing()
|
|
if (error.value) return
|
|
|
|
submitting.value = true
|
|
try {
|
|
await api.createPreOrder({
|
|
color: form.color,
|
|
size: form.size,
|
|
color_mina: form.color_mina,
|
|
color_stone: form.color_stone,
|
|
sum: form.sum,
|
|
file_id: form.file_id,
|
|
description: form.description || undefined,
|
|
})
|
|
toast.success('سفارش با موفقیت ثبت شد')
|
|
router.replace({ name: 'makeOrderStatus' })
|
|
} catch {
|
|
error.value = 'خطا در ثبت سفارش'
|
|
} finally {
|
|
submitting.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.mko__body {
|
|
padding-top: 84px;
|
|
padding-bottom: 110px;
|
|
}
|
|
|
|
.mko__form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.mko__lead {
|
|
margin: 18px 2px 4px;
|
|
font-size: 13px;
|
|
font-weight: 700;
|
|
color: @inkMuted;
|
|
}
|
|
|
|
.mko__field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
padding: 12px 0;
|
|
border-bottom: 1px solid @hairline;
|
|
font-size: 12.5px;
|
|
color: @inkSoft;
|
|
}
|
|
|
|
.mko__field input,
|
|
.mko__field textarea {
|
|
width: 100%;
|
|
padding: 11px 12px;
|
|
border: 1px solid @hairline;
|
|
border-radius: 12px;
|
|
background: transparent;
|
|
color: @ink;
|
|
font-family: inherit;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.mko__error {
|
|
margin: 12px 2px 0;
|
|
font-size: 12.5px;
|
|
color: @red;
|
|
}
|
|
|
|
.mko__submit {
|
|
position: fixed;
|
|
left: 16px;
|
|
right: 16px;
|
|
bottom: 20px;
|
|
z-index: 20;
|
|
max-width: 736px;
|
|
margin: 0 auto;
|
|
padding: 15px;
|
|
border: none;
|
|
border-radius: 999px;
|
|
background: @wine;
|
|
color: #fff;
|
|
font-family: inherit;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.mko__submit:disabled {
|
|
opacity: 0.6;
|
|
cursor: progress;
|
|
}
|
|
</style>
|