feat: complete admin panel and backend admin api migration
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<!--
|
||||
Ported from legacy henza_admin/src/views/sms/create.vue.
|
||||
Each audience option is gated by its own rid, exactly as legacy did — the
|
||||
numeric codes (-1/0/1/2/9) are legacy's own and are preserved on the wire.
|
||||
|
||||
NOTE the "تک فروشی" audience has a rid (sms.create.tak) but NO option in the
|
||||
legacy markup, so it is unreachable. Preserved as absent.
|
||||
-->
|
||||
<a-spin :spinning="loading">
|
||||
<a-card title="ارسال پیامک">
|
||||
<a-form layout="vertical" @submit.prevent="handleSubmit">
|
||||
<div class="grid-2">
|
||||
<a-form-item label="ارسال برای">
|
||||
<a-select v-model:value="type">
|
||||
<a-select-option v-if="hasPermission('sms.create.single')" :value="-1">
|
||||
شماره موبایل
|
||||
</a-select-option>
|
||||
<a-select-option v-if="hasPermission('sms.create.all')" :value="0">
|
||||
همه مشتریان
|
||||
</a-select-option>
|
||||
<a-select-option v-if="hasPermission('sms.create.reagent')" :value="1">
|
||||
کارشناسان فروش
|
||||
</a-select-option>
|
||||
<a-select-option v-if="hasPermission('sms.create.omde')" :value="2">
|
||||
مشتریان عمده
|
||||
</a-select-option>
|
||||
<a-select-option v-if="hasPermission('sms.create.multiple')" :value="9">
|
||||
شماره های موبایل
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-if="type === -1 || type === 9"
|
||||
:label="type === 9 ? 'شماره های موبایل' : 'شماره موبایل'"
|
||||
:validate-status="err.mobile ? 'error' : ''"
|
||||
:help="err.mobile"
|
||||
>
|
||||
<a-textarea
|
||||
v-if="type === 9"
|
||||
v-model:value="mobile"
|
||||
:auto-size="{ minRows: 2, maxRows: 6 }"
|
||||
placeholder="هر شماره در یک خط"
|
||||
/>
|
||||
<a-input v-else v-model:value="mobile" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<a-form-item label="متن پیامک" :validate-status="err.text ? 'error' : ''" :help="err.text">
|
||||
<a-textarea v-model:value="text" :auto-size="{ minRows: 4, maxRows: 8 }" />
|
||||
</a-form-item>
|
||||
|
||||
<a-button type="primary" @click="handleSubmit">ارسال</a-button>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
<a-card v-if="hasPermission('sms.list')" title="لیست پیامک ها" class="mt-4">
|
||||
<XTable ref="tbl" :model="model" />
|
||||
</a-card>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import { buildSmsModel } from './smsTbl';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
import api from '../../api/client';
|
||||
|
||||
const users = useUsersStore();
|
||||
const hasPermission = (rid: string) => Boolean(users.hasPermission(rid));
|
||||
|
||||
const model = buildSmsModel();
|
||||
const tbl = ref<{ fetch: () => Promise<void> } | null>(null);
|
||||
const loading = ref(false);
|
||||
|
||||
const type = ref<number>(-1);
|
||||
const mobile = ref('');
|
||||
const text = ref('');
|
||||
const err = reactive<Record<string, string>>({});
|
||||
|
||||
async function handleSubmit() {
|
||||
Object.keys(err).forEach((k) => delete err[k]);
|
||||
if (!text.value) err.text = 'متن پیامک الزامی است';
|
||||
if ((type.value === -1 || type.value === 9) && !mobile.value) {
|
||||
err.mobile = 'شماره موبایل الزامی است';
|
||||
}
|
||||
if (Object.keys(err).length) return;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await api.post('sms', {
|
||||
type: type.value,
|
||||
mobile: mobile.value,
|
||||
text: text.value,
|
||||
});
|
||||
message.success(`پیامک برای ${data.sentCount} شماره ثبت شد`);
|
||||
text.value = '';
|
||||
mobile.value = '';
|
||||
tbl.value?.fetch();
|
||||
} catch (e: any) {
|
||||
message.error(e?.response?.data?.message ?? 'خطا در ارسال پیامک');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; }
|
||||
.mt-4 { margin-top: 1rem; }
|
||||
</style>
|
||||
@@ -0,0 +1,16 @@
|
||||
// The sent-SMS log. Legacy read it from `POST sms/table` inline in sms/create.vue
|
||||
// rather than through a table model file.
|
||||
import XTbl, { Xtc } from '../../components/x-table/model';
|
||||
|
||||
export function buildSmsModel(): XTbl {
|
||||
const tbl = new XTbl('admin/misc/sms/list', 'لیست پیامک ها');
|
||||
tbl.add(new Xtc('id', 'شماره'));
|
||||
tbl.add(new Xtc('text', 'متن پیامک').filterKey('body').filterText());
|
||||
tbl.add(new Xtc('mobile', 'گیرندگان').noSort());
|
||||
tbl.add(new Xtc('sent_count', 'تعداد').noSort());
|
||||
tbl.add(new Xtc('sender', 'ارسال کننده').noSort());
|
||||
tbl.add(new Xtc('caj', 'تاریخ').filterKey('createdAt').filterDate().noSort());
|
||||
return tbl;
|
||||
}
|
||||
|
||||
export default buildSmsModel;
|
||||
Reference in New Issue
Block a user