Files
template-10490/pages/order/[id].vue
赵忠林 bdcb779cf8 feat(order): 更新订单页面表单内容与提示信息
- 修改页面提示标题为"欢迎留言"
- 简化表单字段,移除产品选择、参考链接及文件上传功能
- 调整表单布局和标签文案,统一使用"留言标题"和"留言内容"
- 更新内容输入框的占位符文本
- 修改必填项验证提示信息,适配新的留言场景
2025-12-23 23:29:51 +08:00

400 lines
12 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<!-- Banner -->
<Banner :layout="layout"/>
<!-- 主体部分 -->
<div class="xl:w-screen-xl m-auto py-4 mt-12 px-4 sm:px-0 sm:mt-[220px]">
<el-page-header :icon="ArrowLeft" @back="goBack">
<template #content>
<span class="text-large font-600"> {{ page.title }} </span>
</template>
<template #extra>
</template>
<el-card shadow="hover" class="my-5 sm:my-10 sm:px-2">
<div class="grid grid-cols-1 sm:grid-cols-4 gap-8">
<div class="col-span-2">
<div class="my-2">
<el-alert title="欢迎留言" type="warning"/>
</div>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="80"
label-position="left"
status-icon
>
<el-form-item label="留言标题" class="hover:bg-gray-50 p-2" prop="reference">
<el-input v-model="form.title" placeholder="留言标题"/>
</el-form-item>
<el-form-item :label="$t('order.content')" prop="content" class="hover:bg-gray-50 p-2">
<el-input type="textarea" :rows="5" cols="80" v-model="form.content"
placeholder="请填写留言内容"/>
</el-form-item>
<template v-if="!token">
<el-form-item :label="$t('order.realName')" class="hover:bg-gray-50 p-2" prop="realName">
<el-input v-model="form.realName" :placeholder="$t('order.realName')"/>
</el-form-item>
<el-form-item :label="$t('order.phone')" class="hover:bg-gray-50 p-2" prop="phone">
<el-input v-model="form.phone" :maxlength="11" :placeholder="$t('order.phone')"/>
</el-form-item>
<el-form-item :label="$t('order.email')" class="hover:bg-gray-50 p-2" prop="email">
<el-input v-model="form.email" :placeholder="$t('order.email')"/>
</el-form-item>
</template>
<el-form-item :label="$t('order.code')" prop="code" class="hover:bg-gray-50 p-2">
<el-space class="flex">
<el-input size="large" :placeholder="$t('order.imgCode')" maxlength="5" v-model="form.code"/>
<el-image :alt="$t('order.imgCode')" v-if="captcha" :src="captcha" @click="changeCaptcha"/>
</el-space>
</el-form-item>
<el-form-item>
<div class="submitForm ml-2">
<el-button
:loading="loading"
size="large"
type="primary"
@click="submitForm(formRef)"
>
{{ $t('order.submit') }}
</el-button>
</div>
</el-form-item>
</el-form>
</div>
<div class="w-full col-span-2">
<div class="p-3">
<div class="w-full text-lg font-bold">
最新留言
</div>
<div class="likes-list my2 w-full">
<div v-for="(item,index) in orders" :key="index" class="item flex justify-between bg-gray-50 p-4 mb-2">
<div class="text-sm">
<div class="avatar flex">
<el-avatar src="/assets/default-avatar.png"/>
<div class="nickname flex flex-col ml-2">
<span class="font-bold">{{ item.realName }}</span>
<span class="text-sm text-gray-400">{{ item.createTime }}</span>
<div class="content py-1">{{ item.content }}</div>
<div class="content py-1 text-red-500">{{ item.comments }}</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-4 flex justify-end" v-if="total > 0">
<el-pagination
:current-page="currentPage"
:page-size="pageSize"
:page-sizes="[5, 10, 20]"
background
layout="total, sizes, prev, pager, next"
:total="total"
@current-change="handlePageChange"
@size-change="handleSizeChange"
/>
</div>
</div>
</div>
</div>
</el-card>
</el-page-header>
</div>
<el-dialog v-model="dialogVisible">
<div class="flex justify-center">
<el-image w-full :src="dialogImageUrl" alt="查看证件"/>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import {ArrowLeft, View, Search, Plus} from '@element-plus/icons-vue'
import type {FormInstance, FormRules, UploadProps, UploadUserFile} from 'element-plus'
import {useLayout, usePage, useUser} from "~/composables/configState";
import {getNavIdByParamsId} from "~/utils/common";
import type {CmsOrder} from "~/api/cms/cmsOrder/model";
import useFormData from "~/utils/use-form-data";
import {addCmsOrder, pageCmsOrder } from "~/api/cms/cmsOrder";
import {getCaptcha} from "~/api/passport/login";
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
import {listCmsWebsite, pageCmsWebsiteAll} from "~/api/cms/cmsWebsite";
import type {CmsWebsite} from "~/api/cms/cmsWebsite/model";
import {useHead} from "nuxt/app";
// 在最顶部添加
definePageMeta({
title: '订单页面'
})
// 引入状态管理
const route = useRoute();
const router = useRouter();
const token = useToken();
const navId = ref();
const layout = useLayout();
const user = useUser();
const page = usePage();
const siteList = ref<CmsWebsite[]>([]);
const dialogVisible = ref(false)
const formRef = ref<FormInstance>()
const dialogImageUrl = ref('')
const files = ref<UploadUserFile[]>([])
const filesStr = ref<string[]>([])
// 验证码 base64 数据
const captcha = ref('');
const text = ref<string>('');
const loading = ref(false)
const orders = ref<CmsOrder[]>([])
const currentPage = ref(1)
const pageSize = ref(5)
const total = ref(0)
const {form, resetFields} = useFormData<CmsOrder>({
// 订单号
orderId: undefined,
// 模型名称
model: 'order',
// 订单标题
title: undefined,
// 订单编号
orderNo: undefined,
// 订单类型0商城 1询价 2留言
type: undefined,
// 关联项目ID配合订单类型使用
articleId: undefined,
// 关联网站ID
websiteId: undefined,
// 真实姓名
realName: undefined,
// 手机号码
phone: undefined,
// 电子邮箱
email: undefined,
// 收货地址
address: undefined,
// 订单内容
content: undefined,
// 附件
files: undefined,
// 订单总额
totalPrice: '0.00',
// 实际付款
payPrice: '0.00',
// 报价询价
price: '0.00',
// 购买数量
totalNum: undefined,
// 二维码地址,保存订单号,支付成功后才生成
qrcode: undefined,
// 下单渠道0网站 1小程序 2其他
channel: undefined,
// 过期时间
expirationTime: undefined,
// 订单是否已结算(0未结算 1已结算)
isSettled: undefined,
// 用户id
userId: undefined,
// 备注
comments: undefined,
// 排序号
sortNumber: undefined,
// 是否删除, 0否, 1是
deleted: undefined,
// 租户id
tenantId: undefined,
// 创建时间
createTime: undefined,
// 图像验证码
code: '',
})
const rules = reactive<FormRules<CmsOrder>>({
title: [
{required: true, message: '请输入产品名称', trigger: 'blur'},
],
phone: [
{required: true, message: '请输入手机号码', trigger: 'blur'},
{pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur'},
],
realName: [
{required: true, message: '请输入联系人姓名', trigger: 'blur'},
],
content: [
{required: true, message: '请输入您的留言内容', trigger: 'blur'},
]
})
/* 获取图形验证码 */
const changeCaptcha = async () => {
getCaptcha().then(captchaData => {
captcha.value = captchaData.base64;
text.value = captchaData.text;
})
};
// 加载留言列表(带分页)
const loadOrders = async () => {
try {
const response = await pageCmsOrder({
isSettled: true,
page: currentPage.value,
limit: pageSize.value,
sort: 'createTime',
order: 'desc',
sceneType: 'display'
})
orders.value = response?.list || []
total.value = response?.count || 0
} catch (error) {
console.error('Failed to load orders:', error)
}
}
// 将 SEO 相关的逻辑修改为
const updateSeo = (data: any) => {
const title = data?.title || '';
const description = data?.comments || data?.title || '';
const appName = useRuntimeConfig().public.appName;
// 使用 definePageMeta 设置页面元数据
useHead({
title,
meta: [
{ name: 'description', content: description },
{ name: 'keywords', content: title },
{ property: 'og:title', content: title },
{ property: 'og:description', content: description }
]
})
}
// 请求数据
const reload = async () => {
try {
const data = await getCmsNavigation(navId.value)
if (!data) return
page.value = data
layout.value.banner = data.banner
// 更新 SEO
updateSeo(data)
// 二级栏目分类
const res = await pageCmsWebsiteAll({
official: true,
sort: 'websiteId',
order: 'asc'
})
siteList.value = res?.list || []
// 用户信息
if (user.value) {
form.realName = user.value.realName
form.phone = user.value.phone
form.email = user.value.email
}
// 重置分页并加载留言列表
currentPage.value = 1
await loadOrders()
changeCaptcha()
} catch (error) {
console.error('Failed to load page data:', error)
}
}
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
dialogImageUrl.value = uploadFile.url!
dialogVisible.value = true
}
const filesRemove: UploadProps['onRemove'] = (uploadFile) => {
const index = filesStr.value.findIndex(f => f == uploadFile.url);
filesStr.value.splice(index, 1)
}
const filesOnSuccess = (e: any) => {
filesStr.value.push(e.data.downloadUrl)
}
const onWebsite = (item: CmsWebsite) => {
form.articleId = item.websiteId;
form.websiteId = item.websiteId;
}
// 提交表单
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
if (loading.value) return // 防止重复提交
if (form.code !== text.value) {
changeCaptcha();
ElMessage.error('验证码不正确!');
return false;
}
if(process.server){
return false;
}
loading.value = true
try {
const valid = await formEl.validate()
if (valid) {
// 如果reference不为空将其添加到content前面
if (form.reference) {
form.content = `参考网站:${form.reference}\n\n${form.content}`
}
if (filesStr.value.length > 0) {
form.files = JSON.stringify(filesStr.value);
}
const res = await addCmsOrder(form)
if (res.code == 0) {
ElMessage.success(res.message)
resetFields();
} else {
ElMessage.error(res.message)
}
}
} catch (error) {
console.error(error)
} finally {
loading.value = false
}
}
const goBack = () => {
router.back();
}
// 分页切换
const handlePageChange = (pageNum: number) => {
currentPage.value = pageNum
loadOrders()
}
const handleSizeChange = (size: number) => {
pageSize.value = size
currentPage.value = 1
loadOrders()
}
watch(
() => route.params.id,
(id) => {
navId.value = getNavIdByParamsId(id);
reload();
},
{immediate: true}
);
</script>
<style lang="scss">
</style>