feat: 促销系统完善、发票页重构、前端中文化、订单表迁移及多项优化
前端: - 发票页完整重构:智能按钮状态、防重复开票、空态引导、订单多选 - 全局中文化:Ant Design Vue locale配置、清除残留英文UI文本 - 新增关于我们、联系我们页面 - 首页活动专区、搜索页、Skill详情等多处优化 后端: - 订单模块:新增original_amount/promotion_deduct_amount字段及DB迁移 - 促销系统:完善促销规则、过期任务、批量查询等 - 新增RateLimit注解及拦截器、CORS过滤器、Health检查接口 - Logback日志配置、points枚举修复等
This commit is contained in:
@@ -204,12 +204,34 @@
|
||||
<div class="form-tip">支持 MP4/MOV/AVI/WEBM 格式,最大 100MB;也可粘贴网盘链接</div>
|
||||
<a-progress v-if="videoUploading" :percent="videoProgress" size="small" style="margin-top: 4px" />
|
||||
</a-form-item>
|
||||
<a-form-item label="作品链接" name="portfolioUrl">
|
||||
<a-input v-model:value="form.portfolioUrl" placeholder="请输入个人作品集或GitHub链接(选填)">
|
||||
<template #prefix>
|
||||
<desktop-outlined />
|
||||
</template>
|
||||
</a-input>
|
||||
<a-form-item label="作品集" name="portfolioUrl">
|
||||
<div class="upload-area">
|
||||
<a-upload
|
||||
:file-list="portfolioFileList"
|
||||
:before-upload="beforePortfolioUpload"
|
||||
:custom-request="handlePortfolioUpload"
|
||||
:max-count="5"
|
||||
multiple
|
||||
accept=".zip,.rar,.7z,.tar.gz,.pdf,.doc,.docx,.ppt,.pptx,.png,.jpg,.jpeg,.gif"
|
||||
@remove="handlePortfolioRemove"
|
||||
>
|
||||
<a-button :loading="portfolioUploading">
|
||||
<template #icon><upload-outlined /></template>
|
||||
{{ portfolioUploading ? '上传中...' : '选择作品文件' }}
|
||||
</a-button>
|
||||
</a-upload>
|
||||
<div class="upload-or">或</div>
|
||||
<a-input
|
||||
v-model:value="form.portfolioUrl"
|
||||
placeholder="粘贴作品集链接(GitHub、网盘等)"
|
||||
:disabled="!!portfolioFileList.length"
|
||||
style="flex: 1"
|
||||
>
|
||||
<template #prefix><link-outlined /></template>
|
||||
</a-input>
|
||||
</div>
|
||||
<div class="form-tip">支持 ZIP/RAR/PDF/图片等格式,单文件最大 50MB,最多 5 个;也可粘贴链接</div>
|
||||
<a-progress v-if="portfolioUploading" :percent="portfolioProgress" size="small" style="margin-top: 4px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="期望收益" name="expectedIncome">
|
||||
@@ -325,12 +347,17 @@ import {
|
||||
ProjectOutlined,
|
||||
DollarCircleOutlined,
|
||||
CheckCircleFilled,
|
||||
CheckCircleOutlined,
|
||||
TrophyOutlined,
|
||||
StarOutlined,
|
||||
UploadOutlined,
|
||||
VideoCameraOutlined,
|
||||
LinkOutlined,
|
||||
DesktopOutlined
|
||||
DesktopOutlined,
|
||||
WalletOutlined,
|
||||
RiseOutlined,
|
||||
TeamOutlined,
|
||||
RightOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
const formRef = ref(null)
|
||||
@@ -347,6 +374,11 @@ const videoFileList = ref([])
|
||||
const videoUploading = ref(false)
|
||||
const videoProgress = ref(0)
|
||||
|
||||
// 作品集上传状态
|
||||
const portfolioFileList = ref([])
|
||||
const portfolioUploading = ref(false)
|
||||
const portfolioProgress = ref(0)
|
||||
|
||||
const form = reactive({
|
||||
realName: '',
|
||||
phone: '',
|
||||
@@ -488,6 +520,50 @@ const handleVideoRemove = () => {
|
||||
videoProgress.value = 0
|
||||
}
|
||||
|
||||
// 作品集上传前校验
|
||||
const beforePortfolioUpload = (file) => {
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
message.error('单个文件大小不能超过 50MB')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 作品集上传处理
|
||||
const handlePortfolioUpload = async ({ file, onSuccess, onError }) => {
|
||||
portfolioUploading.value = true
|
||||
portfolioProgress.value = 0
|
||||
const progressTimer = setInterval(() => {
|
||||
if (portfolioProgress.value < 90) portfolioProgress.value += 10
|
||||
}, 200)
|
||||
try {
|
||||
const res = await uploadApi.uploadFile('portfolio', file)
|
||||
clearInterval(progressTimer)
|
||||
portfolioProgress.value = 100
|
||||
const url = res.data?.url || res.data?.fileUrl
|
||||
portfolioFileList.value = [...portfolioFileList.value, { uid: file.uid, name: file.name, status: 'done', url }]
|
||||
// 将所有已上传文件URL用逗号拼接存入portfolioUrl
|
||||
form.portfolioUrl = portfolioFileList.value.map(f => f.url).join(',')
|
||||
onSuccess(res, file)
|
||||
message.success('文件上传成功')
|
||||
} catch (err) {
|
||||
clearInterval(progressTimer)
|
||||
onError(err)
|
||||
message.error('文件上传失败:' + (err.response?.data?.message || err.message))
|
||||
} finally {
|
||||
portfolioUploading.value = false
|
||||
portfolioProgress.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
// 作品集文件删除
|
||||
const handlePortfolioRemove = (file) => {
|
||||
portfolioFileList.value = portfolioFileList.value.filter(f => f.uid !== file.uid)
|
||||
form.portfolioUrl = portfolioFileList.value.length
|
||||
? portfolioFileList.value.map(f => f.url).join(',')
|
||||
: ''
|
||||
}
|
||||
|
||||
const rules = {
|
||||
realName: [{ required: true, message: '请输入真实姓名', trigger: 'blur' }],
|
||||
phone: [
|
||||
@@ -544,6 +620,8 @@ const resetForm = () => {
|
||||
resumeProgress.value = 0
|
||||
videoFileList.value = []
|
||||
videoProgress.value = 0
|
||||
portfolioFileList.value = []
|
||||
portfolioProgress.value = 0
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user