forked from morrning/hesabixCore
288 lines
7.7 KiB
Vue
288 lines
7.7 KiB
Vue
|
|
<template>
|
|||
|
|
<v-dialog v-model="dialog" max-width="600px" persistent>
|
|||
|
|
<v-card>
|
|||
|
|
<v-card-title class="d-flex align-center p-3 gap-2">
|
|||
|
|
<v-icon class="mr-3" color="primary">mdi-shield-check</v-icon>
|
|||
|
|
<span>{{ isEdit ? 'ویرایش سریال گارانتی' : 'افزودن سریال گارانتی جدید' }}</span>
|
|||
|
|
</v-card-title>
|
|||
|
|
|
|||
|
|
<v-card-text>
|
|||
|
|
<v-form ref="form" v-model="valid">
|
|||
|
|
<v-row>
|
|||
|
|
<v-col cols="12" md="6">
|
|||
|
|
<v-text-field
|
|||
|
|
v-model="formData.serialNumber"
|
|||
|
|
label="شماره سریال *"
|
|||
|
|
:rules="[rules.serialNumber]"
|
|||
|
|
required
|
|||
|
|
:disabled="isEdit"
|
|||
|
|
variant="outlined"
|
|||
|
|
density="comfortable"
|
|||
|
|
hide-details="auto"
|
|||
|
|
maxlength="50"
|
|||
|
|
counter
|
|||
|
|
></v-text-field>
|
|||
|
|
</v-col>
|
|||
|
|
<v-col cols="12" md="6">
|
|||
|
|
<v-autocomplete
|
|||
|
|
v-model="formData.commodity_id"
|
|||
|
|
label="محصول *"
|
|||
|
|
:items="commodities"
|
|||
|
|
item-title="name"
|
|||
|
|
item-value="id"
|
|||
|
|
:rules="[rules.commodity]"
|
|||
|
|
required
|
|||
|
|
:filter="customFilter"
|
|||
|
|
clearable
|
|||
|
|
return-object
|
|||
|
|
@update:model-value="handleCommoditySelect"
|
|||
|
|
variant="outlined"
|
|||
|
|
density="comfortable"
|
|||
|
|
hide-details="auto"
|
|||
|
|
></v-autocomplete>
|
|||
|
|
</v-col>
|
|||
|
|
<v-col cols="12" md="6">
|
|||
|
|
<h-date-picker
|
|||
|
|
v-model="formData.warrantyStartDate"
|
|||
|
|
label="تاریخ شروع گارانتی"
|
|||
|
|
:rules="[rules.date]"
|
|||
|
|
/>
|
|||
|
|
</v-col>
|
|||
|
|
<v-col cols="12" md="6">
|
|||
|
|
<h-date-picker
|
|||
|
|
v-model="formData.warrantyEndDate"
|
|||
|
|
label="تاریخ پایان گارانتی"
|
|||
|
|
:rules="[rules.date, (value: any) => rules.endDate(value, formData.warrantyStartDate)]"
|
|||
|
|
/>
|
|||
|
|
</v-col>
|
|||
|
|
<v-col cols="12" md="6">
|
|||
|
|
<v-select
|
|||
|
|
v-model="formData.status"
|
|||
|
|
label="وضعیت"
|
|||
|
|
:items="statusOptions"
|
|||
|
|
item-title="title"
|
|||
|
|
item-value="value"
|
|||
|
|
variant="outlined"
|
|||
|
|
density="comfortable"
|
|||
|
|
hide-details="auto"
|
|||
|
|
></v-select>
|
|||
|
|
</v-col>
|
|||
|
|
<v-col cols="12">
|
|||
|
|
<v-textarea
|
|||
|
|
v-model="formData.description"
|
|||
|
|
label="توضیحات"
|
|||
|
|
rows="3"
|
|||
|
|
auto-grow
|
|||
|
|
variant="outlined"
|
|||
|
|
density="comfortable"
|
|||
|
|
hide-details="auto"
|
|||
|
|
></v-textarea>
|
|||
|
|
</v-col>
|
|||
|
|
<!-- <v-col cols="12">
|
|||
|
|
<v-textarea
|
|||
|
|
v-model="formData.notes"
|
|||
|
|
label="یادداشتها"
|
|||
|
|
rows="2"
|
|||
|
|
auto-grow
|
|||
|
|
></v-textarea>
|
|||
|
|
</v-col> -->
|
|||
|
|
</v-row>
|
|||
|
|
</v-form>
|
|||
|
|
</v-card-text>
|
|||
|
|
|
|||
|
|
<v-card-actions>
|
|||
|
|
<v-spacer></v-spacer>
|
|||
|
|
<v-btn color="grey" @click="close">انصراف</v-btn>
|
|||
|
|
<v-btn
|
|||
|
|
color="primary"
|
|||
|
|
@click="save"
|
|||
|
|
:loading="loading"
|
|||
|
|
:disabled="!valid"
|
|||
|
|
>
|
|||
|
|
{{ isEdit ? 'ویرایش' : 'ذخیره' }}
|
|||
|
|
</v-btn>
|
|||
|
|
</v-card-actions>
|
|||
|
|
</v-card>
|
|||
|
|
</v-dialog>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup lang="ts">
|
|||
|
|
import { ref, computed, watch, nextTick } from 'vue'
|
|||
|
|
|
|||
|
|
const props = defineProps<{
|
|||
|
|
modelValue: boolean
|
|||
|
|
serial?: any
|
|||
|
|
commodities: any[]
|
|||
|
|
}>()
|
|||
|
|
|
|||
|
|
const emit = defineEmits<{
|
|||
|
|
'update:modelValue': [value: boolean]
|
|||
|
|
save: [data: any]
|
|||
|
|
close: []
|
|||
|
|
}>()
|
|||
|
|
|
|||
|
|
const loading = ref(false)
|
|||
|
|
const valid = ref(false)
|
|||
|
|
const form = ref()
|
|||
|
|
|
|||
|
|
const formData = ref({
|
|||
|
|
serialNumber: '',
|
|||
|
|
commodity_id: '',
|
|||
|
|
description: '',
|
|||
|
|
warrantyStartDate: '',
|
|||
|
|
warrantyEndDate: '',
|
|||
|
|
status: 'active',
|
|||
|
|
notes: ''
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const rules = {
|
|||
|
|
required: (value: any) => !!value || 'این فیلد الزامی است',
|
|||
|
|
serialNumber: (value: any) => {
|
|||
|
|
if (!value) return 'شماره سریال الزامی است'
|
|||
|
|
if (!/^[A-Za-z0-9]+$/.test(value)) {
|
|||
|
|
return 'شماره سریال فقط میتواند شامل حروف انگلیسی و اعداد باشد'
|
|||
|
|
}
|
|||
|
|
if (value.length < 3) {
|
|||
|
|
return 'شماره سریال باید حداقل ۳ کاراکتر باشد'
|
|||
|
|
}
|
|||
|
|
if (value.length > 50) {
|
|||
|
|
return 'شماره سریال نمیتواند بیشتر از ۵۰ کاراکتر باشد'
|
|||
|
|
}
|
|||
|
|
return true
|
|||
|
|
},
|
|||
|
|
commodity: (value: any) => {
|
|||
|
|
if (!value) return 'انتخاب محصول الزامی است'
|
|||
|
|
return true
|
|||
|
|
},
|
|||
|
|
date: (value: any) => {
|
|||
|
|
if (!value) return true
|
|||
|
|
const date = new Date(value)
|
|||
|
|
if (isNaN(date.getTime())) {
|
|||
|
|
return 'تاریخ نامعتبر است'
|
|||
|
|
}
|
|||
|
|
return true
|
|||
|
|
},
|
|||
|
|
endDate: (value: any, startDate: any) => {
|
|||
|
|
if (!value || !startDate) return true
|
|||
|
|
const end = new Date(value)
|
|||
|
|
const start = new Date(startDate)
|
|||
|
|
if (end <= start) {
|
|||
|
|
return 'تاریخ پایان باید بعد از تاریخ شروع باشد'
|
|||
|
|
}
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const statusOptions = [
|
|||
|
|
{ title: 'فعال', value: 'active' },
|
|||
|
|
{ title: 'غیرفعال', value: 'inactive' },
|
|||
|
|
{ title: 'منقضی شده', value: 'expired' },
|
|||
|
|
// { title: 'استفاده شده', value: 'used' }
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
const dialog = computed({
|
|||
|
|
get: () => props.modelValue,
|
|||
|
|
set: (value) => emit('update:modelValue', value)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const isEdit = computed(() => !!props.serial)
|
|||
|
|
|
|||
|
|
const save = async () => {
|
|||
|
|
const isValid = await form.value.validate()
|
|||
|
|
if (!isValid) {
|
|||
|
|
console.log('فرم دارای خطا است')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!formData.value.serialNumber || !formData.value.commodity_id) {
|
|||
|
|
console.log('فیلدهای الزامی پر نشدهاند')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
loading.value = true
|
|||
|
|
const data = { ...formData.value }
|
|||
|
|
emit('save', data)
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(error)
|
|||
|
|
} finally {
|
|||
|
|
loading.value = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const close = () => {
|
|||
|
|
clearValidationErrors()
|
|||
|
|
emit('close')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const resetForm = () => {
|
|||
|
|
formData.value = {
|
|||
|
|
serialNumber: '',
|
|||
|
|
commodity_id: '',
|
|||
|
|
description: '',
|
|||
|
|
warrantyStartDate: '',
|
|||
|
|
warrantyEndDate: '',
|
|||
|
|
status: 'active',
|
|||
|
|
notes: ''
|
|||
|
|
}
|
|||
|
|
if (form.value) {
|
|||
|
|
form.value.resetValidation()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const clearValidationErrors = () => {
|
|||
|
|
if (form.value) {
|
|||
|
|
form.value.resetValidation()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const loadSerialData = () => {
|
|||
|
|
if (props.serial) {
|
|||
|
|
formData.value = {
|
|||
|
|
serialNumber: props.serial.serialNumber || '',
|
|||
|
|
commodity_id: props.serial.commodity?.id || '',
|
|||
|
|
description: props.serial.description || '',
|
|||
|
|
warrantyStartDate: props.serial.warrantyStartDate || '',
|
|||
|
|
warrantyEndDate: props.serial.warrantyEndDate || '',
|
|||
|
|
status: props.serial.status || 'active',
|
|||
|
|
notes: props.serial.notes || ''
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
resetForm()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const customFilter = (item: any, queryText: string) => {
|
|||
|
|
const text = item.name.toLowerCase()
|
|||
|
|
const searchText = queryText.toLowerCase()
|
|||
|
|
return text.indexOf(searchText) > -1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const handleCommoditySelect = (selectedCommodity: any) => {
|
|||
|
|
if (selectedCommodity && selectedCommodity.id) {
|
|||
|
|
formData.value.commodity_id = selectedCommodity.id
|
|||
|
|
} else {
|
|||
|
|
formData.value.commodity_id = ''
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
watch(() => props.serial, () => {
|
|||
|
|
nextTick(() => {
|
|||
|
|
loadSerialData()
|
|||
|
|
})
|
|||
|
|
}, { immediate: true })
|
|||
|
|
|
|||
|
|
watch(() => props.modelValue, (newVal) => {
|
|||
|
|
if (newVal) {
|
|||
|
|
nextTick(() => {
|
|||
|
|
loadSerialData()
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.v-dialog {
|
|||
|
|
direction: rtl;
|
|||
|
|
}
|
|||
|
|
</style>
|