Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite
This commit is contained in:
3
src/assets/images/award/arrow_down.svg
Normal file
3
src/assets/images/award/arrow_down.svg
Normal 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 |
BIN
src/assets/images/award/form_bg.png
Normal file
BIN
src/assets/images/award/form_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 930 KiB |
@@ -16,29 +16,6 @@
|
||||
</template>
|
||||
</a-range-picker>
|
||||
</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">
|
||||
<span>{{ $t('admin.UserName') }}:</span>
|
||||
<a-select
|
||||
@@ -53,19 +30,6 @@
|
||||
@keydown.enter="gettrialList"
|
||||
></a-select>
|
||||
</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 class="admin_search">
|
||||
<div class="admin_search_item" @click="searchHistoryList">
|
||||
@@ -116,6 +80,24 @@
|
||||
</div>
|
||||
</div>
|
||||
<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
|
||||
@resizeColumn="handleResizeColumn"
|
||||
:loading="tableLoading"
|
||||
@@ -147,12 +129,6 @@
|
||||
<div class="operate_item" @click="deleteAagree(record)">
|
||||
{{ $t('admin.Delete') }}
|
||||
</div>
|
||||
<!-- <div
|
||||
class="operate_item"
|
||||
@click="deleteGroup(record, index)"
|
||||
>
|
||||
Delete
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
@@ -160,31 +136,58 @@
|
||||
<allUserPoerationsVue
|
||||
ref="allUserPoerationsVue"
|
||||
@searchHistoryList="searchHistoryList"
|
||||
:plan-options="planFilterOptions"
|
||||
></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>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
createVNode,
|
||||
computed,
|
||||
reactive,
|
||||
toRefs,
|
||||
onMounted
|
||||
} from 'vue'
|
||||
import { formatTime } from '@/tool/util'
|
||||
import { useStore } from 'vuex'
|
||||
import { Https } from '@/tool/https'
|
||||
import { Modal, message } from 'ant-design-vue'
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
|
||||
import allUserPoerationsVue from './addAllUser.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import SelectUser from '@/component/common/SelectUser.vue'
|
||||
export default defineComponent({
|
||||
components: { allUserPoerationsVue },
|
||||
unref,
|
||||
watch
|
||||
} from 'vue'
|
||||
import { formatTime } from '@/tool/util'
|
||||
import { useStore } from 'vuex'
|
||||
import { Https } from '@/tool/https'
|
||||
import { Modal, message, Input } from 'ant-design-vue'
|
||||
import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
|
||||
import allUserPoerationsVue from './addAllUser.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
export default defineComponent({
|
||||
components: { allUserPoerationsVue, MoreOutlined },
|
||||
setup() {
|
||||
const store: any = useStore()
|
||||
const currentOrganizationId = computed(
|
||||
() => store.state.UserHabit.userDetail.organizationId
|
||||
)
|
||||
const selectedRowKeys = ref([]) as any
|
||||
const onSelectChange = (changableRowKeys: string[]) => {
|
||||
selectedRowKeys.value = changableRowKeys
|
||||
@@ -203,6 +206,7 @@ export default defineComponent({
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
let filterData: any = reactive({
|
||||
@@ -218,10 +222,16 @@ export default defineComponent({
|
||||
systemUser: '',
|
||||
order: '', //'Ascending 升序 Descending 降序'
|
||||
orderBy: '',
|
||||
userName: ''
|
||||
userName: '',
|
||||
subscriptionPlanId: ''
|
||||
})
|
||||
|
||||
let renameData: any = ref({}) //修改名字选中的数据
|
||||
const renamePlanModalVisible = ref(false)
|
||||
const renamePlanForm = reactive({
|
||||
planId: null as number | null,
|
||||
planName: ''
|
||||
})
|
||||
const columns: any = computed(() => {
|
||||
return [
|
||||
{
|
||||
@@ -248,13 +258,6 @@ export default defineComponent({
|
||||
key: 'userName',
|
||||
width: 150,
|
||||
ellipsis: true
|
||||
// customRender: (record: any) => {
|
||||
// let time = formatTime(
|
||||
// record.text / 1000,
|
||||
// "YYYY-MM-DD hh:mm:ss"
|
||||
// );
|
||||
// return time;
|
||||
// },
|
||||
},
|
||||
{
|
||||
title: t('admin.language'),
|
||||
@@ -278,10 +281,6 @@ export default defineComponent({
|
||||
{
|
||||
title: t('admin.Credits'),
|
||||
align: 'center',
|
||||
// width: 150,
|
||||
// minWidth: 100,
|
||||
// maxWidth: 200,
|
||||
// resizable: true,
|
||||
dataIndex: 'credits',
|
||||
key: 'credits',
|
||||
width: 100,
|
||||
@@ -309,7 +308,6 @@ export default defineComponent({
|
||||
width: 120,
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
// slots:{customRender:'action'}
|
||||
Operations: true
|
||||
}
|
||||
]
|
||||
@@ -354,7 +352,8 @@ export default defineComponent({
|
||||
(filterData.order = ''), //'Ascending 升序 Descending 降序'
|
||||
(filterData.orderBy = ''), //'Ascending 升序 Descending 降序'
|
||||
(filterData.systemUser = ''),
|
||||
(filterData.userName = '')
|
||||
(filterData.userName = ''),
|
||||
(filterData.subscriptionPlanId = '')
|
||||
}
|
||||
let setHistoryListData = () => {
|
||||
let startDate: any = filterData.rangePickerValue?.[0]
|
||||
@@ -377,18 +376,17 @@ export default defineComponent({
|
||||
order: filterData.order,
|
||||
orderBy: filterData.orderBy,
|
||||
// userName: filterData.userName,
|
||||
userName: filterData.ids
|
||||
userName: filterData.ids,
|
||||
subscriptionPlanId: filterData.subscriptionPlanId
|
||||
}
|
||||
return data
|
||||
}
|
||||
//获取列表
|
||||
let gettrialList = () => {
|
||||
const gettrialList = () => {
|
||||
filter.tableLoading = true
|
||||
let data = setHistoryListData()
|
||||
Https.axiosPost(Https.httpUrls.subAccountList, data).then((rv: any) => {
|
||||
if (rv) {
|
||||
console.log(rv)
|
||||
// this.dataList = rv
|
||||
filter.dataList = rv.content
|
||||
filterData.total = rv.total
|
||||
filter.tableLoading = false
|
||||
@@ -417,6 +415,66 @@ export default defineComponent({
|
||||
// 使用 option.label 进行搜索
|
||||
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 = () => {
|
||||
allUserPoerationsVue.value.init({ value: 'Add', label: t('admin.add') }, '')
|
||||
}
|
||||
@@ -521,6 +579,33 @@ export default defineComponent({
|
||||
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(() => {
|
||||
let allCountry: any = sessionStorage.getItem('allCountry')
|
||||
if (allCountry) {
|
||||
@@ -545,7 +630,15 @@ export default defineComponent({
|
||||
ExportAccountData,
|
||||
uploadTemplate,
|
||||
deleteList,
|
||||
deleteAagree
|
||||
deleteAagree,
|
||||
planFilterOptions,
|
||||
selectPlanFilter,
|
||||
openPlanRenameModal,
|
||||
renamePlanModalVisible,
|
||||
renamePlanForm,
|
||||
confirmRenamePlan,
|
||||
cancelRenamePlan,
|
||||
fetchSubscribePlanList
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -557,31 +650,42 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let historyTable: any = this.$refs.historyTable
|
||||
this.historyTableHeight = historyTable.clientHeight - 200
|
||||
this.updateTableHeight()
|
||||
window.addEventListener('resize', this.updateTableHeight)
|
||||
},
|
||||
methods: {}
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.admin_page {
|
||||
beforeUnmount() {
|
||||
window.removeEventListener('resize', this.updateTableHeight)
|
||||
},
|
||||
methods: {
|
||||
updateTableHeight() {
|
||||
const historyTable: any = this.$refs.historyTable
|
||||
if (historyTable) {
|
||||
// 为底部分页器预留固定空间,使表格部分高度固定且分页器始终可见
|
||||
this.historyTableHeight = historyTable.clientHeight - 200
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.admin_page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
.admin_table_content {
|
||||
}
|
||||
.admin_table_content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.admin_page .admin_table_search .admin_state {
|
||||
}
|
||||
.admin_page .admin_table_search .admin_state {
|
||||
display: flex;
|
||||
width: 70%;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
.admin_page .admin_table_search .admin_search {
|
||||
}
|
||||
.admin_page .admin_table_search .admin_search {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 30%;
|
||||
@@ -589,12 +693,86 @@ export default defineComponent({
|
||||
height: 4rem;
|
||||
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 {
|
||||
:deep(.ant-table-wrapper) {
|
||||
overflow: hidden ;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -287,12 +287,27 @@ export default defineComponent({
|
||||
const saveCanvas = async (canvasData:any)=>{
|
||||
const index = detailData.designDetail.clothes.findIndex(item => item.id === canvasData.id);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
let canvasJSON = JSON.parse(canvasData.canvasJSON)
|
||||
if(!canvasJSON)return resolve()
|
||||
// canvasData.canvas.objects.forEach((objectsItem:any) => {
|
||||
// if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src)
|
||||
// });
|
||||
let blob = new Blob([JSON.stringify(canvasJSON)], { type: "application/json" });
|
||||
if(!detailDom?.editCanvas)return resolve()
|
||||
let canvasJSON = detailDom?.editCanvas?.getJSON()
|
||||
let canvasData = JSON.parse(canvasJSON)
|
||||
if(!canvasData)return resolve()
|
||||
function deepProcessObjects(data:any, callback:any) {
|
||||
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();
|
||||
formData.append("file", blob, "data.json");
|
||||
formData.append("designItemDetailId", detailData.selectDetail.id);
|
||||
|
||||
@@ -925,6 +925,8 @@ export default defineComponent({
|
||||
},
|
||||
onCancel() {}
|
||||
})
|
||||
}else{
|
||||
this.fileList = this.fileList.filter((item: any) => item.imgUrl)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -854,6 +854,10 @@ export default defineComponent({
|
||||
font-size: 2.2rem;
|
||||
font-weight: bold;
|
||||
color: #030303;
|
||||
@media (max-width: 767px) {
|
||||
font-size: 1.2rem;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
.email_last_step_block_icon {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -161,6 +161,13 @@
|
||||
font-size: 2.4rem;
|
||||
line-height: 8.7rem;
|
||||
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 {
|
||||
margin-right: 0;
|
||||
|
||||
@@ -335,9 +335,22 @@ export default defineComponent({
|
||||
let canvasData = JSON.parse(canvasJSON)
|
||||
|
||||
if(!canvasData)return
|
||||
canvasData.canvas.objects.forEach((objectsItem:any) => {
|
||||
if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src)
|
||||
function deepProcessObjects(data:any, callback:any) {
|
||||
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();
|
||||
formData.append("file", blob, "data.json");
|
||||
|
||||
@@ -206,11 +206,22 @@ export default defineComponent({
|
||||
if(!canvasJSON)return
|
||||
if(!store.state.Workspace.probjects?.id)return
|
||||
let canvasData = JSON.parse(canvasJSON)
|
||||
console.log(canvasData)
|
||||
canvasData.canvas.objects.forEach((objectsItem:any) => {
|
||||
if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src)
|
||||
|
||||
function deepProcessObjects(data:any, callback:any) {
|
||||
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();
|
||||
formData.append("file", blob, "data.json");
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
Forgot password?
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="password_input_block">
|
||||
<div class="password_input_block" v-show="emailStap !== 2">
|
||||
<div v-show="passwordConditionShow" class="conditionShow">
|
||||
<div class="item">
|
||||
<div class="icon">
|
||||
@@ -144,12 +144,13 @@
|
||||
@click="changePasswordType()"
|
||||
></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
|
||||
>
|
||||
<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
|
||||
class="login_form_input"
|
||||
v-show="emailStap !== 2"
|
||||
:placeholder="userI18n[selectUserI18n].inputEmail"
|
||||
v-model="email"
|
||||
@keydown.enter="submitPerLogin()"
|
||||
@@ -917,6 +918,7 @@ export default defineComponent({
|
||||
position: relative;
|
||||
@media (max-width: 768px) {
|
||||
margin-top: 2.4rem;
|
||||
height: 20rem;
|
||||
}
|
||||
&[state="2"] {
|
||||
> * {
|
||||
@@ -1015,6 +1017,9 @@ export default defineComponent({
|
||||
// margin-top: 4rem;
|
||||
.email_last_step_bottom {
|
||||
padding: 0 40px;
|
||||
@media (max-width: 767px) {
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
.email_last_step_block {
|
||||
padding: 10px;
|
||||
@@ -1028,6 +1033,10 @@ export default defineComponent({
|
||||
font-size: 2.2rem;
|
||||
font-weight: bold;
|
||||
color: #030303;
|
||||
@media (max-width: 767px) {
|
||||
font-size: 1.2rem;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
.email_last_step_block_icon {
|
||||
cursor: pointer;
|
||||
@@ -1229,6 +1238,9 @@ export default defineComponent({
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
@media (max-width: 767px) {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.email_last_step_des {
|
||||
@@ -1237,16 +1249,25 @@ export default defineComponent({
|
||||
justify-content: space-between;
|
||||
margin-top: 4rem;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
@media (max-width: 767px) {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.sent_email_content {
|
||||
font-size: 1.8rem;
|
||||
font-weight: bold;
|
||||
color: #a5b0c2;
|
||||
@media (max-width: 767px) {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.email_tip_content {
|
||||
font-size: 1.4rem;
|
||||
color: #030303;
|
||||
@media (max-width: 767px) {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,9 +165,22 @@ export default defineComponent({
|
||||
time = setTimeout(()=>{
|
||||
let canvasData = JSON.parse(canvasJSON)
|
||||
if(!canvasData)return
|
||||
canvasData.canvas.objects.forEach((objectsItem:any) => {
|
||||
if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src)
|
||||
function deepProcessObjects(data:any, callback:any) {
|
||||
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();
|
||||
formData.append("file", blob, "data.json");
|
||||
|
||||
@@ -2,18 +2,17 @@ import axios from 'axios'
|
||||
// import qs from 'qs'
|
||||
// import message from '@/components/public/message/src'
|
||||
import router from '@/router/index'
|
||||
import {getCookie,clonAllCookie} from '@/tool/cookie'
|
||||
import { getCookie, clonAllCookie } from '@/tool/cookie'
|
||||
// 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/json";
|
||||
axios.defaults.headers.post['Content-Type'] = 'application/json'
|
||||
|
||||
|
||||
axios.defaults.headers.post['lang'] = 'en'; //配置语言请求头
|
||||
axios.defaults.withCredentials = true; //跨域携带cookie
|
||||
import { message } from 'ant-design-vue';
|
||||
import store from '@/store';
|
||||
axios.defaults.headers.post['lang'] = 'en' //配置语言请求头
|
||||
axios.defaults.withCredentials = true //跨域携带cookie
|
||||
import { message } from 'ant-design-vue'
|
||||
import store from '@/store'
|
||||
// if(import.meta.env.VITE_USER_NODE_ENV == "development"){
|
||||
// axios.defaults.baseURL = ""; //配置接口地址
|
||||
// }else{
|
||||
@@ -25,110 +24,128 @@ import store from '@/store';
|
||||
// }else{
|
||||
// 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" : "";
|
||||
|
||||
axios.defaults.baseURL = httpIp; //配置接口地址
|
||||
axios.defaults.baseURL = httpIp //配置接口地址
|
||||
// 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)
|
||||
|
||||
// 创建取消令牌
|
||||
const CancelToken = axios.CancelToken;
|
||||
const source = CancelToken.source();
|
||||
const CancelToken = axios.CancelToken
|
||||
const source = CancelToken.source()
|
||||
// console.log(import.meta.env.VITE_APP_BASE_URL);
|
||||
let isLoginTime = false
|
||||
//POST传参序列化(添加请求拦截器)
|
||||
axios.interceptors.request.use((config) => {
|
||||
axios.interceptors.request.use(
|
||||
config => {
|
||||
//在发送请求之前做某件事
|
||||
|
||||
|
||||
|
||||
// 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 = JSON.stringify(config.data);
|
||||
}
|
||||
// config.headers.Authorization = 'Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIyIiwic3ViIjoie1wiaWRcIjoyLFwidXNlcm5hbWVcIjpcImxpcnNcIn0iLCJpYXQiOjE2NjU3NDEwODcsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2NzQzODEwODd9.ShM9R_NNFD7oo1OvxrEgg7PFeWinOuAKkuInUCMQupp66s64Hhv8tN0Wwr83nIN4rHPqtn95wmd4msWcvaFYJA';
|
||||
config.headers.Authorization = getCookie('token');
|
||||
return config;
|
||||
},(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);
|
||||
config.headers.Authorization = getCookie('token')
|
||||
return config
|
||||
},
|
||||
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)
|
||||
return url
|
||||
}
|
||||
//返回状态判断(添加响应拦截器)
|
||||
axios.interceptors.response.use((res) =>{
|
||||
axios.interceptors.response.use(
|
||||
res => {
|
||||
// 允许透传完整响应:请求时传 config.fullData = true
|
||||
|
||||
// if(res.data.data == null){
|
||||
// message.warning(res.data.errMsg)
|
||||
// return Promise.reject(res.data);
|
||||
// }else
|
||||
if(res?.config?.env?.binary){
|
||||
let url = binaryToUrl(res.data,res.config.env.binaryType,res)
|
||||
return Promise.resolve({url,data:res.data})
|
||||
if (res?.config?.env?.binary) {
|
||||
let url = binaryToUrl(res.data, res.config.env.binaryType, res)
|
||||
return Promise.resolve({ url, data: res.data })
|
||||
}
|
||||
if (res?.data) {
|
||||
if (res?.data?.errCode === 0) {
|
||||
// message.error(res?.data?.errMsg)
|
||||
return Promise.resolve(res?.data?.data);
|
||||
} else if(res?.data?.errCode === 1){
|
||||
message.warning(res?.data?.errMsg)
|
||||
return Promise.reject(res?.data);
|
||||
} else if(res?.data?.errCode === 2){
|
||||
return Promise.reject(res?.data);
|
||||
}else if(res?.data?.errCode === -1){
|
||||
message.error(res?.data?.errMsg)
|
||||
return Promise.reject(res?.data);
|
||||
if (res?.config?.fullData) {
|
||||
return Promise.resolve(res.data)
|
||||
}
|
||||
return Promise.resolve(res?.data?.data)
|
||||
} else if (res?.data?.errCode === 1) {
|
||||
message.warning(res?.data?.errMsg)
|
||||
return Promise.reject(res?.data)
|
||||
} else if (res?.data?.errCode === 2) {
|
||||
return Promise.reject(res?.data)
|
||||
} else if (res?.data?.errCode === -1) {
|
||||
message.error(res?.data?.errMsg)
|
||||
return Promise.reject(res?.data)
|
||||
}
|
||||
|
||||
} else {
|
||||
if (res?.data?.errCode === 0) {
|
||||
message.warning(res?.data?.errMsg)
|
||||
return Promise.reject(res?.data);
|
||||
} else if(res?.data?.errCode === 1){
|
||||
return Promise.reject(res?.data)
|
||||
} else if (res?.data?.errCode === 1) {
|
||||
message.warning(res?.data?.errMsg)
|
||||
return Promise.reject(res?.data);
|
||||
} else if(res?.data?.errCode === 2){
|
||||
return Promise.reject(res?.data);
|
||||
}else if(res?.data?.errCode === -1){
|
||||
return Promise.reject(res?.data)
|
||||
} else if (res?.data?.errCode === 2) {
|
||||
return Promise.reject(res?.data)
|
||||
} else if (res?.data?.errCode === -1) {
|
||||
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()
|
||||
if(!isLoginTime){
|
||||
if (!isLoginTime) {
|
||||
isLoginTime = true
|
||||
let isSystemUserRouteList = ['/Square']//如果是这两个页面就无需跳转未登录页
|
||||
let isSystemUserRouteList = ['/Square'] //如果是这两个页面就无需跳转未登录页
|
||||
let sSystemUser = false
|
||||
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
|
||||
break
|
||||
}
|
||||
}
|
||||
if(!sSystemUser){
|
||||
if (!sSystemUser) {
|
||||
router.replace('/')
|
||||
}
|
||||
message.warning('Please login and try again~')
|
||||
store.commit('createDetail')
|
||||
store.commit('createProbject')
|
||||
store.commit('createProjectPath')
|
||||
setTimeout(()=>[
|
||||
isLoginTime = false
|
||||
],2000)
|
||||
setTimeout(() => [(isLoginTime = false)], 2000)
|
||||
}
|
||||
// source.cancel('取消后续接口调用');
|
||||
return Promise.reject()
|
||||
}
|
||||
let data_new = error?.response?.data
|
||||
// message.error(data_new?.errMsg || 'Error: server exception')
|
||||
return Promise.reject(data_new);
|
||||
});
|
||||
return Promise.reject(data_new)
|
||||
}
|
||||
)
|
||||
export const Https = {
|
||||
httpUrls: {
|
||||
interfaceUrl: '',
|
||||
@@ -447,9 +464,16 @@ export const Https = {
|
||||
segAnything: `/api/python/segAnything`, //分割Anything
|
||||
|
||||
// award页面
|
||||
uploadPDF: '/api/global-award/uploads/pdf', // 上传pdf
|
||||
uploadVideo: '/api/global-award/uploads/video', // 上传video
|
||||
|
||||
checkEmail: '/api/global-award/checkEmail', // 检查邮箱是否存在
|
||||
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) {
|
||||
|
||||
@@ -5,12 +5,19 @@
|
||||
BLOOM YOUR CREATIVITY • AiDA GLOBAL FASHION AWARD 2026
|
||||
</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="desc">AiDA Users Only</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-container">
|
||||
<Success v-if="isCompleted" />
|
||||
<div
|
||||
class="form-container"
|
||||
v-if="!isCompleted"
|
||||
>
|
||||
<div class="form-content">
|
||||
<a-form
|
||||
name="form"
|
||||
@@ -66,7 +73,22 @@
|
||||
:label="item.label"
|
||||
: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>
|
||||
</template>
|
||||
</div>
|
||||
@@ -84,13 +106,13 @@
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="full-row design-desc"
|
||||
name="description"
|
||||
name="designDescription"
|
||||
label="Design description"
|
||||
required
|
||||
>
|
||||
<a-textarea
|
||||
class="textarea"
|
||||
v-model:value="form.description"
|
||||
v-model:value="form.designDescription"
|
||||
placeholder="Briefly describe your design concept, inspiration, and creative direction..."
|
||||
/>
|
||||
</a-form-item>
|
||||
@@ -307,16 +329,22 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onUnmounted } from 'vue'
|
||||
import { ref, onUnmounted, onMounted } from 'vue'
|
||||
import { debounce } from 'lodash-es'
|
||||
import type { Rule } from 'ant-design-vue/es/form'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { Https } from '@/tool/https'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { UploadChangeParam } from 'ant-design-vue'
|
||||
import VerifycationCodeInput from './components/VerificationCodeInput.vue'
|
||||
import { Https } from '@/tool/https'
|
||||
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 form = ref({
|
||||
email: '',
|
||||
@@ -325,14 +353,15 @@
|
||||
gender: '',
|
||||
occupation: '',
|
||||
age: '',
|
||||
counterOrRegion: '',
|
||||
phone: '',
|
||||
portfoilo: '',
|
||||
countryRegionCity: '',
|
||||
phoneNumber: '',
|
||||
portfolioUrl: '',
|
||||
// code: '',
|
||||
designTitle: '',
|
||||
description: '',
|
||||
pdfPath: null,
|
||||
videoPath: null
|
||||
designDescription: '',
|
||||
pdfPath: 'test.pdf',
|
||||
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([
|
||||
{
|
||||
label: 'First Name',
|
||||
@@ -428,20 +471,20 @@
|
||||
label: 'Country/Region and City',
|
||||
required: true,
|
||||
type: 'input',
|
||||
key: 'counterOrRegion'
|
||||
key: 'countryRegionCity'
|
||||
},
|
||||
{
|
||||
label: 'Phone Number',
|
||||
required: true,
|
||||
type: 'input',
|
||||
key: 'phone'
|
||||
key: 'phoneNumber'
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Portfoilo Website/Instagram(Optional)',
|
||||
required: false,
|
||||
type: 'input',
|
||||
key: 'portfoilo'
|
||||
key: 'portfolioUrl'
|
||||
}
|
||||
])
|
||||
|
||||
@@ -488,11 +531,13 @@
|
||||
try {
|
||||
await formRef.value.validateFields(['email'])
|
||||
// TODO: 发送验证码的逻辑
|
||||
message.success('Verification code sent successfully!')
|
||||
await Https.axiosGet(Https.httpUrls.checkEmail, {
|
||||
params: {
|
||||
email: form.value.email
|
||||
}
|
||||
})
|
||||
|
||||
// 开始倒计时
|
||||
startCountdown()
|
||||
|
||||
showModal.value = true
|
||||
} catch (error) {}
|
||||
}, 300)
|
||||
@@ -506,6 +551,28 @@
|
||||
const handleCloseModal = () => {
|
||||
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 validCondition = conditionsList.value.filter(
|
||||
@@ -515,26 +582,21 @@
|
||||
message.error('Please check the terms and conditions')
|
||||
return
|
||||
}
|
||||
formRef.value.validate().then(res => {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(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)
|
||||
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 videoList = ref([])
|
||||
const isUploadingPdf = ref(false)
|
||||
@@ -544,6 +606,14 @@
|
||||
const pdfUploadStatus = 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) => {
|
||||
if (!hasValidEmail.value) {
|
||||
@@ -626,6 +696,88 @@
|
||||
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'
|
||||
const handleFileChange = (info: UploadChangeParam, type: FileType) => {
|
||||
const status = info.file.status
|
||||
@@ -656,65 +808,68 @@
|
||||
}
|
||||
|
||||
// 统一的上传处理函数
|
||||
const handleUploadFile = (option: any, type: FileType) => {
|
||||
console.log(option, type)
|
||||
const handleUploadFile = async (option: any, type: FileType) => {
|
||||
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') {
|
||||
isUploadingPdf.value = true
|
||||
uploadProgressPdf.value = 0
|
||||
pdfUploadStatus.value = 'uploading'
|
||||
} else if (type === 'video') {
|
||||
} else {
|
||||
isUploadingVideo.value = true
|
||||
uploadProgressVideo.value = 0
|
||||
videoUploadStatus.value = 'uploading'
|
||||
}
|
||||
|
||||
const params = new FormData()
|
||||
params.append('file', file)
|
||||
params.append('email', form.value.email)
|
||||
try {
|
||||
const { uploadId, chunkSize } = await initializeChunkUpload(type, file)
|
||||
chunkUploadState[type].uploadId = uploadId
|
||||
chunkUploadState[type].chunkSize = chunkSize
|
||||
chunkUploadState[type].uploadedChunks = new Set()
|
||||
|
||||
// 根据类型选择不同的上传接口
|
||||
const uploadUrl = Https.httpUrls.uploadAvatar
|
||||
// const uploadUrl =
|
||||
// type === 'pdf' ? Https.httpUrls.uploadPDF : Https.httpUrls.uploadVideo
|
||||
const chunks = createFileChunks(file, chunkSize)
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
await uploadChunk(type, chunks[i], i, chunks.length)
|
||||
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') {
|
||||
uploadProgressPdf.value = percentCompleted
|
||||
} else if (type === 'video') {
|
||||
uploadProgressVideo.value = percentCompleted
|
||||
pdfUploadStatus.value = 'success'
|
||||
uploadProgressPdf.value = 100
|
||||
isUploadingPdf.value = false
|
||||
form.value.pdfPath = uploadId
|
||||
} else {
|
||||
videoUploadStatus.value = 'success'
|
||||
uploadProgressVideo.value = 100
|
||||
isUploadingVideo.value = false
|
||||
form.value.videoPath = uploadId
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
console.log(res)
|
||||
if (type === 'pdf') pdfUploadStatus.value = 'success'
|
||||
if (type === 'video') videoUploadStatus.value = 'success'
|
||||
option.onSuccess(res, option.file)
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
option.onSuccess?.({ uploadId }, option.file)
|
||||
} catch (error: any) {
|
||||
console.error('Upload error:', error)
|
||||
option.onError(error)
|
||||
message.error(error?.message || 'Upload failed')
|
||||
option.onError?.(error)
|
||||
|
||||
if (type === 'pdf') {
|
||||
isUploadingPdf.value = false
|
||||
uploadProgressPdf.value = 0
|
||||
pdfUploadStatus.value = 'error'
|
||||
} else if (type === 'video') {
|
||||
} else {
|
||||
isUploadingVideo.value = false
|
||||
uploadProgressVideo.value = 0
|
||||
videoUploadStatus.value = 'error'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 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(() => {
|
||||
clearCountdown()
|
||||
})
|
||||
@@ -773,10 +939,18 @@
|
||||
.full-row {
|
||||
width: 100%;
|
||||
}
|
||||
.arrow-down-icon {
|
||||
width: 2rem;
|
||||
height: 1rem;
|
||||
}
|
||||
.apply-container {
|
||||
min-height: calc(100% -18rem);
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.banner {
|
||||
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%;
|
||||
text-align: center;
|
||||
padding: 12rem 21.4rem 0;
|
||||
@@ -888,7 +1062,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-input) {
|
||||
:deep(.ant-input),
|
||||
:deep(.ant-select-selector) {
|
||||
border: 0.2rem solid #d5d5d5;
|
||||
height: 6rem;
|
||||
border-radius: 0.8rem;
|
||||
@@ -899,6 +1074,20 @@
|
||||
&.textarea {
|
||||
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) {
|
||||
.ant-checkbox-inner {
|
||||
//修改边框的颜色
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border: 0.2rem solid #585858 !important;
|
||||
@@ -1100,17 +1288,11 @@
|
||||
}
|
||||
|
||||
.ant-checkbox-checked .ant-checkbox-inner {
|
||||
//修改选中框的背景颜色
|
||||
background-color: #fff !important;
|
||||
/* 将背景颜色修改为白色 */
|
||||
//修改边框颜色
|
||||
border-color: #585858 !important;
|
||||
/* 将边框颜色修改为黑色 */
|
||||
}
|
||||
|
||||
.ant-checkbox-checked .ant-checkbox-inner::after {
|
||||
//antd的checkbox组件的选中框里面的透明的钩子,是通过设置底部边框和右边框的颜色再旋转得到的钩子,
|
||||
// 所以设置底部边框和右边框的样式就可以修改钩子的样式
|
||||
border-bottom: 0.2rem solid #585858;
|
||||
border-right: 0.2rem solid #585858;
|
||||
width: 0.65rem;
|
||||
@@ -1202,6 +1384,7 @@
|
||||
font-family: 'ArialBold';
|
||||
font-weight: 700;
|
||||
font-size: 1.6rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cutdown {
|
||||
|
||||
51
src/views/AwardPage/components/Success.vue
Normal file
51
src/views/AwardPage/components/Success.vue
Normal 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>
|
||||
@@ -7,8 +7,11 @@
|
||||
class="logo"
|
||||
/>
|
||||
</div>
|
||||
<div class="header-right flex align-center">
|
||||
<div class="text">Submit your Application</div>
|
||||
<div
|
||||
class="header-right flex align-center"
|
||||
@click="handleBtnClick"
|
||||
>
|
||||
<div class="text">{{ btnText }}</div>
|
||||
<img
|
||||
src="@/assets/images/award/arrow.png"
|
||||
alt=""
|
||||
@@ -89,12 +92,51 @@
|
||||
</template>
|
||||
|
||||
<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 handleCloseQRcode = () => {
|
||||
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>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@@ -123,6 +165,7 @@
|
||||
}
|
||||
.header-right {
|
||||
column-gap: 1rem;
|
||||
cursor: pointer;
|
||||
.text {
|
||||
font-size: 1.6rem;
|
||||
color: #fff;
|
||||
|
||||
@@ -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;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
}
|
||||
&:hover .img_item_hover{
|
||||
// display: block;
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
<!-- <div class="upgrade-content-text">System upgrading</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 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>
|
||||
<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">由于系统服务器维护,AiDA系统暂时无法访问。对于由此造成的任何不便,我们深表歉意,并感谢您的理解</div> -->
|
||||
<div class="upgrade-content-textab">由于系统服务器升级,我们将于12月19日21:00 至12月19日22:00进行升级。<br>在此期间,AiDA系统将暂时无法访问。给您带来的不便,我们深表歉意,并感谢您的理解</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user