Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite

This commit is contained in:
李志鹏
2026-01-21 16:55:18 +08:00
17 changed files with 1387 additions and 816 deletions

View File

@@ -0,0 +1,3 @@
<svg width="22" height="12" viewBox="0 0 22 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 1L11 11L21 1" stroke="#585858" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 KiB

View File

@@ -16,29 +16,6 @@
</template> </template>
</a-range-picker> </a-range-picker>
</div> </div>
<!-- <div class="admin_state_item">
<span>Country or Region:</span>
<a-select
v-model:value="country"
:allowClear="true"
show-search
style="width: 230px"
:filter-option="filterOption"
placeholder="Select Item..."
max-tag-count="responsive"
:options="allCountry"
></a-select>
</div> -->
<!-- <div class="admin_state_item">
<span>Email:</span>
<input
v-model="email"
placeholder="Please enter email"
@keydown.enter="gettrialList"
type="text"
style="width: 230px"
/>
</div> -->
<div class="admin_state_item"> <div class="admin_state_item">
<span>{{ $t('admin.UserName') }}:</span> <span>{{ $t('admin.UserName') }}:</span>
<a-select <a-select
@@ -53,19 +30,6 @@
@keydown.enter="gettrialList" @keydown.enter="gettrialList"
></a-select> ></a-select>
</div> </div>
<!-- <div class="admin_state_item">
<span>User Type:</span>
<a-select
v-model:value="systemUser"
size="large"
style="width: 230px"
optionFilterProp="label"
:options="state"
placeholder="Please select"
allowClear
show-search
></a-select>
</div> -->
</div> </div>
<div class="admin_search"> <div class="admin_search">
<div class="admin_search_item" @click="searchHistoryList"> <div class="admin_search_item" @click="searchHistoryList">
@@ -116,6 +80,24 @@
</div> </div>
</div> </div>
<div class="admin_table_content" ref="historyTable"> <div class="admin_table_content" ref="historyTable">
<div class="admin_state_list plan_list">
<div
v-for="plan in planFilterOptions"
:key="plan.id"
class="plan_item"
:class="{
active: subscriptionPlanId === plan.id,
disabled: plan.status === 'PENDING'
}"
@click="plan.status !== 'PENDING' && selectPlanFilter(plan.id)"
>
<span class="plan_name">{{ plan.name }}</span>
<MoreOutlined
class="plan_more_icon"
@click.stop="plan.status !== 'PENDING' && openPlanRenameModal(plan)"
/>
</div>
</div>
<a-table <a-table
@resizeColumn="handleResizeColumn" @resizeColumn="handleResizeColumn"
:loading="tableLoading" :loading="tableLoading"
@@ -147,12 +129,6 @@
<div class="operate_item" @click="deleteAagree(record)"> <div class="operate_item" @click="deleteAagree(record)">
{{ $t('admin.Delete') }} {{ $t('admin.Delete') }}
</div> </div>
<!-- <div
class="operate_item"
@click="deleteGroup(record, index)"
>
Delete
</div> -->
</div> </div>
</template> </template>
</a-table> </a-table>
@@ -160,31 +136,58 @@
<allUserPoerationsVue <allUserPoerationsVue
ref="allUserPoerationsVue" ref="allUserPoerationsVue"
@searchHistoryList="searchHistoryList" @searchHistoryList="searchHistoryList"
:plan-options="planFilterOptions"
></allUserPoerationsVue> ></allUserPoerationsVue>
<div class="renamePlanModal" ref="renamePlanModal"></div>
<!-- 重命名订阅计划弹窗 -->
<a-modal
v-model:visible="renamePlanModalVisible"
:title="$t('admin.RenamePlan')"
@ok="confirmRenamePlan"
@cancel="cancelRenamePlan"
:ok-text="$t('admin.OK')"
:cancel-text="$t('admin.Cancel')"
:get-container="() => $refs.renamePlanModal"
>
<div class="rename-plan-form">
<div class="admin_state_item">
<span>{{ $t('admin.PlanName') }}:</span>
<a-input
v-model:value="renamePlanForm.planName"
:placeholder="$t('admin.InputPlanName')"
style="width: 250px"
@pressEnter="confirmRenamePlan"
/>
</div> </div>
</template> </div>
<script lang="ts"> </a-modal>
import { </div>
</template>
<script lang="ts">
import {
defineComponent, defineComponent,
ref, ref,
createVNode, createVNode,
computed, computed,
reactive, reactive,
toRefs, toRefs,
onMounted unref,
} from 'vue' watch
import { formatTime } from '@/tool/util' } from 'vue'
import { useStore } from 'vuex' import { formatTime } from '@/tool/util'
import { Https } from '@/tool/https' import { useStore } from 'vuex'
import { Modal, message } from 'ant-design-vue' import { Https } from '@/tool/https'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue' import { Modal, message, Input } from 'ant-design-vue'
import allUserPoerationsVue from './addAllUser.vue' import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
import { useI18n } from 'vue-i18n' import allUserPoerationsVue from './addAllUser.vue'
import SelectUser from '@/component/common/SelectUser.vue' import { useI18n } from 'vue-i18n'
export default defineComponent({ export default defineComponent({
components: { allUserPoerationsVue }, components: { allUserPoerationsVue, MoreOutlined },
setup() { setup() {
const store: any = useStore() const store: any = useStore()
const currentOrganizationId = computed(
() => store.state.UserHabit.userDetail.organizationId
)
const selectedRowKeys = ref([]) as any const selectedRowKeys = ref([]) as any
const onSelectChange = (changableRowKeys: string[]) => { const onSelectChange = (changableRowKeys: string[]) => {
selectedRowKeys.value = changableRowKeys selectedRowKeys.value = changableRowKeys
@@ -203,6 +206,7 @@ export default defineComponent({
} }
}) })
}) })
const { t } = useI18n() const { t } = useI18n()
let filterData: any = reactive({ let filterData: any = reactive({
@@ -218,10 +222,16 @@ export default defineComponent({
systemUser: '', systemUser: '',
order: '', //'Ascending 升序 Descending 降序' order: '', //'Ascending 升序 Descending 降序'
orderBy: '', orderBy: '',
userName: '' userName: '',
subscriptionPlanId: ''
}) })
let renameData: any = ref({}) //修改名字选中的数据 let renameData: any = ref({}) //修改名字选中的数据
const renamePlanModalVisible = ref(false)
const renamePlanForm = reactive({
planId: null as number | null,
planName: ''
})
const columns: any = computed(() => { const columns: any = computed(() => {
return [ return [
{ {
@@ -248,13 +258,6 @@ export default defineComponent({
key: 'userName', key: 'userName',
width: 150, width: 150,
ellipsis: true ellipsis: true
// customRender: (record: any) => {
// let time = formatTime(
// record.text / 1000,
// "YYYY-MM-DD hh:mm:ss"
// );
// return time;
// },
}, },
{ {
title: t('admin.language'), title: t('admin.language'),
@@ -278,10 +281,6 @@ export default defineComponent({
{ {
title: t('admin.Credits'), title: t('admin.Credits'),
align: 'center', align: 'center',
// width: 150,
// minWidth: 100,
// maxWidth: 200,
// resizable: true,
dataIndex: 'credits', dataIndex: 'credits',
key: 'credits', key: 'credits',
width: 100, width: 100,
@@ -309,7 +308,6 @@ export default defineComponent({
width: 120, width: 120,
align: 'center', align: 'center',
fixed: 'right', fixed: 'right',
// slots:{customRender:'action'}
Operations: true Operations: true
} }
] ]
@@ -354,7 +352,8 @@ export default defineComponent({
(filterData.order = ''), //'Ascending 升序 Descending 降序' (filterData.order = ''), //'Ascending 升序 Descending 降序'
(filterData.orderBy = ''), //'Ascending 升序 Descending 降序' (filterData.orderBy = ''), //'Ascending 升序 Descending 降序'
(filterData.systemUser = ''), (filterData.systemUser = ''),
(filterData.userName = '') (filterData.userName = ''),
(filterData.subscriptionPlanId = '')
} }
let setHistoryListData = () => { let setHistoryListData = () => {
let startDate: any = filterData.rangePickerValue?.[0] let startDate: any = filterData.rangePickerValue?.[0]
@@ -377,18 +376,17 @@ export default defineComponent({
order: filterData.order, order: filterData.order,
orderBy: filterData.orderBy, orderBy: filterData.orderBy,
// userName: filterData.userName, // userName: filterData.userName,
userName: filterData.ids userName: filterData.ids,
subscriptionPlanId: filterData.subscriptionPlanId
} }
return data return data
} }
//获取列表 //获取列表
let gettrialList = () => { const gettrialList = () => {
filter.tableLoading = true filter.tableLoading = true
let data = setHistoryListData() let data = setHistoryListData()
Https.axiosPost(Https.httpUrls.subAccountList, data).then((rv: any) => { Https.axiosPost(Https.httpUrls.subAccountList, data).then((rv: any) => {
if (rv) { if (rv) {
console.log(rv)
// this.dataList = rv
filter.dataList = rv.content filter.dataList = rv.content
filterData.total = rv.total filterData.total = rv.total
filter.tableLoading = false filter.tableLoading = false
@@ -417,6 +415,66 @@ export default defineComponent({
// 使用 option.label 进行搜索 // 使用 option.label 进行搜索
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
} }
// 订阅计划筛选(按钮点击)
const selectPlanFilter = async (planId: string) => {
filterData.subscriptionPlanId = planId
// 切换管理员订阅计划
Https.axiosGet(Https.httpUrls.switchSubscribePlan, {
params: {
targetSubscriptionPlanId: planId,
adminAccId: store.state.UserHabit.userDetail.id
}
}).then((res: any) => {
console.log(res)
})
searchHistoryList()
}
const planFilterOptions = ref([])
const fetchSubscribePlanList = () => {
const orgId = currentOrganizationId.value
if (!orgId) return
Https.axiosPost(Https.httpUrls.searchSubscribeByOrg, {
organizationId: orgId,
status: ['ACTIVE', 'PENDING']
}).then(res => {
// 将与当前用户 subscriptionPlanId 相同的订阅计划放到第一个
const userSubscriptionPlanId = store.state.UserHabit.userDetail.subscriptionPlanId
if (userSubscriptionPlanId && Array.isArray(res)) {
const sortedList = [...res].sort((a: any, b: any) => {
const isAUserPlan = a.id == userSubscriptionPlanId
const isBUserPlan = b.id == userSubscriptionPlanId
if (isAUserPlan && !isBUserPlan) return -1
if (!isAUserPlan && isBUserPlan) return 1
return 0
})
planFilterOptions.value = sortedList
} else {
planFilterOptions.value = res
}
})
}
// 监听组织ID获取到值后再拉取订阅计划
watch(
() => currentOrganizationId.value,
orgId => {
if (orgId) {
fetchSubscribePlanList()
const userSubscriptionPlanId =
store.state.UserHabit.userDetail.subscriptionPlanId
if (userSubscriptionPlanId) {
selectPlanFilter(userSubscriptionPlanId)
}
}
},
{ immediate: true }
)
// 打开重命名弹窗(基于当前点击的计划)
const openPlanRenameModal = plan => {
renamePlanForm.planId = plan.id
renamePlanForm.planName = plan?.name || ''
renamePlanModalVisible.value = true
console.log(renamePlanForm)
}
let addhHistoryList = () => { let addhHistoryList = () => {
allUserPoerationsVue.value.init({ value: 'Add', label: t('admin.add') }, '') allUserPoerationsVue.value.init({ value: 'Add', label: t('admin.add') }, '')
} }
@@ -521,6 +579,33 @@ export default defineComponent({
gettrialList() gettrialList()
}) })
} }
// 确认重命名
const confirmRenamePlan = () => {
if (!renamePlanForm.planName || !renamePlanForm.planName.trim()) {
message.warning(t('admin.PlanNameRequired'))
return
}
Https.axiosPost(Https.httpUrls.updateSubscribePlan, {
id: renamePlanForm.planId,
name: renamePlanForm.planName.trim()
})
.then((rv: any) => {
message.success(t('admin.RenamePlanSuccess'))
renamePlanModalVisible.value = false
fetchSubscribePlanList()
})
.catch((error: any) => {
message.error(error.message || t('admin.RenamePlanFailed'))
})
}
// 取消重命名
const cancelRenamePlan = () => {
renamePlanModalVisible.value = false
renamePlanForm.planId = null
renamePlanForm.planName = ''
}
onMounted(() => { onMounted(() => {
let allCountry: any = sessionStorage.getItem('allCountry') let allCountry: any = sessionStorage.getItem('allCountry')
if (allCountry) { if (allCountry) {
@@ -545,7 +630,15 @@ export default defineComponent({
ExportAccountData, ExportAccountData,
uploadTemplate, uploadTemplate,
deleteList, deleteList,
deleteAagree deleteAagree,
planFilterOptions,
selectPlanFilter,
openPlanRenameModal,
renamePlanModalVisible,
renamePlanForm,
confirmRenamePlan,
cancelRenamePlan,
fetchSubscribePlanList
} }
}, },
data() { data() {
@@ -557,31 +650,42 @@ export default defineComponent({
} }
}, },
mounted() { mounted() {
let historyTable: any = this.$refs.historyTable this.updateTableHeight()
this.historyTableHeight = historyTable.clientHeight - 200 window.addEventListener('resize', this.updateTableHeight)
}, },
methods: {} beforeUnmount() {
}) window.removeEventListener('resize', this.updateTableHeight)
</script> },
<style lang="less" scoped> methods: {
.admin_page { updateTableHeight() {
const historyTable: any = this.$refs.historyTable
if (historyTable) {
// 为底部分页器预留固定空间,使表格部分高度固定且分页器始终可见
this.historyTableHeight = historyTable.clientHeight - 200
}
}
}
})
</script>
<style lang="less" scoped>
.admin_page {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
} }
.admin_table_content { .admin_table_content {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
} }
.admin_page .admin_table_search .admin_state { .admin_page .admin_table_search .admin_state {
display: flex; display: flex;
width: 70%; width: 70%;
flex-wrap: wrap; flex-wrap: wrap;
align-content: flex-start; align-content: flex-start;
} }
.admin_page .admin_table_search .admin_search { .admin_page .admin_table_search .admin_search {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
width: 30%; width: 30%;
@@ -589,12 +693,86 @@ export default defineComponent({
height: 4rem; height: 4rem;
font-size: 1.6rem; font-size: 1.6rem;
} }
} }
.all-user { .plan_list {
margin-top: 1rem;
display: flex;
// flex-wrap: wrap;
padding-left: 2.8rem;
column-gap: 0.6rem;
margin-bottom: 2rem;
.plan_item {
height: 4rem;
width: auto;
min-width: 10rem;
display: flex;
align-items: center;
justify-content: center;
// font-size: 1.8rem;
font-weight: 600;
border-radius: 1.3rem;
color: #fff;
cursor: pointer;
border: 1.8px solid #000;
background-color: #000;
padding: 0 1rem 0 2rem;
&:hover {
color: #000;
background-color: #fff;
}
&.active {
background: #ffffff;
color: #000000;
}
&.disabled {
opacity: 0.5;
cursor: not-allowed;
background-color: #d9d9d9;
border-color: #d9d9d9;
color: #999;
&:hover {
background-color: #d9d9d9;
color: #999;
}
}
}
.plan_item {
column-gap: 0.6rem;
}
.plan_more_icon {
font-size: 1.6rem;
cursor: pointer;
}
}
.subscription-plan-cell {
display: flex;
align-items: center;
justify-content: center;
}
.rename-plan-form {
padding: 2rem 0;
.admin_state_item {
display: flex;
align-items: center;
> span {
width: 10rem;
margin-right: 1rem;
}
}
}
.all-user {
.admin_table_content { .admin_table_content {
:deep(.ant-table-wrapper) { :deep(.ant-table-wrapper) {
overflow: hidden ; overflow: hidden;
} }
} }
} }
</style> </style>

View File

@@ -287,12 +287,27 @@ export default defineComponent({
const saveCanvas = async (canvasData:any)=>{ const saveCanvas = async (canvasData:any)=>{
const index = detailData.designDetail.clothes.findIndex(item => item.id === canvasData.id); const index = detailData.designDetail.clothes.findIndex(item => item.id === canvasData.id);
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
let canvasJSON = JSON.parse(canvasData.canvasJSON) if(!detailDom?.editCanvas)return resolve()
if(!canvasJSON)return resolve() let canvasJSON = detailDom?.editCanvas?.getJSON()
// canvasData.canvas.objects.forEach((objectsItem:any) => { let canvasData = JSON.parse(canvasJSON)
// if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src) if(!canvasData)return resolve()
// }); function deepProcessObjects(data:any, callback:any) {
let blob = new Blob([JSON.stringify(canvasJSON)], { type: "application/json" }); if (!Array.isArray(data)) return data;
return data.map(item => {
callback(item)
const processedItem = {...item};
if (processedItem.objects &&
Array.isArray(processedItem.objects) &&
processedItem.objects.length > 0) {
processedItem.objects = deepProcessObjects(processedItem.objects, callback);
}
return processedItem;
});
}
canvasData.canvas.objects = deepProcessObjects(canvasData.canvas.objects,(item:any)=>{
if(item.type == 'image')item.minioUrl = getMinioUrl(item.src)
})
let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" });
let formData = new FormData(); let formData = new FormData();
formData.append("file", blob, "data.json"); formData.append("file", blob, "data.json");
formData.append("designItemDetailId", detailData.selectDetail.id); formData.append("designItemDetailId", detailData.selectDetail.id);

View File

@@ -925,6 +925,8 @@ export default defineComponent({
}, },
onCancel() {} onCancel() {}
}) })
}else{
this.fileList = this.fileList.filter((item: any) => item.imgUrl)
} }
}) })
}, },

View File

@@ -854,6 +854,10 @@ export default defineComponent({
font-size: 2.2rem; font-size: 2.2rem;
font-weight: bold; font-weight: bold;
color: #030303; color: #030303;
@media (max-width: 767px) {
font-size: 1.2rem;
margin-left: .5rem;
}
} }
.email_last_step_block_icon { .email_last_step_block_icon {
cursor: pointer; cursor: pointer;

View File

@@ -161,6 +161,13 @@
font-size: 2.4rem; font-size: 2.4rem;
line-height: 8.7rem; line-height: 8.7rem;
outline: none; outline: none;
@media (max-width: 767px) {
border-radius: .7rem;
width: 3.5rem;
height: 3.5rem;
font-size: 1.8rem;
line-height: 3.5rem;
}
} }
input:last-of-type { input:last-of-type {
margin-right: 0; margin-right: 0;

View File

@@ -335,9 +335,22 @@ export default defineComponent({
let canvasData = JSON.parse(canvasJSON) let canvasData = JSON.parse(canvasJSON)
if(!canvasData)return if(!canvasData)return
canvasData.canvas.objects.forEach((objectsItem:any) => { function deepProcessObjects(data:any, callback:any) {
if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src) if (!Array.isArray(data)) return data;
return data.map(item => {
callback(item)
const processedItem = {...item};
if (processedItem.objects &&
Array.isArray(processedItem.objects) &&
processedItem.objects.length > 0) {
processedItem.objects = deepProcessObjects(processedItem.objects, callback);
}
return processedItem;
}); });
}
canvasData.canvas.objects = deepProcessObjects(canvasData.canvas.objects,(item:any)=>{
if(item.type == 'image')item.minioUrl = getMinioUrl(item.src)
})
let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" }); let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" });
let formData = new FormData(); let formData = new FormData();
formData.append("file", blob, "data.json"); formData.append("file", blob, "data.json");

View File

@@ -206,11 +206,22 @@ export default defineComponent({
if(!canvasJSON)return if(!canvasJSON)return
if(!store.state.Workspace.probjects?.id)return if(!store.state.Workspace.probjects?.id)return
let canvasData = JSON.parse(canvasJSON) let canvasData = JSON.parse(canvasJSON)
console.log(canvasData) function deepProcessObjects(data:any, callback:any) {
canvasData.canvas.objects.forEach((objectsItem:any) => { if (!Array.isArray(data)) return data;
if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src) return data.map(item => {
callback(item)
const processedItem = {...item};
if (processedItem.objects &&
Array.isArray(processedItem.objects) &&
processedItem.objects.length > 0) {
processedItem.objects = deepProcessObjects(processedItem.objects, callback);
}
return processedItem;
}); });
}
canvasData.canvas.objects = deepProcessObjects(canvasData.canvas.objects,(item:any)=>{
if(item.type == 'image')item.minioUrl = getMinioUrl(item.src)
})
let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" }); let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" });
let formData = new FormData(); let formData = new FormData();
formData.append("file", blob, "data.json"); formData.append("file", blob, "data.json");

View File

@@ -79,7 +79,7 @@
Forgot password Forgot password
</div> --> </div> -->
</div> </div>
<div class="password_input_block"> <div class="password_input_block" v-show="emailStap !== 2">
<div v-show="passwordConditionShow" class="conditionShow"> <div v-show="passwordConditionShow" class="conditionShow">
<div class="item"> <div class="item">
<div class="icon"> <div class="icon">
@@ -144,12 +144,13 @@
@click="changePasswordType()" @click="changePasswordType()"
></div> ></div>
</div> </div>
<span style="font-weight: 400; opacity: 0.7" <span style="font-weight: 400; opacity: 0.7" v-show="emailStap !== 2"
>{{ userI18n[selectUserI18n].inputPasswordTip }}</span >{{ userI18n[selectUserI18n].inputPasswordTip }}</span
> >
<div class="login_form_title marign_top30">{{ userI18n[selectUserI18n].Email }}</div> <div class="login_form_title marign_top30" v-show="emailStap !== 2">{{ userI18n[selectUserI18n].Email }}</div>
<input <input
class="login_form_input" class="login_form_input"
v-show="emailStap !== 2"
:placeholder="userI18n[selectUserI18n].inputEmail" :placeholder="userI18n[selectUserI18n].inputEmail"
v-model="email" v-model="email"
@keydown.enter="submitPerLogin()" @keydown.enter="submitPerLogin()"
@@ -917,6 +918,7 @@ export default defineComponent({
position: relative; position: relative;
@media (max-width: 768px) { @media (max-width: 768px) {
margin-top: 2.4rem; margin-top: 2.4rem;
height: 20rem;
} }
&[state="2"] { &[state="2"] {
> * { > * {
@@ -1015,6 +1017,9 @@ export default defineComponent({
// margin-top: 4rem; // margin-top: 4rem;
.email_last_step_bottom { .email_last_step_bottom {
padding: 0 40px; padding: 0 40px;
@media (max-width: 767px) {
padding: 0 2rem;
}
} }
.email_last_step_block { .email_last_step_block {
padding: 10px; padding: 10px;
@@ -1028,6 +1033,10 @@ export default defineComponent({
font-size: 2.2rem; font-size: 2.2rem;
font-weight: bold; font-weight: bold;
color: #030303; color: #030303;
@media (max-width: 767px) {
font-size: 1.2rem;
margin-left: .5rem;
}
} }
.email_last_step_block_icon { .email_last_step_block_icon {
cursor: pointer; cursor: pointer;
@@ -1229,6 +1238,9 @@ export default defineComponent({
font-weight: bold; font-weight: bold;
color: #000; color: #000;
cursor: pointer; cursor: pointer;
@media (max-width: 767px) {
font-size: 1rem;
}
} }
.email_last_step_des { .email_last_step_des {
@@ -1237,16 +1249,25 @@ export default defineComponent({
justify-content: space-between; justify-content: space-between;
margin-top: 4rem; margin-top: 4rem;
margin-bottom: 2rem; margin-bottom: 2rem;
@media (max-width: 767px) {
margin-top: 2rem;
margin-bottom: 1rem;
}
.sent_email_content { .sent_email_content {
font-size: 1.8rem; font-size: 1.8rem;
font-weight: bold; font-weight: bold;
color: #a5b0c2; color: #a5b0c2;
@media (max-width: 767px) {
font-size: 1.2rem;
}
} }
.email_tip_content { .email_tip_content {
font-size: 1.4rem; font-size: 1.4rem;
color: #030303; color: #030303;
@media (max-width: 767px) {
font-size: 1.2rem;
}
} }
} }
} }

View File

@@ -165,9 +165,22 @@ export default defineComponent({
time = setTimeout(()=>{ time = setTimeout(()=>{
let canvasData = JSON.parse(canvasJSON) let canvasData = JSON.parse(canvasJSON)
if(!canvasData)return if(!canvasData)return
canvasData.canvas.objects.forEach((objectsItem:any) => { function deepProcessObjects(data:any, callback:any) {
if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src) if (!Array.isArray(data)) return data;
return data.map(item => {
callback(item)
const processedItem = {...item};
if (processedItem.objects &&
Array.isArray(processedItem.objects) &&
processedItem.objects.length > 0) {
processedItem.objects = deepProcessObjects(processedItem.objects, callback);
}
return processedItem;
}); });
}
canvasData.canvas.objects = deepProcessObjects(canvasData.canvas.objects,(item:any)=>{
if(item.type == 'image')item.minioUrl = getMinioUrl(item.src)
})
let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" }); let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" });
let formData = new FormData(); let formData = new FormData();
formData.append("file", blob, "data.json"); formData.append("file", blob, "data.json");

View File

@@ -2,18 +2,17 @@ import axios from 'axios'
// import qs from 'qs' // import qs from 'qs'
// import message from '@/components/public/message/src' // import message from '@/components/public/message/src'
import router from '@/router/index' import router from '@/router/index'
import {getCookie,clonAllCookie} from '@/tool/cookie' import { getCookie, clonAllCookie } from '@/tool/cookie'
// import cookie from '@/tools/cookie.js' // import cookie from '@/tools/cookie.js'
axios.defaults.timeout = 60000; //响应时间 axios.defaults.timeout = 60000 //响应时间
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; //配置请求头 // axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; //配置请求头
axios.defaults.headers.post["Content-Type"] = "application/json"; axios.defaults.headers.post['Content-Type'] = 'application/json'
axios.defaults.headers.post['lang'] = 'en' //配置语言请求头
axios.defaults.headers.post['lang'] = 'en'; //配置语言请求头 axios.defaults.withCredentials = true //跨域携带cookie
axios.defaults.withCredentials = true; //跨域携带cookie import { message } from 'ant-design-vue'
import { message } from 'ant-design-vue'; import store from '@/store'
import store from '@/store';
// if(import.meta.env.VITE_USER_NODE_ENV == "development"){ // if(import.meta.env.VITE_USER_NODE_ENV == "development"){
// axios.defaults.baseURL = ""; //配置接口地址 // axios.defaults.baseURL = ""; //配置接口地址
// }else{ // }else{
@@ -25,110 +24,128 @@ import store from '@/store';
// }else{ // }else{
// httpIp = '' // httpIp = ''
// } // }
let httpIp = import.meta.env.VITE_USER_NODE_ENV == 'development' ? "" : ""; let httpIp = import.meta.env.VITE_USER_NODE_ENV == 'development' ? '' : ''
// let httpIp = import.meta.env.VITE_USER_NODE_ENV == 'development' ? "https://192.168.1.8:10086" : ""; // let httpIp = import.meta.env.VITE_USER_NODE_ENV == 'development' ? "https://192.168.1.8:10086" : "";
axios.defaults.baseURL = httpIp; //配置接口地址 axios.defaults.baseURL = httpIp //配置接口地址
// console.log(axios.defaults.baseURL); // console.log(axios.defaults.baseURL);
axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_URL; //配置接口地址 axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_URL //配置接口地址
console.log(import.meta.env.VITE_APP_BASE_URL) console.log(import.meta.env.VITE_APP_BASE_URL)
// 创建取消令牌 // 创建取消令牌
const CancelToken = axios.CancelToken; const CancelToken = axios.CancelToken
const source = CancelToken.source(); const source = CancelToken.source()
// console.log(import.meta.env.VITE_APP_BASE_URL); // console.log(import.meta.env.VITE_APP_BASE_URL);
let isLoginTime = false let isLoginTime = false
//POST传参序列化(添加请求拦截器) //POST传参序列化(添加请求拦截器)
axios.interceptors.request.use((config) => { axios.interceptors.request.use(
config => {
//在发送请求之前做某件事 //在发送请求之前做某件事
// config.cancelToken = source.token // config.cancelToken = source.token
if(config.method === 'post' || config.method === 'put' || config.method === 'delete'){ if (
config.method === 'post' ||
config.method === 'put' ||
config.method === 'delete'
) {
// config.data = qs.stringify(config.data); // config.data = qs.stringify(config.data);
// config.data = JSON.stringify(config.data); // config.data = JSON.stringify(config.data);
} }
// config.headers.Authorization = 'Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIyIiwic3ViIjoie1wiaWRcIjoyLFwidXNlcm5hbWVcIjpcImxpcnNcIn0iLCJpYXQiOjE2NjU3NDEwODcsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2NzQzODEwODd9.ShM9R_NNFD7oo1OvxrEgg7PFeWinOuAKkuInUCMQupp66s64Hhv8tN0Wwr83nIN4rHPqtn95wmd4msWcvaFYJA'; // config.headers.Authorization = 'Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIyIiwic3ViIjoie1wiaWRcIjoyLFwidXNlcm5hbWVcIjpcImxpcnNcIn0iLCJpYXQiOjE2NjU3NDEwODcsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2NzQzODEwODd9.ShM9R_NNFD7oo1OvxrEgg7PFeWinOuAKkuInUCMQupp66s64Hhv8tN0Wwr83nIN4rHPqtn95wmd4msWcvaFYJA';
config.headers.Authorization = getCookie('token'); config.headers.Authorization = getCookie('token')
return config; return config
},(error) =>{ },
return Promise.reject(error); error => {
}); return Promise.reject(error)
const binaryToUrl = (binary,type = 'application/json',res)=>{ }
let blob = new Blob([binary], {'content-type':type}); )
let url = URL.createObjectURL(blob); const binaryToUrl = (binary, type = 'application/json', res) => {
let blob = new Blob([binary], { 'content-type': type })
let url = URL.createObjectURL(blob)
return url return url
} }
//返回状态判断(添加响应拦截器) //返回状态判断(添加响应拦截器)
axios.interceptors.response.use((res) =>{ axios.interceptors.response.use(
res => {
// 允许透传完整响应:请求时传 config.fullData = true
// if(res.data.data == null){ // if(res.data.data == null){
// message.warning(res.data.errMsg) // message.warning(res.data.errMsg)
// return Promise.reject(res.data); // return Promise.reject(res.data);
// }else // }else
if(res?.config?.env?.binary){ if (res?.config?.env?.binary) {
let url = binaryToUrl(res.data,res.config.env.binaryType,res) let url = binaryToUrl(res.data, res.config.env.binaryType, res)
return Promise.resolve({url,data:res.data}) return Promise.resolve({ url, data: res.data })
} }
if (res?.data) { if (res?.data) {
if (res?.data?.errCode === 0) { if (res?.data?.errCode === 0) {
// message.error(res?.data?.errMsg) // message.error(res?.data?.errMsg)
return Promise.resolve(res?.data?.data); if (res?.config?.fullData) {
} else if(res?.data?.errCode === 1){ return Promise.resolve(res.data)
message.warning(res?.data?.errMsg) }
return Promise.reject(res?.data); return Promise.resolve(res?.data?.data)
} else if(res?.data?.errCode === 2){ } else if (res?.data?.errCode === 1) {
return Promise.reject(res?.data); message.warning(res?.data?.errMsg)
}else if(res?.data?.errCode === -1){ return Promise.reject(res?.data)
message.error(res?.data?.errMsg) } else if (res?.data?.errCode === 2) {
return Promise.reject(res?.data); return Promise.reject(res?.data)
} else if (res?.data?.errCode === -1) {
message.error(res?.data?.errMsg)
return Promise.reject(res?.data)
} }
} else { } else {
if (res?.data?.errCode === 0) { if (res?.data?.errCode === 0) {
message.warning(res?.data?.errMsg) message.warning(res?.data?.errMsg)
return Promise.reject(res?.data); return Promise.reject(res?.data)
} else if(res?.data?.errCode === 1){ } else if (res?.data?.errCode === 1) {
message.warning(res?.data?.errMsg) message.warning(res?.data?.errMsg)
return Promise.reject(res?.data); return Promise.reject(res?.data)
} else if(res?.data?.errCode === 2){ } else if (res?.data?.errCode === 2) {
return Promise.reject(res?.data); return Promise.reject(res?.data)
}else if(res?.data?.errCode === -1){ } else if (res?.data?.errCode === -1) {
message.error(res?.data?.errMsg) message.error(res?.data?.errMsg)
return Promise.reject(res?.data); return Promise.reject(res?.data)
} }
} }
}, function(error) { },
if(error?.response?.status === 401 && router.currentRoute._value.name != 'setIdentification'){//如果是记录浏览器页面就不跳转login function (error) {
if (
error?.response?.status === 401 &&
router.currentRoute._value.name != 'setIdentification'
) {
//如果是记录浏览器页面就不跳转login
clonAllCookie() clonAllCookie()
if(!isLoginTime){ if (!isLoginTime) {
isLoginTime = true isLoginTime = true
let isSystemUserRouteList = ['/Square']//如果是这两个页面就无需跳转未登录页 let isSystemUserRouteList = ['/Square'] //如果是这两个页面就无需跳转未登录页
let sSystemUser = false let sSystemUser = false
for (let index = 0; index < isSystemUserRouteList.length; index++) { for (let index = 0; index < isSystemUserRouteList.length; index++) {
if(router.currentRoute.value.path.indexOf(isSystemUserRouteList[index]) > -1){ if (
router.currentRoute.value.path.indexOf(
isSystemUserRouteList[index]
) > -1
) {
sSystemUser = true sSystemUser = true
break break
} }
} }
if(!sSystemUser){ if (!sSystemUser) {
router.replace('/') router.replace('/')
} }
message.warning('Please login and try again~') message.warning('Please login and try again~')
store.commit('createDetail') store.commit('createDetail')
store.commit('createProbject') store.commit('createProbject')
store.commit('createProjectPath') store.commit('createProjectPath')
setTimeout(()=>[ setTimeout(() => [(isLoginTime = false)], 2000)
isLoginTime = false
],2000)
} }
// source.cancel('取消后续接口调用'); // source.cancel('取消后续接口调用');
return Promise.reject() return Promise.reject()
} }
let data_new = error?.response?.data let data_new = error?.response?.data
// message.error(data_new?.errMsg || 'Error: server exception') // message.error(data_new?.errMsg || 'Error: server exception')
return Promise.reject(data_new); return Promise.reject(data_new)
}); }
)
export const Https = { export const Https = {
httpUrls: { httpUrls: {
interfaceUrl: '', interfaceUrl: '',
@@ -447,9 +464,16 @@ export const Https = {
segAnything: `/api/python/segAnything`, //分割Anything segAnything: `/api/python/segAnything`, //分割Anything
// award页面 // award页面
uploadPDF: '/api/global-award/uploads/pdf', // 上传pdf checkEmail: '/api/global-award/checkEmail', // 检查邮箱是否存在
uploadVideo: '/api/global-award/uploads/video', // 上传video checkOTP: '/api/global-award/checkCode', // 检查验证码是否正确
initPdfUpload: '/api/global-award/uploads/pdf/init', // 初始化pdf上传
initVideoUpload: '/api/global-award/uploads/video/init', // 初始化video上传
uploadPDF: '/api/global-award/uploads/pdf/chunk', // 上传pdf
uploadVideo: '/api/global-award/uploads/video/chunk', // 上传video
uploadPDFComplete: '/api/global-award/uploads/pdf/complete', // 上传pdf完成
uploadVideoComplete: '/api/global-award/uploads/video/complete', // 上传video完成
submitForm: '/api/global-award/contestants/save', // 提交表单
getContestantByID: '/api/global-award/contestants/' // 获取表单
}, },
axiosGet(url, config) { axiosGet(url, config) {

View File

@@ -5,12 +5,19 @@
BLOOM YOUR CREATIVITY AiDA GLOBAL FASHION AWARD 2026 BLOOM YOUR CREATIVITY AiDA GLOBAL FASHION AWARD 2026
</div> </div>
<div class="title poppins-medium">Application Form</div> <div class="title poppins-medium">Application Form</div>
<div class="form-header"> <div
class="form-header"
v-if="!isCompleted"
>
<div class="form-title poppins-bold">Email Verification</div> <div class="form-title poppins-bold">Email Verification</div>
<div class="desc">AiDA Users Only</div> <div class="desc">AiDA Users Only</div>
</div> </div>
</div> </div>
<div class="form-container"> <Success v-if="isCompleted" />
<div
class="form-container"
v-if="!isCompleted"
>
<div class="form-content"> <div class="form-content">
<a-form <a-form
name="form" name="form"
@@ -66,7 +73,22 @@
:label="item.label" :label="item.label"
:name="item.key" :name="item.key"
> >
<a-input v-model:value="form[item.key]" /> <a-input
v-if="item.type === 'input'"
v-model:value="form[item.key]"
/>
<a-select
v-if="item.type === 'select'"
v-model:value="form[item.key]"
:options="genderOptions"
>
<template #suffixIcon>
<img
class="arrow-down-icon"
src="@/assets/images/award/arrow_down.svg"
/>
</template>
</a-select>
</a-form-item> </a-form-item>
</template> </template>
</div> </div>
@@ -84,13 +106,13 @@
</a-form-item> </a-form-item>
<a-form-item <a-form-item
class="full-row design-desc" class="full-row design-desc"
name="description" name="designDescription"
label="Design description" label="Design description"
required required
> >
<a-textarea <a-textarea
class="textarea" class="textarea"
v-model:value="form.description" v-model:value="form.designDescription"
placeholder="Briefly describe your design concept, inspiration, and creative direction..." placeholder="Briefly describe your design concept, inspiration, and creative direction..."
/> />
</a-form-item> </a-form-item>
@@ -307,16 +329,22 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onUnmounted } from 'vue' import { ref, onUnmounted, onMounted } from 'vue'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
import type { Rule } from 'ant-design-vue/es/form' import type { Rule } from 'ant-design-vue/es/form'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { Https } from '@/tool/https'
import { useRoute } from 'vue-router'
import type { UploadChangeParam } from 'ant-design-vue' import type { UploadChangeParam } from 'ant-design-vue'
import VerifycationCodeInput from './components/VerificationCodeInput.vue' import VerifycationCodeInput from './components/VerificationCodeInput.vue'
import { Https } from '@/tool/https'
import UploadStatus from './components/UploadStatus.vue' import UploadStatus from './components/UploadStatus.vue'
import Success from './components/Success.vue'
const hasValidEmail = ref(true) const route = useRoute()
const isCompleted = ref(false)
const hasValidEmail = ref(false)
const formRef = ref(null) const formRef = ref(null)
const form = ref({ const form = ref({
email: '', email: '',
@@ -325,14 +353,15 @@
gender: '', gender: '',
occupation: '', occupation: '',
age: '', age: '',
counterOrRegion: '', countryRegionCity: '',
phone: '', phoneNumber: '',
portfoilo: '', portfolioUrl: '',
// code: '', // code: '',
designTitle: '', designTitle: '',
description: '', designDescription: '',
pdfPath: null, pdfPath: 'test.pdf',
videoPath: null videoPath: 'test.video',
secureToken: null
}) })
// 验证码输入组件引用 // 验证码输入组件引用
@@ -393,6 +422,20 @@
] ]
} }
const genderOptions = [
{
label: 'Male',
value: 'Male'
},
{
label: 'Female',
value: 'Female'
},
{
label: 'Other',
value: 'Other'
}
]
const formKeys = ref([ const formKeys = ref([
{ {
label: 'First Name', label: 'First Name',
@@ -428,20 +471,20 @@
label: 'Country/Region and City', label: 'Country/Region and City',
required: true, required: true,
type: 'input', type: 'input',
key: 'counterOrRegion' key: 'countryRegionCity'
}, },
{ {
label: 'Phone Number', label: 'Phone Number',
required: true, required: true,
type: 'input', type: 'input',
key: 'phone' key: 'phoneNumber'
}, },
{ {
label: 'Portfoilo Website/Instagram(Optional)', label: 'Portfoilo Website/Instagram(Optional)',
required: false, required: false,
type: 'input', type: 'input',
key: 'portfoilo' key: 'portfolioUrl'
} }
]) ])
@@ -488,11 +531,13 @@
try { try {
await formRef.value.validateFields(['email']) await formRef.value.validateFields(['email'])
// TODO: 发送验证码的逻辑 // TODO: 发送验证码的逻辑
message.success('Verification code sent successfully!') await Https.axiosGet(Https.httpUrls.checkEmail, {
params: {
email: form.value.email
}
})
// 开始倒计时
startCountdown() startCountdown()
showModal.value = true showModal.value = true
} catch (error) {} } catch (error) {}
}, 300) }, 300)
@@ -506,6 +551,28 @@
const handleCloseModal = () => { const handleCloseModal = () => {
showModal.value = false showModal.value = false
} }
const handleVerifyCode = () => {
console.log(verifyCode.value)
if (verifyCode.value.length !== 6) {
message.error('Please enter the complete 6-digit verification code')
return
}
Https.axiosGet(Https.httpUrls.checkOTP, {
params: {
email: form.value.email,
code: verifyCode.value
},
fullData: true
}).then(res => {
console.log('coderes', res)
form.value.secureToken = res.data.secureToken
message.success('Verification successful!')
showModal.value = false
})
}
const handleSubmitForm = () => { const handleSubmitForm = () => {
const validCondition = conditionsList.value.filter( const validCondition = conditionsList.value.filter(
@@ -515,26 +582,21 @@
message.error('Please check the terms and conditions') message.error('Please check the terms and conditions')
return return
} }
formRef.value.validate().then(res => { formRef.value
.validate()
.then(res => {
console.log(res) console.log(res)
}).catch(err => { Https.axiosPost(Https.httpUrls.submitForm, form.value).then(res => {
console.log('res', res)
isCompleted.value = true
})
})
.catch(err => {
console.log(err) console.log(err)
message.error('Please fill in all the required fields') message.error('Please fill in all the required fields')
}) })
} }
const handleVerifyCode = () => {
if (verifyCode.value.length !== 6) {
message.error('Please enter the complete 6-digit verification code')
return
}
message.success('Verification successful!')
// 关闭模态框
showModal.value = false
}
const pdfList = ref([]) const pdfList = ref([])
const videoList = ref([]) const videoList = ref([])
const isUploadingPdf = ref(false) const isUploadingPdf = ref(false)
@@ -544,6 +606,14 @@
const pdfUploadStatus = ref<'idle' | 'uploading' | 'success' | 'error'>('idle') const pdfUploadStatus = ref<'idle' | 'uploading' | 'success' | 'error'>('idle')
const videoUploadStatus = ref<'idle' | 'uploading' | 'success' | 'error'>('idle') const videoUploadStatus = ref<'idle' | 'uploading' | 'success' | 'error'>('idle')
const chunkUploadState: Record<
FileType,
{ uploadId: string | null; chunkSize: number; uploadedChunks: Set<number> }
> = {
pdf: { uploadId: null, chunkSize: 0, uploadedChunks: new Set() },
video: { uploadId: null, chunkSize: 0, uploadedChunks: new Set() }
}
// 统一的文件上传前验证 // 统一的文件上传前验证
const beforeUploadFile = (type: FileType, file: File) => { const beforeUploadFile = (type: FileType, file: File) => {
if (!hasValidEmail.value) { if (!hasValidEmail.value) {
@@ -626,6 +696,88 @@
return beforeUploadFile('video', file) return beforeUploadFile('video', file)
} }
const initializeChunkUpload = async (type: FileType, file: File) => {
const endpoint =
type === 'pdf' ? Https.httpUrls.initPdfUpload : Https.httpUrls.initVideoUpload
const data = await Https.axiosPost(endpoint, {
fileName: file.name,
fileSize: file.size,
fileType: file.type,
email: form.value.email,
secureToken: form.value.secureToken
})
return {
uploadId: data?.uploadId as string,
chunkSize: data?.chunkSize as number
}
}
const createFileChunks = (file: File, chunkSize: number) => {
const chunks: Blob[] = []
const totalChunks = Math.ceil(file.size / chunkSize)
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize
const end = Math.min(start + chunkSize, file.size)
const chunk = file.slice(start, end)
chunks.push(chunk)
}
return chunks
}
const updateUploadProgress = (
type: FileType,
uploadedCount: number,
total: number
) => {
const percent = Math.round((uploadedCount / total) * 100)
if (type === 'pdf') {
uploadProgressPdf.value = percent
} else {
uploadProgressVideo.value = percent
}
}
const uploadChunk = async (
type: FileType,
chunk: Blob,
chunkIndex: number,
totalChunks: number
) => {
const endpoint =
type === 'pdf' ? Https.httpUrls.uploadPDF : Https.httpUrls.uploadVideo
const formData = new FormData()
formData.append('chunk', chunk)
formData.append('uploadId', chunkUploadState[type].uploadId || '')
formData.append('chunkIndex', String(chunkIndex))
formData.append('totalChunks', String(totalChunks))
formData.append('secureToken', form.value.secureToken)
await Https.axiosPost(endpoint, formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
chunkUploadState[type].uploadedChunks.add(chunkIndex)
}
const completeChunkUpload = async (type: FileType, file: File) => {
const endpoint =
type === 'pdf'
? Https.httpUrls.uploadPDFComplete
: Https.httpUrls.uploadVideoComplete
await Https.axiosPost(endpoint, {
uploadId: chunkUploadState[type].uploadId,
fileName: file.name,
totalSize: file.size,
secureToken: form.value.secureToken
})
}
type FileType = 'pdf' | 'video' type FileType = 'pdf' | 'video'
const handleFileChange = (info: UploadChangeParam, type: FileType) => { const handleFileChange = (info: UploadChangeParam, type: FileType) => {
const status = info.file.status const status = info.file.status
@@ -656,65 +808,68 @@
} }
// 统一的上传处理函数 // 统一的上传处理函数
const handleUploadFile = (option: any, type: FileType) => { const handleUploadFile = async (option: any, type: FileType) => {
console.log(option, type) const file = option.file as File
const file = option.file if (!form.value.email) {
message.error('Please input the email address first')
option.onError?.(new Error('Email required'))
return
}
// 根据类型设置上传状态和进度
if (type === 'pdf') { if (type === 'pdf') {
isUploadingPdf.value = true isUploadingPdf.value = true
uploadProgressPdf.value = 0 uploadProgressPdf.value = 0
pdfUploadStatus.value = 'uploading' pdfUploadStatus.value = 'uploading'
} else if (type === 'video') { } else {
isUploadingVideo.value = true isUploadingVideo.value = true
uploadProgressVideo.value = 0 uploadProgressVideo.value = 0
videoUploadStatus.value = 'uploading' videoUploadStatus.value = 'uploading'
} }
const params = new FormData() try {
params.append('file', file) const { uploadId, chunkSize } = await initializeChunkUpload(type, file)
params.append('email', form.value.email) chunkUploadState[type].uploadId = uploadId
chunkUploadState[type].chunkSize = chunkSize
chunkUploadState[type].uploadedChunks = new Set()
// 根据类型选择不同的上传接口 const chunks = createFileChunks(file, chunkSize)
const uploadUrl = Https.httpUrls.uploadAvatar for (let i = 0; i < chunks.length; i++) {
// const uploadUrl = await uploadChunk(type, chunks[i], i, chunks.length)
// type === 'pdf' ? Https.httpUrls.uploadPDF : Https.httpUrls.uploadVideo updateUploadProgress(type, i + 1, chunks.length)
}
const res = await completeChunkUpload(type, file)
console.log('上传完成-----', res)
Https.axiosPost(uploadUrl, params, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: progressEvent => {
if (progressEvent.total) {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
)
if (type === 'pdf') { if (type === 'pdf') {
uploadProgressPdf.value = percentCompleted pdfUploadStatus.value = 'success'
} else if (type === 'video') { uploadProgressPdf.value = 100
uploadProgressVideo.value = percentCompleted isUploadingPdf.value = false
form.value.pdfPath = uploadId
} else {
videoUploadStatus.value = 'success'
uploadProgressVideo.value = 100
isUploadingVideo.value = false
form.value.videoPath = uploadId
} }
}
} option.onSuccess?.({ uploadId }, option.file)
}) } catch (error: any) {
.then(res => {
console.log(res)
if (type === 'pdf') pdfUploadStatus.value = 'success'
if (type === 'video') videoUploadStatus.value = 'success'
option.onSuccess(res, option.file)
})
.catch(error => {
console.error('Upload error:', error) console.error('Upload error:', error)
option.onError(error) message.error(error?.message || 'Upload failed')
option.onError?.(error)
if (type === 'pdf') { if (type === 'pdf') {
isUploadingPdf.value = false isUploadingPdf.value = false
uploadProgressPdf.value = 0 uploadProgressPdf.value = 0
pdfUploadStatus.value = 'error' pdfUploadStatus.value = 'error'
} else if (type === 'video') { } else {
isUploadingVideo.value = false isUploadingVideo.value = false
uploadProgressVideo.value = 0 uploadProgressVideo.value = 0
videoUploadStatus.value = 'error' videoUploadStatus.value = 'error'
} }
}) }
} }
// PDF上传处理 // PDF上传处理
@@ -753,7 +908,18 @@
} }
]) ])
// 组件卸载时清理定时器 const handleEchoForm = () => {
Https.axiosGet(Https.httpUrls.getContestantByID + route.query.id).then(res => {
console.log('获取到的值---', res)
Object.assign(form.value, res)
})
}
onMounted(() => {
if (route.query.id) {
handleEchoForm()
}
})
onUnmounted(() => { onUnmounted(() => {
clearCountdown() clearCountdown()
}) })
@@ -773,10 +939,18 @@
.full-row { .full-row {
width: 100%; width: 100%;
} }
.arrow-down-icon {
width: 2rem;
height: 1rem;
}
.apply-container {
min-height: calc(100% -18rem);
background-color: #f5f5f5;
}
.banner { .banner {
height: 54.8rem; height: 54.8rem;
background: url('@/assets/images/award/apply_bg.png') no-repeat; background: url('@/assets/images/award/form_bg.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
text-align: center; text-align: center;
padding: 12rem 21.4rem 0; padding: 12rem 21.4rem 0;
@@ -888,7 +1062,8 @@
} }
} }
:deep(.ant-input) { :deep(.ant-input),
:deep(.ant-select-selector) {
border: 0.2rem solid #d5d5d5; border: 0.2rem solid #d5d5d5;
height: 6rem; height: 6rem;
border-radius: 0.8rem; border-radius: 0.8rem;
@@ -899,6 +1074,20 @@
&.textarea { &.textarea {
height: 20rem; height: 20rem;
} }
.ant-select-selection-search {
height: 100%;
}
.ant-select-selection-item {
line-height: 6rem;
}
}
:deep(.ant-select-arrow) {
height: 4rem;
width: 6.2rem;
justify-content: center;
display: flex;
align-items: center;
border-left: 0.1rem solid #d5d5d5;
} }
} }
} }
@@ -1092,7 +1281,6 @@
:deep(.ant-checkbox-wrapper) { :deep(.ant-checkbox-wrapper) {
.ant-checkbox-inner { .ant-checkbox-inner {
//修改边框的颜色
width: 2rem; width: 2rem;
height: 2rem; height: 2rem;
border: 0.2rem solid #585858 !important; border: 0.2rem solid #585858 !important;
@@ -1100,17 +1288,11 @@
} }
.ant-checkbox-checked .ant-checkbox-inner { .ant-checkbox-checked .ant-checkbox-inner {
//修改选中框的背景颜色
background-color: #fff !important; background-color: #fff !important;
/* 将背景颜色修改为白色 */
//修改边框颜色
border-color: #585858 !important; border-color: #585858 !important;
/* 将边框颜色修改为黑色 */
} }
.ant-checkbox-checked .ant-checkbox-inner::after { .ant-checkbox-checked .ant-checkbox-inner::after {
//antd的checkbox组件的选中框里面的透明的钩子是通过设置底部边框和右边框的颜色再旋转得到的钩子
// 所以设置底部边框和右边框的样式就可以修改钩子的样式
border-bottom: 0.2rem solid #585858; border-bottom: 0.2rem solid #585858;
border-right: 0.2rem solid #585858; border-right: 0.2rem solid #585858;
width: 0.65rem; width: 0.65rem;
@@ -1202,6 +1384,7 @@
font-family: 'ArialBold'; font-family: 'ArialBold';
font-weight: 700; font-weight: 700;
font-size: 1.6rem; font-size: 1.6rem;
cursor: pointer;
} }
.cutdown { .cutdown {

View File

@@ -0,0 +1,51 @@
<template>
<div class="success-container flex flex-col align-center">
<img
src="@/assets/images/award/successful.png"
alt=""
class="icon-img"
/>
<div class="title">Submission Successful</div>
<div class="desc">
<div>
Please review your submitted information in the AiDA in-platform message.
</div>
<div>
You may edit it if needed. Competition updates and results will be sent
via email.
</div>
</div>
</div>
</template>
<script setup lang="ts"></script>
<style lang="less" scoped>
.success-container {
margin: 0 21.5rem;
padding: 10.6rem 27.3rem 0;
height: 50rem;
position: relative;
top: -16.8rem;
background-color: #fff;
border-radius: 0.8rem;
.icon-img {
width: 12rem;
height: 12rem;
}
.title {
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 3rem;
color: #232323;
text-align: center;
margin: 2rem 0 4rem;
}
.desc {
color: #585858;
font-family: Arial;
font-weight: 400;
font-size: 2.4rem;
text-align: center;
}
}
</style>

View File

@@ -7,8 +7,11 @@
class="logo" class="logo"
/> />
</div> </div>
<div class="header-right flex align-center"> <div
<div class="text">Submit your Application</div> class="header-right flex align-center"
@click="handleBtnClick"
>
<div class="text">{{ btnText }}</div>
<img <img
src="@/assets/images/award/arrow.png" src="@/assets/images/award/arrow.png"
alt="" alt=""
@@ -89,12 +92,51 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const showQRcode = ref(false) const showQRcode = ref(false)
const handleCloseQRcode = () => { const handleCloseQRcode = () => {
showQRcode.value = false showQRcode.value = false
} }
type BtnType = 'index' | 'form'
const btnType = ref<BtnType>('index')
const btnText = computed(() => {
if (btnType.value === 'index') {
return 'Submit your Application'
}
if (btnType.value === 'form') {
return 'Back to Introduction'
}
})
watch(
() => route.path,
val => {
console.log('val', val)
if (val.includes('apply')) {
btnType.value = 'form'
} else {
btnType.value = 'index'
}
console.log('btnType', btnType.value)
},
{
immediate: true
}
)
const handleBtnClick = () => {
if (btnType.value === 'index') {
router.push('/award/apply')
} else {
router.push('/award/index')
}
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@@ -123,6 +165,7 @@
} }
.header-right { .header-right {
column-gap: 1rem; column-gap: 1rem;
cursor: pointer;
.text { .text {
font-size: 1.6rem; font-size: 1.6rem;
color: #fff; color: #fff;

View File

@@ -1814,6 +1814,8 @@ export default defineComponent({
} }
}); });
}else{
this.generateList[selectCodeStr] = this.generateList[selectCodeStr].filter((item: any) => item.imgUrl)
} }
}); });
}, },
@@ -2420,6 +2422,7 @@ export default defineComponent({
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: absolute;
} }
&:hover .img_item_hover{ &:hover .img_item_hover{
// display: block; // display: block;

View File

@@ -8,15 +8,15 @@
<!-- <div class="upgrade-content-text">System upgrading</div> --> <!-- <div class="upgrade-content-text">System upgrading</div> -->
<div class="upgrade-content-text">System maintenance</div> <div class="upgrade-content-text">System maintenance</div>
<!-- 没有截至时间 --> <!-- 没有截至时间 -->
<div class="upgrade-content-textab">The AiDA system cannot be accessed temporarily due to system server maintenance. We apologize for any inconvenience this may cause and thank you for your understanding.</div> <!-- <div class="upgrade-content-textab">The AiDA system cannot be accessed temporarily due to system server maintenance. We apologize for any inconvenience this may cause and thank you for your understanding.</div> -->
<!-- <div class="upgrade-content-textab">Due to the system server upgrade, we will start the upgrade from 9:30 am Hong Kong time on the weekend of October 20th until October 21st. During this time,<br> the AiDA system will be temporarily inaccessible. We apologize for any inconvenience this may cause and thank you for your understanding.</div> --> <!-- <div class="upgrade-content-textab">Due to the system server upgrade, we will start the upgrade from 9:30 am Hong Kong time on the weekend of October 20th until October 21st. During this time,<br> the AiDA system will be temporarily inaccessible. We apologize for any inconvenience this may cause and thank you for your understanding.</div> -->
<!-- 有截至时间 --> <!-- 有截至时间 -->
<!-- <div class="upgrade-content-textab">Due to system server upgrades, we will be upgrading from Tuesday, September 2 at 00:00 (HKT) to Wednesday, September 3 at 00:00. During this period, the AiDA system will be temporarily inaccessible. <br>We sincerely apologize for the inconvenience caused and thank you for your understanding</div> --> <div class="upgrade-content-textab">Due to system server upgrades, maintenance will be carried out from 21:00 to 22:00 on December 19.<br>The AiDA system will be temporarily unavailable during this period. We sincerely apologize for any inconvenience caused and thank you for your understanding.</div>
<br> <br>
<br> <br>
<br> <br>
<div class="upgrade-content-textab">由于系统服务器维护AiDA系统暂时无法访问对于由此造成的任何不便我们深表歉意并感谢您的理解</div> <!-- <div class="upgrade-content-textab">由于系统服务器维护AiDA系统暂时无法访问对于由此造成的任何不便我们深表歉意并感谢您的理解</div> -->
<!-- <div class="upgrade-content-textab">由于系统服务器升级我们将于9月2日星期二凌晨00:00香港时间至9月3日星期三凌晨00:00进行升级<br>在此期间AiDA系统将暂时无法访问给您带来的不便我们深表歉意并感谢您的理解</div> --> <div class="upgrade-content-textab">由于系统服务器升级我们将于12月19日21:00 至12月19日22:00进行升级<br>在此期间AiDA系统将暂时无法访问给您带来的不便我们深表歉意并感谢您的理解</div>
</div> </div>
</div> </div>
</template> </template>