diff --git a/.env.development b/.env.development
index 81a54878..f1912101 100644
--- a/.env.development
+++ b/.env.development
@@ -2,33 +2,32 @@
ENV = 'development'
# 'development'
-#VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
+# VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
-# VITE_APP_BASE_API_Url = ' http://25.18.122.66:9786'
-#sit
+# VITE_APP_BASE_API_Url = 'http://192.168.247.200'
+# VITE_APP_BASE_API_Url = 'http://aitscdn.jlbank.com.cn:7001'
+# VITE_APP_BASE_API_Url = 'http://192.168.108.129'
+# dev
+#VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
+# sit
# VITE_APP_BASE_API_Url = 'http://25.18.122.91:9786'
# UAT
# VITE_APP_BASE_API_Url = 'http://25.18.122.78:9786'
# DEV
-
# app入口
-# VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
+
# VITE_APP_BASE_API_Url = 'http://25.16.122.91:9786'
# VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786'
# h5专用地址x2
-VITE_APP_BASE_H5_API_Url = 'http://25.18.122.65:7001'
+# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.65:7001'
# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.91:9786'
# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.78:9786'
-
-# VITE_APP_BASE_H5_API_Url_TRAAPP = 'http://25.64.16.130:9601'
-# VITE_APP_BASE_H5_API_Url_TRASTUDY = 'http://25.64.16.130:9602'
-
-# VITE_APP_BASE_H5_API_Url_TRAASK = 'http://25.64.16.144:9605'
-VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.16.139:9604'
-
-
+#VITE_APP_BASE_H5_API_Url_TRAAPP = 'http://192.168.247.200'
+# VITE_APP_BASE_H5_API_Url_TRASTUDY = 'http://25.64.32.154:9602'
+#VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://192.168.247.200'
+# VITE_APP_BASE_H5_API_Url_TRAASK = 'http://25.64.32.154:9605'
diff --git a/.env.development.rd b/.env.development.rd
new file mode 100644
index 00000000..ca382f2c
--- /dev/null
+++ b/.env.development.rd
@@ -0,0 +1,8 @@
+# 任东专用开发环境
+ENV = 'development.rd'
+# 'development.rd'
+
+#VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
+VITE_APP_BASE_API_Url = 'http://25.18.122.91:9786'
+
+VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.32.154:9604'
diff --git a/.env.development.ty b/.env.development.ty
new file mode 100644
index 00000000..15d511f0
--- /dev/null
+++ b/.env.development.ty
@@ -0,0 +1,9 @@
+# 田岩开发环境
+ENV = 'development.ty'
+# 'development.ty'
+
+VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
+
+VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://192.168.108.129'
+
+
diff --git a/.env.development.yh b/.env.development.yh
new file mode 100644
index 00000000..55b67b98
--- /dev/null
+++ b/.env.development.yh
@@ -0,0 +1,10 @@
+# 杨航开发环境
+ENV = 'development.yh'
+# 'development.yh'
+
+VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
+
+VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.32.154:9604'
+
+
+
diff --git a/logo/Thumbs.db b/logo/Thumbs.db
new file mode 100644
index 00000000..4aac3f54
Binary files /dev/null and b/logo/Thumbs.db differ
diff --git a/package.json b/package.json
index cc24343e..71972694 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,9 @@
"description": "",
"scripts": {
"dev:h5": "uni",
+ "dev:rd": "uni -p h5 --mode development.rd",
+ "dev:yh": "uni -p h5 --mode development.yh",
+ "dev:ty": "uni -p h5 --mode development.ty",
"dev:h5:sit": "uni -p h5 --mode sit",
"dev:h5:uat": "uni -p h5 --mode uat",
"dev:h5:production": "uni -p h5 --mode production",
diff --git a/src/App.vue b/src/App.vue
index b5f9ab78..141b9280 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -9,23 +9,7 @@
});
},
onShow: function () {
- // function getBrowserInfo() {
- // const userAgent = navigator.userAgent;
- // let browserName = '未知浏览器';
- // let version = '未知版本';
- // // 检测 Chrome
- // if (userAgent.indexOf('Chrome') > -1 && userAgent.indexOf('Edg') === -1) {
- // browserName = 'Chrome';
- // version = userAgent.match(/Chrome\/(\d+\.\d+)/)[1];
- // }
-
- // return {
- // browser: browserName,
- // version: version,
- // userAgent: userAgent
- // };
- // }
},
onHide: function () {
}
diff --git a/src/api/competition.js b/src/api/competition.js
new file mode 100644
index 00000000..131a92ab
--- /dev/null
+++ b/src/api/competition.js
@@ -0,0 +1,85 @@
+import request from '@/api/request'
+
+const module_url = '/traexam'
+
+// 查询竞赛列表
+export const queryTraCompetitionInfoPaging = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/queryTraCompetitionInfoPaging',
+ method: 'post',
+ data
+ });
+};
+
+// 查询试卷
+export const queryTestPapers = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/queryTestPapers',
+ method: 'post',
+ data
+ });
+};
+
+// 查询PK人员+试题
+export const queryTraCompetitionInfoByPkUser = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/queryTraCompetitionInfoByPkUser',
+ method: 'post',
+ data
+ });
+};
+
+// 循环获取简答题结果
+export const queryCompetitionPracticeAnswerResult = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/queryCompetitionPracticeAnswerResult',
+ method: 'post',
+ data
+ });
+};
+
+// 答题结束
+export const competitionAnswerEnd = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/competitionAnswerEnd',
+ method: 'post',
+ data,
+ suppressErrors: true // 屏蔽报错信息
+ });
+};
+
+// 竞赛答题
+export const competitionAnswer = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/competitionAnswer',
+ method: 'post',
+ data
+ });
+};
+
+// 查询答题结果
+export const queryCompetitionAnswerResult = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/queryCompetitionAnswerResult',
+ method: 'post',
+ data
+ });
+};
+
+// 竞赛排行榜
+export const queryTraCompetitionRankingList = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/queryTraCompetitionRankingList',
+ method: 'post',
+ data
+ });
+};
+
+// 全行的机构数据
+export const queryOrgTree = (data) => {
+ return request({
+ url: module_url + '/traCompetitionInfo/queryOrgTree',
+ method: 'post',
+ data
+ });
+};
diff --git a/src/api/login.js b/src/api/login.js
index fe1660ef..42ccd781 100644
--- a/src/api/login.js
+++ b/src/api/login.js
@@ -4,6 +4,10 @@ import {
queryCurrentValidMascotInfo
} from "@/api/mascot.js"
+import {
+ queryCurrentStatus
+} from '@/api/pointsAndRank.js';
+
import {
setToken,
setUserInfo,
@@ -24,15 +28,26 @@ export const useAccountLoginApp = (data) => request({
}) => {
if (rtnCode === '0000') {
setToken(body)
- const res = await Promise.all([queryCurrentUser(), queryCurrentValidMascotInfo()])
+ const res = await Promise.all([queryCurrentUser(), queryCurrentValidMascotInfo()
+ // queryCurrentStatus()
+ ])
const userInfo = getUserInfo()
const mascotInfo = res[1]
setUserInfo({
...userInfo,
'mascotInfo': mascotInfo
})
+ // 积分状态
+ // const pointsStatus = res[2].body
+
+ common.setValue('points_data', {
+ badgeNum: pointsStatus['badgeNum'] ?? 0, // 徽章数
+ currentPoints: pointsStatus['currentPoints'] ?? 0, // 当前积分
+ currentRankAddr: pointsStatus['ossAddr'] ?? '', // 当前段位图片
+ currentRankName: pointsStatus['currentRankName']?? '未知', // 当前段位名称
+ })
return {
- mascotState:!mascotInfo.mascotId
+ mascotState: !mascotInfo.mascotId
}
}
return Promise.reject({
@@ -40,22 +55,6 @@ export const useAccountLoginApp = (data) => request({
body
})
}).catch(res => {
- /**
- error: "Service Unavailable"
- path: "/traapp/access/userLogin"
- requestId: "74d60800-104"
- status: 503
- timestamp: "2025-06-24T00:53:35.293+00:00"
- */
- /**
- body: null
- channelNo: "FF6944B69A99745C009F4D0B3C3B22B8E81B22F587D68455E354BABBABCCB6246C54ABD28F3C55AAD34224A16CE7E24E"
- head: null
- message: "系统异常"
- rtnCode: "9999"
- rtnTime: "2025-06-24 08:54:52"
- */
-
return Promise.reject(res)
})
@@ -72,7 +71,7 @@ export const queryCurrentUser = (data) => request({
method: 'post',
data
}).then(res => {
-
+
// deptId: ""
// deptName: null
// loginName: "ADMIN" // todo id
@@ -92,107 +91,109 @@ export const queryCurrentUser = (data) => request({
// #ifdef APP-PLUS
// 更新用户信息中的头像路径
const updateUserAvatar = (imagePath) => {
- const _userInfo = getUserInfo() ?? {}
- setUserInfo({
- ..._userInfo,
- ...res.body,
- 'imagePath': imagePath
- })
+ const _userInfo = getUserInfo() ?? {}
+ setUserInfo({
+ ..._userInfo,
+ ...res.body,
+ 'imagePath': imagePath
+ })
}
-
+
// 确保目录存在
const ensureDirectoryExists = (dirPath) => {
- return new Promise((resolve) => {
- plus.io.requestFileSystem(plus.io.PRIVATE_DOC, (fs) => {
- fs.root.getDirectory(dirPath, { create: true }, resolve, resolve)
- })
- })
+ return new Promise((resolve) => {
+ plus.io.requestFileSystem(plus.io.PRIVATE_DOC, (fs) => {
+ fs.root.getDirectory(dirPath, {
+ create: true
+ }, resolve, resolve)
+ })
+ })
}
-
+
// 生成唯一文件名
const generateUniqueFilename = (pathName) => {
- if (!pathName || typeof pathName !== 'string') {
- throw new Error('无效的路径');
- }
-
- // 直接使用原始文件名(带扩展名)
- const filename = pathName.split('/').pop();
-
- if (!filename) {
- throw new Error('无法从路径中提取文件名');
- }
-
- // 确保文件扩展名为.png (可选,根据实际需求)
- const ext = filename.split('.').pop().toLowerCase();
- if (ext === 'png' || ext === 'jpg' || ext === 'jpeg' || ext === 'webp') {
- return filename;
- }
-
- // 如果没有有效扩展名,添加.png
- return `${filename}.png`;
+ if (!pathName || typeof pathName !== 'string') {
+ throw new Error('无效的路径');
+ }
+
+ // 直接使用原始文件名(带扩展名)
+ const filename = pathName.split('/').pop();
+
+ if (!filename) {
+ throw new Error('无法从路径中提取文件名');
+ }
+
+ // 确保文件扩展名为.png (可选,根据实际需求)
+ const ext = filename.split('.').pop().toLowerCase();
+ if (ext === 'png' || ext === 'jpg' || ext === 'jpeg' || ext === 'webp') {
+ return filename;
+ }
+
+ // 如果没有有效扩展名,添加.png
+ return `${filename}.png`;
};
-
+
// 下载并保存头像
const downloadAndSaveAvatar = async (fileUrl, localFilePath) => {
- try {
- await ensureDirectoryExists('avatar')
-
- return new Promise((resolve, reject) => {
- console.log('开始下载头像:', fileUrl)
- const dtask = plus.downloader.createDownload(fileUrl, {
- filename: localFilePath
- }, (d, status) => {
- if (status === 200) {
- console.log("保存路径:", d.filename)
- resolve(d.filename)
- } else {
- console.error("文件下载失败:", status)
- reject(new Error(`下载失败,状态码: ${status}`))
- }
- })
-
- dtask.start()
- })
- } catch (error) {
- console.error('创建目录失败:', error)
- throw error
- }
+ try {
+ await ensureDirectoryExists('avatar')
+
+ return new Promise((resolve, reject) => {
+ console.log('开始下载头像:', fileUrl)
+ const dtask = plus.downloader.createDownload(fileUrl, {
+ filename: localFilePath
+ }, (d, status) => {
+ if (status === 200) {
+ console.log("保存路径:", d.filename)
+ resolve(d.filename)
+ } else {
+ console.error("文件下载失败:", status)
+ reject(new Error(`下载失败,状态码: ${status}`))
+ }
+ })
+
+ dtask.start()
+ })
+ } catch (error) {
+ console.error('创建目录失败:', error)
+ throw error
+ }
}
-
+
// 检查文件是否存在
const checkFileExists = (filePath) => {
- return new Promise((resolve) => {
- uni.getFileInfo({
- filePath,
- success: () => resolve(true),
- fail: () => resolve(false)
- })
- })
+ return new Promise((resolve) => {
+ uni.getFileInfo({
+ filePath,
+ success: () => resolve(true),
+ fail: () => resolve(false)
+ })
+ })
}
-
+
// 主逻辑
(async () => {
- try {
- const pathName = res.body.imageAddr
- const fileUrl = base_url + pathName
-
- // 生成保存路径
- const filename = generateUniqueFilename(pathName)
- const localFilePath = '_doc/avatar/' + filename
-
- // 检查文件是否存在
- const exists = await checkFileExists(localFilePath)
-
- if (exists) {
- // console.log('头像已存在,无需下载')
- updateUserAvatar(localFilePath)
- } else {
- const savedPath = await downloadAndSaveAvatar(fileUrl, localFilePath)
- updateUserAvatar(savedPath)
- }
- } catch (error) {
- console.error('头像预加载过程发生错误:', error)
- }
+ try {
+ const pathName = res.body.imageAddr
+ const fileUrl = base_url + pathName
+
+ // 生成保存路径
+ const filename = generateUniqueFilename(pathName)
+ const localFilePath = '_doc/avatar/' + filename
+
+ // 检查文件是否存在
+ const exists = await checkFileExists(localFilePath)
+
+ if (exists) {
+ // console.log('头像已存在,无需下载')
+ updateUserAvatar(localFilePath)
+ } else {
+ const savedPath = await downloadAndSaveAvatar(fileUrl, localFilePath)
+ updateUserAvatar(savedPath)
+ }
+ } catch (error) {
+ console.error('头像预加载过程发生错误:', error)
+ }
})()
// #endif
@@ -230,4 +231,5 @@ export const loginOut = (data) => request({
setUserInfo(null)
common.setValue('me_statistics_data', null) // 我的页统计数据缓存
common.setValue('index_statistics_data', null) // 首页统计数据缓存
+ common.setValue('points_data', null) // 首页统计数据缓存
})
\ No newline at end of file
diff --git a/src/api/pointsAndRank.js b/src/api/pointsAndRank.js
new file mode 100644
index 00000000..bab3c9dc
--- /dev/null
+++ b/src/api/pointsAndRank.js
@@ -0,0 +1,123 @@
+import request from '@/api/request'
+const base_url = '/traapp'
+
+/**
+ * 查询签到
+ * userId 学员ID String
+ * checkInToday 今日是否签到 String
+ * days 连续签到天数 int
+ */
+export const queryCheckIn = (data) => {
+ return request({
+ url: base_url + '/traPointsInfo/queryCheckIn',
+ method: 'post',
+ data
+ });
+};
+
+/**
+ * 点击签到
+ */
+export const addPointsByCheckIn = (data) => {
+ return request({
+ url: base_url + '/traPointsInfo/addPointsByCheckIn',
+ method: 'post',
+ data
+ });
+};
+
+
+/**
+ * 每次完成任务获得弹窗奖励
+ * 入参:
+ taskId 必输项:true 类型:String
+ type 必输项:true 类型:String
+ 出参:
+ userId 学员ID String
+ badgeName 徽章名称 String
+ badgeImg 徽章图片 String
+ num 次数 int
+ name 描述 String
+ pointsBadgeName 积分徽章名称 String
+ pointsBadgeImg 徽章图片 String
+ currentPoints 当前积分 int
+ changePoints 本次获得积分 int
+ */
+export const addPointsByTask = (data) => {
+ return request({
+ url: base_url + '/traPointsInfo/addPointsByTask',
+ method: 'post',
+ data
+ });
+};
+
+/**
+ * 查询积分明细
+ * 出参:
+ detailId 明细ID String
+ userId 学员ID String
+ mattr 积分来源事项 String
+ mattrDesc 积分来源描述 String
+ changeValue 积分变化值 String
+ currentPoints 当前积分 int
+ countPoints 累计积分 int
+ ctTime 创建时间 String
+ */
+export const queryPointsDetail = (data) => {
+ return request({
+ url: base_url + '/traPointsInfo/queryPointsDetail',
+ method: 'post',
+ data
+ });
+};
+
+
+/**
+ * 查询段位明细
+ * 出参:
+ rankId 段位ID String
+ rankName 段位名称 String
+ currentRankName 当前段位名称 String
+ ossAddr 段位图片 String
+ pointsStart 段位开始区间 int
+ pointsEnd 段位结束区间 int
+ countPoints 累计积分 int
+ */
+export const queryRankDetail = (data) => {
+ return request({
+ url: base_url + '/traPointsInfo/queryRankDetail',
+ method: 'post',
+ data
+ });
+};
+
+
+/**
+ * 查询当前状态
+ * 出参:
+ userId 学员ID String
+ orgId 机构ID String
+ countPoints 累计积分 int
+ currentPoints 当前积分 int
+ currentRankName 当前段位 String
+ badgeNum 徽章数 int
+ */
+export const queryCurrentStatus = (data) => {
+ return request({
+ url: base_url + '/traPointsInfo/queryCurrentStatus',
+ method: 'post',
+ data
+ });
+};
+
+
+/**
+ * 徽章墙
+ */
+export const queryRankWall = (data) => {
+ return request({
+ url: base_url + '/traPointsInfo/queryRankWall',
+ method: 'post',
+ data
+ });
+};
diff --git a/src/api/request.js b/src/api/request.js
index 50e865f0..e9a30160 100644
--- a/src/api/request.js
+++ b/src/api/request.js
@@ -4,9 +4,27 @@ import {
import common from '@/common/common.js'
const ENV = import.meta.env
+// function getBrowserInfo() {
+// const userAgent = navigator.userAgent;
+// let browserName = '未知浏览器';
+// let version = '未知版本';
+
+// // 检测 Chrome
+// if (userAgent.indexOf('Chrome') > -1 && userAgent.indexOf('Edg') === -1) {
+// browserName = 'Chrome';
+// version = userAgent.match(/Chrome\/(\d+\.\d+)/)[1];
+// }
+
+// return {
+// browser: browserName,
+// version: version,
+// userAgent: userAgent
+// };
+// }
+
export const get_base_url = (url = '') => {
- if (ENV.MODE === 'development') { // 开发环境
+ if (['development', 'development.rd', 'development.yh', 'development.ty'].includes(ENV.MODE)) { // 开发环境
// #ifdef H5
if (url) {
let _str = (url.split('/')[0] || url.split('/')[1])?.toUpperCase()
@@ -20,7 +38,7 @@ export const get_base_url = (url = '') => {
return ENV.VITE_APP_BASE_API_Url
// #endif
} else { // 其他环境,包括生产环境,sit环境,uat环境
-
+
return ENV.VITE_APP_BASE_API_Url
// return ENV.VITE_APP_BASE_API_Url
diff --git a/src/api/user.js b/src/api/user.js
index 87aa7224..b4a180b1 100644
--- a/src/api/user.js
+++ b/src/api/user.js
@@ -36,4 +36,22 @@ export const updateDfSysUserExtandInfoGender = (data) => {
data
});
};
-
\ No newline at end of file
+
+// 设置匿名 是Y 否N
+export const updateTraUserAnony = (data) => {
+ return request({
+ url: '/traapp/traUserAnony/updateTraUserAnony',
+ method: 'post',
+ data
+ });
+};
+
+// 查询是否匿名 是Y 否N
+export const queryTraUserAnonyByUserId = (data) => {
+ return request({
+ url: '/traapp/traUserAnony/queryTraUserAnonyByUserId',
+ method: 'post',
+ data
+ });
+};
+
diff --git a/src/common/common.js b/src/common/common.js
index 3e2f2054..037c20a2 100644
--- a/src/common/common.js
+++ b/src/common/common.js
@@ -233,8 +233,8 @@ function setValue(key, value) {
uni.setStorageSync(key, value);
}
-function getValue(key) {
- return uni.getStorageSync(key)
+function getValue(key, defaultValue=null) {
+ return uni.getStorageSync(key) ?? defaultValue
}
function isLogin() {
diff --git a/src/common/imgSvg.ts b/src/common/imgSvg.ts
index 4dbf34f4..ea02103c 100644
--- a/src/common/imgSvg.ts
+++ b/src/common/imgSvg.ts
@@ -5,7 +5,7 @@ export const optionSuccessIcon = (color : string) : string => {
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
-export const optionErrorIcon = (color: string='#F5212D') : string => {
+export const optionErrorIcon = (color : string = '#F5212D') : string => {
const svgXml = `
`.trim();
@@ -19,7 +19,7 @@ export const examinationSheetIcon = () : string => {
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
-export const markIcon = (color: string='#ABABAB') : string => {
+export const markIcon = (color : string = '#ABABAB') : string => {
const svgXml = `
`.trim();
@@ -34,7 +34,7 @@ export const feedbackIcon = () : string => {
};
// 通过考试
-export const passTheExamIcon = (color: string) : string => {
+export const passTheExamIcon = (color : string) : string => {
const svgXml = `
`.trim();
@@ -42,7 +42,7 @@ export const passTheExamIcon = (color: string) : string => {
};
// 完成练习
-export const completeTheExercisesIcon = (color: string) : string => {
+export const completeTheExercisesIcon = (color : string) : string => {
const svgXml = `
`.trim();
@@ -50,7 +50,7 @@ export const completeTheExercisesIcon = (color: string) : string => {
};
// 锁定
-export const lockIcon = (color: string) : string => {
+export const lockIcon = (color : string) : string => {
const svgXml = `
`.trim();
@@ -66,3 +66,53 @@ export const practiceExitIcon = () : string => {
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
+
+// Pk页规则图标
+export const pkRules = () : string => {
+ const svgXml = `
+
+`.trim();
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
+};
+
+// Pk页排行榜图标
+export const pkRankingList = () : string => {
+ const svgXml = `
+
+`.trim();
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
+};
+
+// Pk页匿名关
+export const pkAnonymousClose = () : string => {
+ const svgXml = `
+
+`.trim();
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
+};
+
+// Pk页匿名开
+export const pkAnonymousOpen = () : string => {
+ const svgXml = `
+
+`.trim();
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
+};
+
+
+// 重置页图标
+export const resetIcon = () : string => {
+ const svgXml = `
+
+`.trim();
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
+};
+
+
+// pk页切换图标
+export const switchIcon = () : string => {
+ const svgXml = `
+
+`.trim();
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
+};
diff --git a/src/components/cached-avatar/cached-avatar.vue b/src/components/cached-avatar/cached-avatar.vue
new file mode 100644
index 00000000..ff1a20b6
--- /dev/null
+++ b/src/components/cached-avatar/cached-avatar.vue
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/examination/es-analysis.vue b/src/components/examination/es-analysis.vue
index e1a82d6c..a2de879c 100644
--- a/src/components/examination/es-analysis.vue
+++ b/src/components/examination/es-analysis.vue
@@ -19,7 +19,7 @@
diff --git a/src/components/points-and-badge/badge.vue b/src/components/points-and-badge/badge.vue
new file mode 100644
index 00000000..0754586f
--- /dev/null
+++ b/src/components/points-and-badge/badge.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/points-and-badge/check-in.vue b/src/components/points-and-badge/check-in.vue
new file mode 100644
index 00000000..8d2341b8
--- /dev/null
+++ b/src/components/points-and-badge/check-in.vue
@@ -0,0 +1,417 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/points-and-badge/points.vue b/src/components/points-and-badge/points.vue
new file mode 100644
index 00000000..02409e35
--- /dev/null
+++ b/src/components/points-and-badge/points.vue
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/selection-institutions/index.vue b/src/components/selection-institutions/index.vue
new file mode 100644
index 00000000..fb0ba731
--- /dev/null
+++ b/src/components/selection-institutions/index.vue
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
diff --git a/src/components/selection-institutions/treeSelector.vue b/src/components/selection-institutions/treeSelector.vue
new file mode 100644
index 00000000..ef10a915
--- /dev/null
+++ b/src/components/selection-institutions/treeSelector.vue
@@ -0,0 +1,134 @@
+
+
+
+
+
+ {{ item.orgName }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/composables/useZpaging.js b/src/composables/useZpaging.js
index faf92378..e7482454 100644
--- a/src/composables/useZpaging.js
+++ b/src/composables/useZpaging.js
@@ -43,7 +43,8 @@ export default function useZpaging({
}
// 搜索
- const search = (value, state) => {
+ const search = (value, state=true) => {
+ console.log('搜索', value, state);
searchText.value = value;
if (state) {
reload()
diff --git a/src/enum.js b/src/enum.js
index 7ec50154..d40c7cb8 100644
--- a/src/enum.js
+++ b/src/enum.js
@@ -13,7 +13,7 @@ export const GENDER = [{
value: "f",
label: "女性",
}
-]
+]
// 试题题型
export const SUBJECT_TYPE = [{
value: "SN",
@@ -32,4 +32,19 @@ export const SUBJECT_TYPE = [{
label: "问答题",
}
]
-export const defaultAvatar = '/static/images/me/default_user_avatar.png'
\ No newline at end of file
+export const defaultAvatar = '/static/images/me/default_user_avatar.png'
+export const defaultAnonymousAvatar = '/static/images/competition/competition_default_avatar.png'
+export const styleButton = {
+ style_button_1: {
+ color: '#FFFFFF',
+ fontSize: '30rpx',
+ backgroundColor: '#0066FF',
+ borderRadius: '8rpx'
+ },
+ style_button_2: {
+ color: '#0066FF',
+ fontSize: '30rpx',
+ backgroundColor: '#E2EDFF',
+ borderRadius: '8rpx'
+ }
+}
\ No newline at end of file
diff --git a/src/manifest.json b/src/manifest.json
index ce7971c6..3013d5af 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -48,11 +48,13 @@
]
},
/* ios打包配置 */
- "ios" : {},
+ "ios" : {
+ "dSYMs" : false
+ },
/* SDK配置 */
"sdkConfigs" : {},
"splashscreen" : {
- "androidStyle" : "default",
+ "androidStyle" : "common",
"android" : {
"hdpi" : "src/static/images/login/open.9.png",
"xhdpi" : "src/static/images/login/open.9.png",
diff --git a/src/pages.json b/src/pages.json
index 675567b4..29a19bfc 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -311,6 +311,79 @@
}
}
},
+ {
+ "path": "pages/competition/index",
+ "style": {
+ "navigationBarTitleText": "竞赛列表页",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/competition/matching",
+ "style": {
+ "navigationBarTitleText": "匹配页面",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/competition/pk",
+ "style": {
+ "navigationBarTitleText": "pk页面",
+ "disableSwipeBack": true,
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/competition/result",
+ "style": {
+ "navigationBarTitleText": "pk结果页面",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/competition/ranking",
+ "style": {
+ "navigationBarTitleText": "pk排行榜",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/pointsAndRank/points",
+ "style": {
+ "navigationBarTitleText": "积分变动明细",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/pointsAndRank/rank",
+ "style": {
+ "navigationBarTitleText": "段位列表",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/pointsAndRank/badge",
+ "style": {
+ "navigationBarTitleText": "徽章列表",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
{
"path": "pages/course/index",
"style": {
diff --git a/src/pages/competition/index.vue b/src/pages/competition/index.vue
new file mode 100644
index 00000000..ac0b1980
--- /dev/null
+++ b/src/pages/competition/index.vue
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+ 竞赛练习
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.comName }}
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/competition/js/matching.ts b/src/pages/competition/js/matching.ts
new file mode 100644
index 00000000..213b1e23
--- /dev/null
+++ b/src/pages/competition/js/matching.ts
@@ -0,0 +1,64 @@
+/**
+ * 生成随机匹配时间
+ * 特点:同一时间段生成的时间会比较接近,时间范围可配置
+ */
+export const MatchTimeGenerator = (() => {
+ // 可配置的时间范围(毫秒)
+ const MIN_TIME = 2000; // 最小时间
+ const MAX_TIME = 6000; // 最大时间
+
+ // 时间窗口:100秒内生成的时间会基于同一基准(可根据需要调整)
+ const TIME_WINDOW = 100000;
+ // 同一窗口内的最大偏差(±1.5秒,可根据需要调整)
+ const MAX_DEVIATION = 1500;
+
+ // 记录上一次生成的基准时间和时间戳
+ let lastBaseTime = 0;
+ let lastTimestamp = 0;
+
+ return {
+ /**
+ * 生成匹配时间(毫秒)
+ * @returns {number} 介于MIN_TIME和MAX_TIME之间的随机数(毫秒)
+ */
+ generate() : number {
+ const now = Date.now();
+ let baseTime : number;
+
+ // 如果超过时间窗口或首次生成,重新计算基准时间
+ if (now - lastTimestamp > TIME_WINDOW || lastBaseTime === 0) {
+ // 生成MIN_TIME到MAX_TIME之间的基准时间(毫秒)
+ const timeRange = MAX_TIME - MIN_TIME;
+ baseTime = MIN_TIME + Math.floor(Math.random() * timeRange);
+ lastBaseTime = baseTime;
+ lastTimestamp = now;
+ } else {
+ // 在同一时间窗口内,基于上次基准时间生成偏差
+ baseTime = lastBaseTime;
+ }
+
+ // 生成偏差值(-MAX_DEVIATION 到 MAX_DEVIATION)
+ const deviation = Math.floor(Math.random() * (MAX_DEVIATION * 2 + 1)) - MAX_DEVIATION;
+ let matchTime = baseTime + deviation;
+
+ // 确保结果在配置的范围内
+ matchTime = Math.max(MIN_TIME, Math.min(MAX_TIME, matchTime));
+
+ return matchTime;
+ },
+
+ /**
+ * 生成匹配时间(秒)
+ * @returns {number} 介于MIN_TIME/1000和MAX_TIME/1000之间的随机数(秒,保留一位小数)
+ */
+ generateInSeconds() : number {
+ return Math.round(this.generate() / 100) / 10;
+ }
+ };
+})();
+
+export const formatTime = (seconds : number) => {
+ const m = Math.floor(seconds / 60);
+ const s = seconds % 60;
+ return [m.toString().padStart(2, '0'), s.toString().padStart(2, '0')].join(':');
+};
\ No newline at end of file
diff --git a/src/pages/competition/js/random_avatar.ts b/src/pages/competition/js/random_avatar.ts
new file mode 100644
index 00000000..e0875f68
--- /dev/null
+++ b/src/pages/competition/js/random_avatar.ts
@@ -0,0 +1,69 @@
+import AvatarW1 from '@/static/images/competition/avatar/f_1.jpg'
+import AvatarW2 from '@/static/images/competition/avatar/f_2.jpg'
+import AvatarW3 from '@/static/images/competition/avatar/f_3.jpg'
+import AvatarW4 from '@/static/images/competition/avatar/f_4.jpg'
+import AvatarM1 from '@/static/images/competition/avatar/m_1.jpg'
+import AvatarM2 from '@/static/images/competition/avatar/m_2.jpg'
+import AvatarM3 from '@/static/images/competition/avatar/m_3.jpg'
+import AvatarM4 from '@/static/images/competition/avatar/m_4.jpg'
+import AvatarS1 from '@/static/images/competition/avatar/s_1.jpg'
+import AvatarS2 from '@/static/images/competition/avatar/s_2.jpg'
+import AvatarS3 from '@/static/images/competition/avatar/s_3.jpg'
+import AvatarS4 from '@/static/images/competition/avatar/s_4.jpg'
+
+// 定义头像类型
+type AvatarType = 'f' | 'm' | 's';
+
+// 按类型分组
+const avatarsByType = {
+ f: [AvatarW1, AvatarW2, AvatarW3, AvatarW4],
+ m: [AvatarM1, AvatarM2, AvatarM3, AvatarM4],
+ s: [AvatarS1, AvatarS2, AvatarS3, AvatarS4]
+};
+
+/**
+ * 随机获取头像
+ * @param type1 第一个头像类型(可选)
+ * @param type2 第二个头像类型(可选,传入则返回2个头像)
+ * @returns 单个头像路径(当只传type1或都不传时)或两个头像路径的数组(当传入type2时)
+ */
+export default function getRandomAvatars(
+ type1 ?: AvatarType,
+ type2 ?: AvatarType
+) {
+ // 随机获取指定类型的头像
+ const getRandomAvatar = (type ?: AvatarType) => {
+ // 如果指定了类型且有效,则从该类型中选择
+ if (type && avatarsByType[type]) {
+ const avatars = avatarsByType[type];
+ return avatars[Math.floor(Math.random() * avatars.length)];
+ }
+
+ // 否则从所有头像中随机选择
+ const allAvatars = [
+ ...avatarsByType.f,
+ ...avatarsByType.m,
+ ...avatarsByType.s
+ ];
+ return allAvatars[Math.floor(Math.random() * allAvatars.length)];
+ };
+
+ // 只传type1或都不传时,返回1个头像
+ if (type2 === undefined) {
+ return getRandomAvatar(type1);
+ }
+
+ // 传入type2时,返回2个头像
+ const avatar1 = getRandomAvatar(type1);
+ let avatar2;
+
+ // 当两个类型相同时,确保头像不重复
+ if (type1 && type1 === type2) {
+ const sameTypeAvatars = avatarsByType[type1].filter(avatar => avatar !== avatar1);
+ avatar2 = sameTypeAvatars[Math.floor(Math.random() * sameTypeAvatars.length)];
+ } else {
+ avatar2 = getRandomAvatar(type2);
+ }
+
+ return [avatar1, avatar2];
+}
\ No newline at end of file
diff --git a/src/pages/competition/js/tool.js b/src/pages/competition/js/tool.js
new file mode 100644
index 00000000..4ea1d197
--- /dev/null
+++ b/src/pages/competition/js/tool.js
@@ -0,0 +1,20 @@
+export function formatSecondsToMS(seconds) {
+
+ // 尝试将输入转换为数字(处理字符串类型的数字)
+ const num = Number(seconds);
+
+ // 处理无效输入(转换失败、非数字、负数)
+ if (isNaN(num) || num < 0) {
+ return '0-秒';
+ }
+
+ // 计算分钟(不进位,直接取整)
+ const minutes = Math.floor(num / 60);
+ // 计算剩余秒数(取整)
+ const remainingSeconds = Math.floor(num % 60);
+ if (minutes === 0) {
+ return `${remainingSeconds}秒`;
+ }
+ // 拼接结果
+ return `${minutes}分${remainingSeconds}秒`;
+}
\ No newline at end of file
diff --git a/src/pages/competition/matching.vue b/src/pages/competition/matching.vue
new file mode 100644
index 00000000..5cbb2dde
--- /dev/null
+++ b/src/pages/competition/matching.vue
@@ -0,0 +1,337 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ data_info.isAnony === 'N' ? '不匿名' : '匿名' }}
+
+
+
+ 规则说明
+
+
+
+ 排行榜
+
+
+
+ {{ data_info.comName }}
+
+ 匹配中...
+
+
+
+
+
+
+
+ {{ data_info.isAnony === 'N' ? data_info.userName : '匿名' }}
+
+
+
+ {{ data_info.orgName }}
+
+
+ *选择机构后,会根据机构进行人员随机匹配挑战
+
+
+
+
+ {{ formatTime(practiceTime) }}
+
+
+
+ {{ challengeLoading ? '取消匹配' : '开始挑战' }}
+
+
+
+
+
+
+
+ 匹配成功
+
+
+
+
+
+
+
+
+
+ {{ data_info.isAnony === 'N' ? data_info.userName : '匿名' }}
+
+
+ {{ data_info.isAnony === 'N' ? data_info.orgIdName : '机构不显示' }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ data_info.pkIsAnony === 'N' ? data_info.pkUserName : '匿名' }}
+
+
+ {{ data_info.pkIsAnony === 'N' ? data_info.pkOrgIdName : '机构不显示' }}
+
+
+
+
+ 准备!
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/competition/pk.vue b/src/pages/competition/pk.vue
new file mode 100644
index 00000000..6fb7c603
--- /dev/null
+++ b/src/pages/competition/pk.vue
@@ -0,0 +1,803 @@
+
+
+
+
+ PK中
+
+
+
+
+
+
+
+
+
+
+
+ {{ pkData.isAnony === 'N' ? pkData.userName : '匿名' }}
+
+
+ 分数
+ {{ ourScore }}
+
+
+ 分数
+ {{ opponentScore }}
+
+
+
+
+
+
+ {{ pkData.pkIsAnony === 'N' ? pkData.pkUserName : '匿名' }}
+
+
+
+
+
+
+ {{ questionNumber + 1 }}
+ /{{ topicList.length }}
+
+
+
+ {{ formatSeconds(practiceRemainingTime) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 已答对
+ {{ correctQuestions.length }}
+ 题
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/competition/ranking.vue b/src/pages/competition/ranking.vue
new file mode 100644
index 00000000..44c88751
--- /dev/null
+++ b/src/pages/competition/ranking.vue
@@ -0,0 +1,399 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 欲穷千里目,更上一层楼
+
+
+
+
+
+
+
+ {{ item.ranking }}
+
+
+
+
+
+
+ {{ item.userName }}
+ {{ item.orgName }}
+
+ {{ item.examGrade }}
+ {{ item.time ?? 0 }}s
+
+ 暂无数据
+
+
+
+
+
+
+ {{ userRankObj.ranking }}
+
+
+
+
+
+
+ {{ userRankObj.userName }}
+ {{ userRankObj.orgName }}
+
+ {{ userRankObj.examGrade }}
+ {{ userRankObj.time }}s
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/competition/result.vue b/src/pages/competition/result.vue
new file mode 100644
index 00000000..8dc794a8
--- /dev/null
+++ b/src/pages/competition/result.vue
@@ -0,0 +1,586 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ pkData.userName }}
+ 正确/总题数
+
+ {{ pkData.correctNub }}
+ /{{ pkData.qnsNub }}
+ 结算中
+
+ 总分
+
+ {{ pkData.totalScore }}
+ 结算中
+
+ 用时
+
+ {{ formatSecondsToMS(pkData.timeTaken) }}
+ 结算中
+
+
+
+
+
+
+
+ {{ pkData.userNamePk }}
+ 正确/总题数
+
+ {{ pkData.correctNubPk }}
+ /{{ pkData.qnsNubPk }}
+ 结算中
+
+ 总分
+
+ {{ pkData.totalScorePk }}
+ 结算中
+
+ 用时
+
+ {{ formatSecondsToMS(pkData.timeTakenPk) }}
+ 结算中
+
+
+
+
+ 查看排行榜
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/competition/style/matching-loading.scss b/src/pages/competition/style/matching-loading.scss
new file mode 100644
index 00000000..1f958557
--- /dev/null
+++ b/src/pages/competition/style/matching-loading.scss
@@ -0,0 +1,37 @@
+.match-time-div {
+ font-weight: 400;
+ font-size: 34rpx;
+ color: #ffffff;
+ line-height: 34rpx;
+ font-style: normal;
+ margin-bottom: 20rpx;
+ transition: opacity 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
+ opacity: 1; /* 初始显示状态 */
+ transform: translateY(0); /* 初始位置 */
+ &.hidden {
+ opacity: 0; /* 完全透明 */
+ transform: translateY(40rpx); /* 轻微上移增强淡出效果 */
+ pointer-events: none; /* 隐藏后不响应事件 */
+ height: 0; /* 可选:完全隐藏高度 */
+ overflow: hidden; /* 可选:隐藏溢出内容 */
+ }
+}
+.match-msg-div {
+ width: 100%;
+ height: 8vh;
+ font-weight: normal;
+ font-size: 72rpx;
+ color: #ffffff;
+ display: flex;
+ justify-content: center;
+ align-items: flex-end;
+ transition: opacity 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
+ opacity: 1; /* 初始显示状态 */
+ transform: translateY(0); /* 初始位置 */
+ &.hidden {
+ opacity: 0; /* 完全透明 */
+ transform: translateY(-40rpx); /* 轻微上移增强淡出效果 */
+ pointer-events: none; /* 隐藏后不响应事件 */
+ overflow: hidden; /* 可选:隐藏溢出内容 */
+ }
+}
diff --git a/src/pages/competition/style/matching-prelude.scss b/src/pages/competition/style/matching-prelude.scss
new file mode 100644
index 00000000..05758db2
--- /dev/null
+++ b/src/pages/competition/style/matching-prelude.scss
@@ -0,0 +1,334 @@
+.select-div {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+ transition: opacity 0.3s ease-out;
+ opacity: 1; /* 初始显示状态 */
+ &.hidden {
+ opacity: 0; /* 完全透明 */
+ pointer-events: none; /* 隐藏后不响应事件 */
+ height: 0; /* 可选:完全隐藏高度 */
+ overflow: hidden; /* 可选:隐藏溢出内容 */
+ }
+}
+.select-institution-msg-div {
+ width: calc(100% - 228rpx);
+ font-weight: 400;
+ font-size: 22rpx;
+ color: #ffffff;
+ line-height: 32rpx;
+ text-align: left;
+ font-style: normal;
+ opacity: 0.8;
+ padding-top: 18rpx;
+ padding-bottom: 18rpx;
+}
+
+.select-institution-div {
+ width: calc(100% - 228rpx);
+ height: 86rpx;
+ border: 1rpx solid transparent;
+ position: relative;
+ font-weight: 400;
+ font-size: 32rpx;
+ line-height: 86rpx;
+ text-align: center;
+ color: #ffffff;
+ background-color: rgba(0, 0, 0, 0.4);
+ z-index: 1;
+ overflow: hidden;
+ padding: 0 60rpx 0 20rpx;
+ white-space: nowrap;
+ /* 强制不换行 */
+ overflow: hidden;
+ /* 超出部分隐藏 */
+ text-overflow: ellipsis;
+ .img {
+ // background-color: red;
+ padding: 16rpx;
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ right: 10rpx;
+ width: 30rpx;
+ height: 30rpx;
+ }
+}
+
+/* 边框高光效果 */
+.select-institution-div::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ border: 4rpx solid transparent;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.8), transparent) border-box;
+ -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+
+ /* 初始位置在左侧外部 */
+ background-size: 200% 100%;
+
+ /* 动画:高光从左到右流动 */
+ animation: highlightFlow 4s linear infinite;
+}
+
+/* 定义高光流动动画 */
+@keyframes highlightFlow {
+ 0% {
+ background-position: -100% 0;
+ }
+ 100% {
+ background-position: 100% 0;
+ }
+}
+
+/* 环绕版本带呼吸效果 */
+.select-institution-div.full-flow::before {
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(255, 255, 255, 0.8),
+ transparent,
+ transparent,
+ transparent,
+ transparent,
+ transparent,
+ transparent
+ );
+ background-size: 300% 300%;
+ animation: fullBorderFlow 2s linear infinite, breathing 1s ease-in-out infinite;
+}
+
+@keyframes fullBorderFlow {
+ 0% {
+ background-position: 0 0;
+ }
+ 25% {
+ background-position: 100% 0;
+ }
+ 50% {
+ background-position: 100% 100%;
+ }
+ 75% {
+ background-position: 0 100%;
+ }
+ 100% {
+ background-position: 0 0;
+ }
+}
+
+.title-div {
+ width: calc(100% - 80rpx);
+ margin: 40rpx;
+ font-size: 32rpx;
+ font-weight: 500;
+ color: #ffffff;
+ line-height: 44rpx;
+ text-shadow: 0px 0px 19px rgba(0, 0, 0, 0.11);
+ text-align: center;
+ font-family: none;
+ min-height: 88rpx;
+ margin: calc(var(--status-bar-height) + 40rpx);
+
+ /* 添加过渡动画 */
+ transition: opacity 0.3s ease-out, transform 0.3s ease-out;
+ opacity: 1; /* 初始显示状态 */
+ transform: translateY(0); /* 初始位置 */
+ &.hidden {
+ opacity: 0; /* 完全透明 */
+ transform: translateY(-10rpx); /* 轻微上移增强淡出效果 */
+ pointer-events: none; /* 隐藏后不响应事件 */
+ height: 0; /* 可选:完全隐藏高度 */
+ overflow: hidden; /* 可选:隐藏溢出内容 */
+ }
+}
+
+.avatar-div {
+ margin-top: 20rpx;
+ .avatar-img-div {
+ width: 204rpx;
+ height: 204rpx;
+ border: 4rpx solid #ffffff;
+ border-radius: 50%;
+ position: relative;
+ overflow: visible;
+ /* 修复伪元素显示问题 */
+ &.hidden::before {
+ content: '';
+ position: absolute;
+ /* 使用固定尺寸确保计算正确 */
+ width: 230rpx;
+ height: 230rpx;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ /* 确保在z轴上处于正确层级 */
+ z-index: 1;
+ /* 背景图设置 */
+ background-image: url('@/static/images/competition/avatar_surround.png');
+ background-size: contain; /* 改用contain确保完整显示 */
+ background-repeat: no-repeat;
+ background-position: center;
+ /* 旋转动画 */
+ animation: variableRotate 2s linear infinite;
+ }
+ .img {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ position: relative;
+ z-index: 2;
+ overflow: hidden;
+ }
+ }
+
+ @keyframes variableRotate {
+ 0% {
+ transform: translate(-50%, -50%) rotate(0deg);
+ }
+ 100% {
+ transform: translate(-50%, -50%) rotate(360deg);
+ }
+ }
+
+ .avatar-name-div {
+ font-weight: 600;
+ font-size: 46rpx;
+ color: #ffffff;
+ line-height: 64rpx;
+ text-align: center;
+ font-style: normal;
+ padding-top: 16rpx;
+ padding-bottom: 16rpx;
+ }
+}
+.button-div {
+ .start_button {
+ width: 569rpx;
+ height: 92rpx;
+ background: linear-gradient(#009fff 0%, #0066ff 100%);
+ border-radius: 58rpx;
+ font-weight: 500;
+ font-size: 30rpx;
+ color: #ffffff;
+ line-height: 92rpx;
+ text-align: center;
+ margin-top: 250rpx;
+ }
+ .cancel_button {
+ width: 246rpx;
+ height: 92rpx;
+ border-radius: 58rpx;
+ font-weight: 500;
+ font-size: 30rpx;
+ color: #ffffff;
+ line-height: 92rpx;
+ text-align: center;
+ background: rgba(0, 0, 0, 0.5);
+ background: linear-gradient(rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.5) 100%);
+ border-radius: 58rpx;
+ border: 2rpx solid #dbdbdb;
+ margin-bottom: 250rpx; /* 向上移动50rpx,可根据需要调整 */
+ }
+ .button-transition {
+ /* 添加过渡动画属性 */
+ transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+ /* 确保边框变化也有过渡效果 */
+ box-sizing: border-box;
+ }
+}
+
+.top-button-div {
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ height: 70rpx;
+ padding-top: calc(16rpx + var(--status-bar-height));
+ font-weight: 500;
+ position: relative;
+ margin-right: 10rpx;
+ .top-icon-div {
+ display: flex;
+ align-items: center;
+ margin-right: 30rpx;
+ font-weight: 400;
+ font-size: 26rpx;
+ color: #ffffff;
+ text-align: left;
+ .img1,
+ .img3 {
+ width: 40rpx;
+ height: 40rpx;
+ margin-right: 6rpx;
+ }
+ .img2 {
+ width: 30rpx;
+ height: 30rpx;
+ margin-right: 6rpx;
+ }
+ }
+ .back_div {
+ position: absolute;
+ left: 26rpx;
+ height: 34rpx;
+ top: calc(10rpx + var(--status-bar-height));
+ .back-icon {
+ position: relative;
+ width: 50rpx;
+ height: 50rpx;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ }
+
+ .back-icon::before,
+ .back-icon::after {
+ content: '';
+ position: absolute;
+ transition: all 0.3s ease;
+ }
+
+ .back-icon::after {
+ top: 25%;
+ left: 25%;
+ width: 40%;
+ height: 40%;
+ border-top: 4rpx solid #ffffff;
+ border-left: 4rpx solid #ffffff;
+ transform: rotate(-45deg);
+ }
+ }
+}
+
+.popup {
+ z-index: 1800;
+ padding: 0 38rpx;
+
+ .sheet_popup_div {
+ width: 100%;
+ height: 100%;
+ background-color: #ffffff;
+ padding: 10rpx 34rpx;
+ border-radius: 34rpx 34rpx 0px 0px;
+ position: relative;
+
+ .title_div {
+ width: 100%;
+ padding: 30rpx 0;
+ font-family: PingFangSC;
+ font-weight: 600;
+ font-size: 30rpx;
+ color: #000000;
+ font-style: normal;
+ border-bottom: 2rpx solid #efefef;
+ }
+ .note_div {
+ padding: 20rpx 0 80rpx 0;
+ }
+ }
+}
diff --git a/src/pages/competition/style/matching-success.scss b/src/pages/competition/style/matching-success.scss
new file mode 100644
index 00000000..e7bf1ebe
--- /dev/null
+++ b/src/pages/competition/style/matching-success.scss
@@ -0,0 +1,194 @@
+// 坠落动画配置变量 - 方便调整效果
+$fall-duration: 0.26s; // 动画总时长
+$initial-scale: 2.8; // 初始大小倍数
+$impact-scale: 0.9; // 撞击瞬间的压缩倍数
+$final-scale: 1; // 最终稳定大小
+$primary-color: #ffe271; // 文字颜色
+
+.matching-success-text {
+ margin-top: 10%;
+ padding-left: 1rem;
+ // 基础样式
+ font-size: 74rpx;
+ font-weight: bold;
+ color: #ffe271;
+ text-align: center;
+ // 动画属性
+ animation: fallDown $fall-duration ease-out forwards;
+
+ // 坠落动画关键帧
+ @keyframes fallDown {
+ 0% {
+ // 初始状态:高处坠落的起点
+ transform: scale($initial-scale);
+ opacity: 0.8;
+ }
+
+ 80% {
+ // 撞击瞬间:略微压缩,增强冲击力
+ transform: scale($impact-scale);
+ opacity: 1;
+ }
+
+ 100% {
+ // 稳定状态:恢复正常大小
+ transform: scale($final-scale);
+ opacity: 1;
+ }
+ }
+
+ // 增强版:带震动效果的撞击(可选)
+ &.with-vibration {
+ animation: fallWithVibration $fall-duration cubic-bezier(0.21, 0.98, 0.6, 0.99) forwards;
+
+ @keyframes fallWithVibration {
+ 0% {
+ transform: scale($initial-scale) rotate(0deg);
+ opacity: 0.8;
+ }
+
+ 70% {
+ transform: scale($impact-scale) rotate(2deg);
+ opacity: 1;
+ }
+
+ 85% {
+ transform: scale($final-scale * 1.05) rotate(-1deg);
+ opacity: 1;
+ }
+
+ 100% {
+ transform: scale($final-scale) rotate(0deg);
+ opacity: 1;
+ }
+ }
+ }
+}
+
+// 可通过修改变量快速调整效果
+// 示例:更重的坠落效果
+.heavy-impact {
+ $fall-duration: 0.3s;
+ $initial-scale: 2.5;
+ $impact-scale: 0.8;
+
+ animation: fallDown $fall-duration ease-out forwards;
+}
+
+.matching-success-msg {
+ margin-top: 20%;
+ font-family: Alibaba-PuHuiTi, Alibaba-PuHuiTi;
+ font-weight: normal;
+ font-size: 74rpx;
+ color: #ffffff;
+ font-weight: 700;
+ margin-bottom: 10%;
+}
+
+/**匹配成功样式*/
+.matching-success-animation {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ height: 540rpx;
+ position: relative;
+ // overflow: hidden;
+ .left {
+ position: absolute;
+ width: calc(59vw);
+ left: -10rpx;
+ top: 0%;
+ z-index: 3;
+ }
+ .right {
+ position: absolute;
+ right: -10rpx;
+ top: 18vw;
+ width: calc(59vw);
+ z-index: 2;
+ }
+ .img {
+ width: 100%;
+ }
+ // 左侧元素回弹动画
+ .animate-left {
+ animation: leftCollision 0.24s ease-out forwards;
+ }
+ @keyframes leftCollision {
+ 0% {
+ transform: translateX(-100%);
+ } // 初始位置
+ 90% {
+ transform: translateX(10rpx);
+ } // 超过目标位置10rpx(冲刺)
+ 100% {
+ transform: translateX(0);
+ } // 回到目标位置(回弹)
+ }
+
+ // 右侧元素回弹动画
+ .animate-right {
+ animation: rightCollision 0.24s ease-out forwards;
+ }
+ @keyframes rightCollision {
+ 0% {
+ transform: translateX(100%);
+ } // 初始位置
+ 90% {
+ transform: translateX(-10rpx);
+ } // 超过目标位置10rpx(冲刺)
+ 100% {
+ transform: translateX(0);
+ } // 回到目标位置(回弹)
+ }
+
+ // 上面的双方头像
+ .information-div-left,
+ .information-div-right {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .avatar-img-div {
+ width: 120rpx;
+ height: 120rpx;
+ border: 4rpx solid #ffffff;
+ border-radius: 50%;
+ overflow: hidden;
+ .img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ .name {
+ font-size: 30rpx;
+ margin-top: 20rpx;
+ margin-bottom: 100rpx;
+ font-weight: 600;
+ font-size: 36rpx;
+ color: #ffffff;
+ }
+ .org {
+ font-weight: 400;
+ font-size: 30rpx;
+ color: #ffffff;
+ text-align: center;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: 160rpx;
+ }
+ }
+ .information-div-left {
+ position: absolute;
+ top: 0%;
+ left: 0%;
+ transform: translate(24%, -20%);
+ }
+ .information-div-right {
+ position: absolute;
+ right: 0%;
+ top: 0%;
+ transform: translate(-24%, -20%);
+ }
+}
diff --git a/src/pages/course/components/touchBtn.vue b/src/pages/course/components/touchBtn.vue
index fee712ec..03dddf4b 100644
--- a/src/pages/course/components/touchBtn.vue
+++ b/src/pages/course/components/touchBtn.vue
@@ -445,6 +445,7 @@
box-shadow: 0 8rpx 20rpx 0 rgba(0, 0, 0, 0.06);
text-align: center;
line-height: 92rpx;
+ font-size: 28rpx;
color: #000;
font-weight: 400;
position: relative;
diff --git a/src/pages/examination/components/dialog.vue b/src/pages/examination/components/dialog.vue
index a66bb3aa..64fd870e 100644
--- a/src/pages/examination/components/dialog.vue
+++ b/src/pages/examination/components/dialog.vue
@@ -9,6 +9,9 @@
{{ title }}
+
+ {{ msg }}
+
{{ item?.name || '' }}
@@ -25,12 +28,14 @@
dialogConfiguration: {
type: Object,
required: false
- }
+ },
+
});
const emit = defineEmits(['button_click']);
const title = ref('');
const html = ref('');
+ const msg = ref('');
const buttonList = ref([]);
const PopupRef = ref(null);
// 点击按钮
@@ -41,9 +46,10 @@
const close = () => PopupRef.value?.close();
const open = (dialogConfiguration) => {
// 解构赋值更清晰
- const { title: t, html: h, buttonList: bl = [] } = dialogConfiguration || props.dialogConfiguration || {};
+ const { title: t, html: h, msg: m, buttonList: bl = [] } = dialogConfiguration || props.dialogConfiguration || {};
title.value = t || '';
html.value = h || '';
+ msg.value = m || '';
buttonList.value = Array.isArray(bl) ? bl : [];
// 确保PopupRef存在再调用open
@@ -62,7 +68,7 @@
z-index: 1810;
width: 100%;
height: 100%;
- background-color: rgba(0, 0, 0, 0.9);
+ background-color: rgba(0, 0, 0, 0.5);
}
.popup_div {
diff --git a/src/pages/examination/components/feedback.vue b/src/pages/examination/components/feedback.vue
index d701c8ed..8aea1a9c 100644
--- a/src/pages/examination/components/feedback.vue
+++ b/src/pages/examination/components/feedback.vue
@@ -143,7 +143,7 @@
onUnmounted(() => {
removeListener();
});
-
+
const open = (qnsId) => {
feedbackInfo.qnsId = qnsId;
openFeedback(true);
diff --git a/src/pages/index/dialog.vue b/src/pages/index/dialog.vue
index 7b00709f..076a8526 100644
--- a/src/pages/index/dialog.vue
+++ b/src/pages/index/dialog.vue
@@ -1113,7 +1113,7 @@
height: calc(100% - 772rpx);
padding: 12rpx 24rpx;
box-sizing: border-box;
-
+ min-height: 300rpx;
.talking-scroll-list {
height: 100%;
}
diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue
index bc124d6d..e8de8d9b 100644
--- a/src/pages/index/index.vue
+++ b/src/pages/index/index.vue
@@ -138,7 +138,8 @@
考试中心
-
+
+
竞赛练习
diff --git a/src/pages/learningTasks/components/content-item.vue b/src/pages/learningTasks/components/content-item.vue
index 39afeb40..9fa7823b 100644
--- a/src/pages/learningTasks/components/content-item.vue
+++ b/src/pages/learningTasks/components/content-item.vue
@@ -1,5 +1,5 @@
-
+
已完成
@@ -10,15 +10,19 @@
{{ item.taskName }}
- 起止时间:{{ item.startTm?.substr(0, 10) }}至{{ item.endTm?.substr(0, 10) }}
+ 起止时间:
+ {{ item.startTm?.substr(0, 10) }}至{{ item.endTm?.substr(0, 10) }}
- 完成人数:{{ item.taskFinishSums ?? 0 }}/{{ item.taskSums ?? 0 }}
+ 完成人数:
+ {{ item.taskFinishSums ?? 0 }}/{{ item.taskSums ?? 0 }}
进度:
- {{ item.finishCrs ?? item.learnedNumber ?? 0 }}/{{ item.sumCrs ?? item.taskNumber ?? 0 }}门课程
+
+ {{ item.finishCrs ?? item.learnedNumber ?? 0 }}/{{ item.sumCrs ?? item.taskNumber ?? 0 }}门课程
+
@@ -37,26 +41,27 @@
});
const emit = defineEmits(['click_item']);
const item = computed(() => props.item);
- const getStatusClass = (isFinish) => {
+ const getStatusClass = (item) => {
// 01进行中、02已完成、03已超时
// if (isFinish === '00') return 'in_progress';
// if (isFinish === '01') return 'completed';
// return 'expired';
- if (isFinish === '02') return 'completed';
+ if (item.isFinish === '02') return 'completed';
+ if (item.isTimeOut === '02') return 'expired';
return 'expired';
};
// 跳转到详情
const click_item = (item) => {
- if(item.limitTyp === '02') {
- if(item.isTimeOut === '01') {
+ if (item.limitTyp === '02') {
+ if (item.isTimeOut === '01') {
return common.msg('任务未开始');
- } else if(item.isTimeOut === '02') {
+ } else if (item.isTimeOut === '02') {
return common.msg('任务已结束');
}
}
-
+
setPageCache('learning_tasks_details', item);
- common.navigateTo('/pages/learningTasks/details?taskId='+item.taskId);
+ common.navigateTo('/pages/learningTasks/details?taskId=' + item.taskId);
};
@@ -67,7 +72,6 @@
color: #0066ff;
background-color: #daf0ff;
}
-
.blod_color {
color: #0066ff;
}
@@ -89,11 +93,11 @@
// 已超时
.subscript {
color: #ffffff;
- background-color: #ef5705;
+ background-color: #999 !important;
}
.blod_color {
- color: #d70c18;
+ color: #333333;
}
}
.item {
diff --git a/src/pages/me/index.vue b/src/pages/me/index.vue
index 38dfea4d..c07533c9 100644
--- a/src/pages/me/index.vue
+++ b/src/pages/me/index.vue
@@ -32,37 +32,47 @@
src="/static/images/me/man.png"
>
+
+
+
+
+
+
工号:{{ user_info.loginName }}
-
-
+ 签到
-
+
我的积分
-
+
-
+
徽章墙
-
+
@@ -81,13 +91,13 @@
-
+
考试记录
-
+
AI陪练记录
@@ -101,7 +111,12 @@
-
+
+
+
+
diff --git a/src/pages/pointsAndRank/points.vue b/src/pages/pointsAndRank/points.vue
new file mode 100644
index 00000000..93d9ef54
--- /dev/null
+++ b/src/pages/pointsAndRank/points.vue
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+
+
+
+ 积分明细
+
+
+
+ 我的积分
+
+
+
+
+
+
+
+
+
+ 事项明细
+ 时间
+ 积分变化
+
+
+
+ {{ item.mattrDesc }}
+
+
+ {{ item.ctTime.substr(0, 16) }}
+
+
+ {{ item.changeValue }}
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/pointsAndRank/rank.vue b/src/pages/pointsAndRank/rank.vue
new file mode 100644
index 00000000..4289dc86
--- /dev/null
+++ b/src/pages/pointsAndRank/rank.vue
@@ -0,0 +1,257 @@
+
+
+
+
+
+
+
+
+
+ 积分段位说明
+
+
+
+
+
+ 当前段位:{{dataInfo.currentRankName}}
+
+ 我的累计积分:
+ {{dataInfo.currentPoints}}/{{dataInfo.countPoints}}
+
+
+
+
+
+
+
+
+
+
+
+
+ 段位
+ 积分范围
+ 标识
+
+
+
+ {{ item.rankName }}
+
+ {{ item.pointsStart }}~{{ item.pointsEnd }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/practice/index.vue b/src/pages/practice/index.vue
index be67ffb1..7b0a8d32 100644
--- a/src/pages/practice/index.vue
+++ b/src/pages/practice/index.vue
@@ -114,7 +114,7 @@
const storageTopicList = ref([]); // 所有题列表
const popup_input_bottom = ref('0px');
const questionNumber = ref(0); // 题号
- const systemInfo = uni.getSystemInfoSync();
+
const topic = computed({
get: () => topicList[questionNumber.value],
@@ -747,7 +747,7 @@
}
}
}
-
+
.main_div {
display: flex;
flex-direction: column;
diff --git a/src/pages/setting/index.vue b/src/pages/setting/index.vue
index 0b5bfb55..0abe8e10 100644
--- a/src/pages/setting/index.vue
+++ b/src/pages/setting/index.vue
@@ -67,16 +67,7 @@
const mascotName = computed(() => userInfo.value.mascotInfo?.mascotName || '');
const sexOptions = GENDER;
- const anonymousOptions = [
- {
- value: 'y',
- label: '是'
- },
- {
- value: 'n',
- label: '否'
- }
- ]; // 性别
+
// 去选择百禄
const gotoMascot = () => {
diff --git a/src/pagesA.json b/src/pagesA.json
index ee081f97..a6daa78c 100644
--- a/src/pagesA.json
+++ b/src/pagesA.json
@@ -123,7 +123,7 @@
"style": {
"navigationBarTitleText": "错题本",
"app-plus": {
- "titleNView": false
+ "titleNView": false
}
}
},
@@ -246,7 +246,79 @@
"titleNView": false
}
}
+ },
+ {
+ "path": "pages/competition/index",
+ "style": {
+ "navigationBarTitleText": "竞赛列表页",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/competition/matching",
+ "style": {
+ "navigationBarTitleText": "匹配页面",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/competition/pk",
+ "style": {
+ "navigationBarTitleText": "pk页面",
+ "disableSwipeBack": true,
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/competition/result",
+ "style": {
+ "navigationBarTitleText": "pk结果页面",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/competition/ranking",
+ "style": {
+ "navigationBarTitleText": "pk排行榜",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/pointsAndRank/points",
+ "style": {
+ "navigationBarTitleText": "积分变动明细",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/pointsAndRank/rank",
+ "style": {
+ "navigationBarTitleText": "段位列表",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
+ },
+ {
+ "path": "pages/pointsAndRank/badge",
+ "style": {
+ "navigationBarTitleText": "徽章墙",
+ "app-plus": {
+ "titleNView": false
+ }
+ }
}
-
]
}
\ No newline at end of file
diff --git a/src/pagesOther.json b/src/pagesOther.json
index ac8f95c7..e8cf31c7 100644
--- a/src/pagesOther.json
+++ b/src/pagesOther.json
@@ -3,11 +3,11 @@
{
"path": "pages/index/dialog",
"style": {
- "navigationBarTitleText": "AI问答",
- "app-plus": {
- "titleNView": false,
- "animationType": "fade-in"
- }
+ "navigationBarTitleText": "AI问答",
+ "app-plus": {
+ "titleNView": false,
+ "animationType": "fade-in"
+ }
}
},
{
diff --git a/src/static/images/competition/avatar_surround.png b/src/static/images/competition/avatar_surround.png
new file mode 100644
index 00000000..cd12d0b1
Binary files /dev/null and b/src/static/images/competition/avatar_surround.png differ
diff --git a/src/static/images/competition/bg.png b/src/static/images/competition/bg.png
new file mode 100644
index 00000000..c8b35ffa
Binary files /dev/null and b/src/static/images/competition/bg.png differ
diff --git a/src/static/images/competition/competition_default_avatar.png b/src/static/images/competition/competition_default_avatar.png
new file mode 100644
index 00000000..1660ff8c
Binary files /dev/null and b/src/static/images/competition/competition_default_avatar.png differ
diff --git a/src/static/images/competition/list_empty.png b/src/static/images/competition/list_empty.png
new file mode 100644
index 00000000..b197bdf8
Binary files /dev/null and b/src/static/images/competition/list_empty.png differ
diff --git a/src/static/images/competition/matching-success-left.png b/src/static/images/competition/matching-success-left.png
new file mode 100644
index 00000000..451fbb74
Binary files /dev/null and b/src/static/images/competition/matching-success-left.png differ
diff --git a/src/static/images/competition/matching-success-right.png b/src/static/images/competition/matching-success-right.png
new file mode 100644
index 00000000..68a5443a
Binary files /dev/null and b/src/static/images/competition/matching-success-right.png differ
diff --git a/src/static/images/competition/matching-success-text-2.png b/src/static/images/competition/matching-success-text-2.png
new file mode 100644
index 00000000..cc7602f1
Binary files /dev/null and b/src/static/images/competition/matching-success-text-2.png differ
diff --git a/src/static/images/competition/matching-success-text.png b/src/static/images/competition/matching-success-text.png
new file mode 100644
index 00000000..648c7020
Binary files /dev/null and b/src/static/images/competition/matching-success-text.png differ
diff --git a/src/static/images/competition/pk_bg_icon.png b/src/static/images/competition/pk_bg_icon.png
new file mode 100644
index 00000000..e64e4efa
Binary files /dev/null and b/src/static/images/competition/pk_bg_icon.png differ
diff --git a/src/static/images/competition/ranking/1@2x.png b/src/static/images/competition/ranking/1@2x.png
new file mode 100644
index 00000000..fcfe338c
Binary files /dev/null and b/src/static/images/competition/ranking/1@2x.png differ
diff --git a/src/static/images/competition/ranking/2@2x.png b/src/static/images/competition/ranking/2@2x.png
new file mode 100644
index 00000000..6912627b
Binary files /dev/null and b/src/static/images/competition/ranking/2@2x.png differ
diff --git a/src/static/images/competition/ranking/3@2x.png b/src/static/images/competition/ranking/3@2x.png
new file mode 100644
index 00000000..abb2f860
Binary files /dev/null and b/src/static/images/competition/ranking/3@2x.png differ
diff --git a/src/static/images/competition/ranking/ranking_bg.png b/src/static/images/competition/ranking/ranking_bg.png
new file mode 100644
index 00000000..a4e36345
Binary files /dev/null and b/src/static/images/competition/ranking/ranking_bg.png differ
diff --git a/src/static/images/competition/ranking/ranking_title.png b/src/static/images/competition/ranking/ranking_title.png
new file mode 100644
index 00000000..e6426924
Binary files /dev/null and b/src/static/images/competition/ranking/ranking_title.png differ
diff --git a/src/static/images/competition/result_bg.png b/src/static/images/competition/result_bg.png
new file mode 100644
index 00000000..4181ef18
Binary files /dev/null and b/src/static/images/competition/result_bg.png differ
diff --git a/src/static/images/competition/result_huosheng.png b/src/static/images/competition/result_huosheng.png
new file mode 100644
index 00000000..d1636c0c
Binary files /dev/null and b/src/static/images/competition/result_huosheng.png differ
diff --git a/src/static/images/competition/result_loading_mascot.png b/src/static/images/competition/result_loading_mascot.png
new file mode 100644
index 00000000..87d1c007
Binary files /dev/null and b/src/static/images/competition/result_loading_mascot.png differ
diff --git a/src/static/images/competition/result_loading_msg.png b/src/static/images/competition/result_loading_msg.png
new file mode 100644
index 00000000..b49369d2
Binary files /dev/null and b/src/static/images/competition/result_loading_msg.png differ
diff --git a/src/static/images/competition/result_pk_bg.png b/src/static/images/competition/result_pk_bg.png
new file mode 100644
index 00000000..d7b953d6
Binary files /dev/null and b/src/static/images/competition/result_pk_bg.png differ
diff --git a/src/static/images/competition/result_shengli.png b/src/static/images/competition/result_shengli.png
new file mode 100644
index 00000000..d02a1f8a
Binary files /dev/null and b/src/static/images/competition/result_shengli.png differ
diff --git a/src/static/images/competition/result_shibai.png b/src/static/images/competition/result_shibai.png
new file mode 100644
index 00000000..c18d305f
Binary files /dev/null and b/src/static/images/competition/result_shibai.png differ
diff --git a/src/static/images/me/sign-in-button-bg.png b/src/static/images/me/sign-in-button-bg.png
new file mode 100644
index 00000000..736d22e1
Binary files /dev/null and b/src/static/images/me/sign-in-button-bg.png differ
diff --git a/src/static/images/me/sign-in-button-bg2.png b/src/static/images/me/sign-in-button-bg2.png
new file mode 100644
index 00000000..555239e1
Binary files /dev/null and b/src/static/images/me/sign-in-button-bg2.png differ
diff --git a/src/static/images/pointsAndRank/badge-bg.png b/src/static/images/pointsAndRank/badge-bg.png
new file mode 100644
index 00000000..0c800a1a
Binary files /dev/null and b/src/static/images/pointsAndRank/badge-bg.png differ
diff --git a/src/static/images/pointsAndRank/badge-icon.png b/src/static/images/pointsAndRank/badge-icon.png
new file mode 100644
index 00000000..6dcf5b5e
Binary files /dev/null and b/src/static/images/pointsAndRank/badge-icon.png differ
diff --git a/src/static/images/pointsAndRank/badge-title-left.png b/src/static/images/pointsAndRank/badge-title-left.png
new file mode 100644
index 00000000..0e03e19d
Binary files /dev/null and b/src/static/images/pointsAndRank/badge-title-left.png differ
diff --git a/src/static/images/pointsAndRank/badge-title-right.png b/src/static/images/pointsAndRank/badge-title-right.png
new file mode 100644
index 00000000..ad3f1f7f
Binary files /dev/null and b/src/static/images/pointsAndRank/badge-title-right.png differ
diff --git a/src/static/images/pointsAndRank/badge-wheat-left.png b/src/static/images/pointsAndRank/badge-wheat-left.png
new file mode 100644
index 00000000..e70ccac7
Binary files /dev/null and b/src/static/images/pointsAndRank/badge-wheat-left.png differ
diff --git a/src/static/images/pointsAndRank/badge-wheat-right.png b/src/static/images/pointsAndRank/badge-wheat-right.png
new file mode 100644
index 00000000..88331a46
Binary files /dev/null and b/src/static/images/pointsAndRank/badge-wheat-right.png differ
diff --git a/src/static/images/pointsAndRank/bg.png b/src/static/images/pointsAndRank/bg.png
new file mode 100644
index 00000000..7bcccbf4
Binary files /dev/null and b/src/static/images/pointsAndRank/bg.png differ
diff --git a/src/types/global.d.ts b/src/types/global.d.ts
new file mode 100644
index 00000000..049d9855
--- /dev/null
+++ b/src/types/global.d.ts
@@ -0,0 +1,20 @@
+// 声明图片文件模块
+declare module '*.jpg' {
+ const src: string;
+ export default src;
+}
+
+declare module '*.jpeg' {
+ const src: string;
+ export default src;
+}
+
+declare module '*.png' {
+ const src: string;
+ export default src;
+}
+
+declare module '*.gif' {
+ const src: string;
+ export default src;
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..ae61526a
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ // Vue 项目常用配置(根据实际版本调整)
+ "moduleResolution": "NodeNext", // 或 "Node"
+ "module": "NodeNext", // 与 moduleResolution 保持一致
+ "target": "ES2022",
+ "jsx": "preserve",
+ "lib": ["ES2022", "DOM"],
+ "baseUrl": ".", // 表示以 tsconfig.json 所在目录为基准
+ "types": ["vue"], // 确保包含 vue 类型定义
+ "paths": {
+ "@/*": ["src/*"]
+ }
+ },
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
+}
\ No newline at end of file
diff --git a/vite.config.js b/vite.config.js
index 6f7b2c3d..e2ccf4bc 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,8 +1,14 @@
-import { defineConfig } from 'vite'
+import {
+ defineConfig
+} from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
-// https://vitejs.dev/config/
+import path from 'path'
export default defineConfig({
- plugins: [
- uni(),
- ],
-})
+ plugins: [uni()],
+ // 新增服务器配置,指定启动端口
+ server: {
+ port: 5174,
+ strictPort: true, // 可选:端口被占用时直接报错(避免自动切换端口)
+ open: false // 可选:启动后自动打开浏览器(按需开启)
+ }
+})
\ No newline at end of file