s
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# 启用严格模式,确保依赖版本一致
|
||||
strict-peer-dependencies=false
|
||||
|
||||
# 配置依赖安装目录(pnpm 特有,节省磁盘空间)
|
||||
store-dir=~/.pnpm-store
|
||||
|
||||
# 兼容 uniapp 对依赖的查找逻辑
|
||||
node-linker=hoisted
|
||||
|
||||
# 忽略废弃依赖警告
|
||||
ignore-deprecations=all
|
||||
|
||||
# 忽略对等依赖警告
|
||||
strict-peer-dependencies=false
|
||||
@@ -42,7 +42,7 @@
|
||||
<image class="img" src="@/static/images/pointsAndRank/badge-title-right.png" mode=""></image>
|
||||
</view>
|
||||
<view class="item-list-container">
|
||||
<view class="item" v-for="item in itemList.child">
|
||||
<view class="item" v-for="item in itemList.child" @click="showDetailed(item)">
|
||||
<view class="badge-img">
|
||||
<image-preview
|
||||
class="img"
|
||||
@@ -56,8 +56,32 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- </view> -->
|
||||
</z-paging>
|
||||
<uni-popup ref="popup" class="popup">
|
||||
<view class="popup-content" @touchmove.stop>
|
||||
<view class="fl1"></view>
|
||||
<view class="fl1"></view>
|
||||
<view class="max-div">
|
||||
<view class="points-img-div">
|
||||
<image-preview class="img" :src="detailedInfo.ossAddr" mode="widthFix"></image-preview>
|
||||
</view>
|
||||
<view class="points-title">{{ detailedInfo.badgeName }}</view>
|
||||
<view class="points-div select-institution-div">
|
||||
<view class="points-remark">{{ detailedInfo.remark }}</view>
|
||||
<view class="points-time">{{ detailedInfo.obtainTm }}</view>
|
||||
</view>
|
||||
<view class="points-button-div">
|
||||
<uv-button
|
||||
class="button"
|
||||
text="关闭"
|
||||
:custom-style="customStyle"
|
||||
@click="closeDetailed()"
|
||||
></uv-button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -68,29 +92,63 @@
|
||||
import useZpaging from '@/composables/useZpaging.js';
|
||||
import { queryRankWall } from '@/api/pointsAndRank.js';
|
||||
import { getUserInfo } from '@/common/common';
|
||||
const buttonColor = '';
|
||||
const customStyle = {
|
||||
background:"linear-gradient( 0deg, RGBA(8, 9, 4, 1) 0%, RGBA(100, 100, 100, .5) 100%)",
|
||||
color:'#fff',
|
||||
width: '290rpx',
|
||||
height: '100rpx',
|
||||
border: '4rpx solid #EEDA9B',
|
||||
borderRadius: '180rpx'
|
||||
}
|
||||
const popup = ref(null);
|
||||
const user_info = reactive({
|
||||
userName: '',
|
||||
userId: ''
|
||||
});
|
||||
const detailedInfo = ref({
|
||||
ossAddr: '',
|
||||
message: '',
|
||||
num: ''
|
||||
});
|
||||
const fetchFunction = (params) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
queryRankWall().then(({ body }) => {
|
||||
let originalData = body;
|
||||
// 处理逻辑:构建二维数组(外层分类列表 + 内层徽章列表)
|
||||
const twoDimensionalArray = [];
|
||||
// 遍历每个分类,生成二维数组的每一项
|
||||
Object.entries(originalData).forEach(([categoryKey, badgeArray]) => {
|
||||
// 构建外层列表项:包含 name 和子列表 badgeList
|
||||
const categoryItem = {
|
||||
name: categoryKey, // 第一维度的 name 是原始键
|
||||
child: badgeArray // 子列表:直接放入当前分类的所有徽章数据
|
||||
};
|
||||
// 将分类项加入二维数组
|
||||
twoDimensionalArray.push(categoryItem);
|
||||
const scoreRankBadges = originalData['积分段位徽章'];
|
||||
|
||||
// 2. 动态合并除“积分段位徽章”外的所有徽章数组
|
||||
const otherBadges = [];
|
||||
// 遍历原始数据的所有键
|
||||
Object.keys(originalData).forEach((key) => {
|
||||
// 排除固定键,其余全部合并
|
||||
if (key !== '积分段位徽章') {
|
||||
// 确保对应值是数组,避免非数组类型导致错误
|
||||
if (Array.isArray(originalData[key])) {
|
||||
otherBadges.push(...originalData[key]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// // 处理逻辑:构建二维数组(外层分类列表 + 内层徽章列表)
|
||||
// const twoDimensionalArray = [];
|
||||
// // 遍历每个分类,生成二维数组的每一项
|
||||
// Object.entries(originalData).forEach(([categoryKey, badgeArray]) => {
|
||||
// // 构建外层列表项:包含 name 和子列表 badgeList
|
||||
// const categoryItem = {
|
||||
// name: categoryKey, // 第一维度的 name 是原始键
|
||||
// child: badgeArray // 子列表:直接放入当前分类的所有徽章数据
|
||||
// };
|
||||
// // 将分类项加入二维数组
|
||||
// twoDimensionalArray.push(categoryItem);
|
||||
// });
|
||||
|
||||
uni.$emit('update_me_data', true);
|
||||
resolve({
|
||||
body: twoDimensionalArray
|
||||
body: [
|
||||
{ name: '段位徽章', child: scoreRankBadges },
|
||||
{ name: '节气徽章', child: otherBadges }
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -98,7 +156,16 @@
|
||||
const { pagingRef, queryList, data_list, search } = useZpaging({
|
||||
fetchFunction
|
||||
});
|
||||
|
||||
// 显示详细信息
|
||||
const showDetailed = (item) => {
|
||||
if(item.isOpen !== 'Y') return;
|
||||
detailedInfo.value = item;
|
||||
popup.value.open();
|
||||
};
|
||||
const closeDetailed = () => {
|
||||
popup.value.close();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
Object.assign(user_info, getUserInfo());
|
||||
pagingRef.value.reload();
|
||||
@@ -107,6 +174,33 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.popup {
|
||||
.popup-content {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 40rpx 0;
|
||||
background-color: rgba(0,0,0,.85);
|
||||
}
|
||||
.max-div {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-top: var(--status-bar-height);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.points-img-div {
|
||||
width: 420rpx;
|
||||
height: 420rpx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.main-div {
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
@@ -187,6 +281,7 @@
|
||||
gap: 40rpx; /* 调大间距(根据需要调整数值) */
|
||||
padding: 6vw;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
.item {
|
||||
/* 计算宽度:总宽度减去两倍间距后三等分(保证三列) */
|
||||
@@ -195,7 +290,6 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
.badge-img {
|
||||
width: calc(27vw - 14rpx); /* 基于父元素宽度计算,更适配 */
|
||||
height: calc(27vw - 14rpx);
|
||||
@@ -218,7 +312,6 @@
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
color: #e2d1cc;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,4 +378,76 @@
|
||||
background-repeat: no-repeat; /* 不重复平铺 */
|
||||
background-color: #fef1dd;
|
||||
}
|
||||
.points-title{
|
||||
font-weight: 400;
|
||||
font-size: 54rpx;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
margin: 20rpx 0 60rpx 0;
|
||||
}
|
||||
.points-button-div{
|
||||
margin-bottom: 200rpx;
|
||||
margin-top: 180rpx;
|
||||
.button{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.select-institution-div {
|
||||
position: relative;
|
||||
border-radius: 20rpx;
|
||||
width: 560rpx;
|
||||
height: 130rpx;
|
||||
padding: 12rpx 0;
|
||||
border: 2rpx solid #EEDA9B;
|
||||
background: linear-gradient(150deg, RGBA(86, 82, 73, 1), RGBA(17, 17, 17, .4)) border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
|
||||
.points-remark{
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
.points-time{
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 边框高光效果 */
|
||||
.select-institution-div2::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
border: 4rpx solid transparent;
|
||||
background: linear-gradient(90deg, transparent, RGBA(251, 231, 178, 1), transparent) border-box;
|
||||
-webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
border-radius: 20rpx;
|
||||
/* 初始位置在左侧外部 */
|
||||
background-size: 200% 100%;
|
||||
|
||||
/* 动画:高光从左到右流动 */
|
||||
animation: highlightFlow 20s linear infinite;
|
||||
}
|
||||
|
||||
/* 定义高光流动动画 */
|
||||
@keyframes highlightFlow {
|
||||
0% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
* 音频路由兼容方案(适配 H5/小程序/不支持 setAudioRoute 的设备)
|
||||
* @param {string} type - earpiece(听筒)/speaker(扬声器)
|
||||
*/
|
||||
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
const _this = this;
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
// 关闭通话
|
||||
const closeTalking = async () => {
|
||||
// todo 防抖
|
||||
common.show('', '挂断'+(isVideoStyle.value?'视频':'电话')+'将结束训练,是否确认?').then((res) => {
|
||||
common.show('', '挂断' + (isVideoStyle.value ? '视频' : '电话') + '将结束训练,是否确认?').then((res) => {
|
||||
if (res) {
|
||||
destroy(); // 走关闭销毁流程
|
||||
}
|
||||
@@ -113,7 +113,6 @@
|
||||
console.log('当前分贝', res);
|
||||
};
|
||||
|
||||
const targetTimestamp = ref(0);
|
||||
// 定时器实例
|
||||
let timer = null;
|
||||
|
||||
@@ -127,13 +126,15 @@
|
||||
return `${minutes}:${seconds.toString().padStart(2, '0')}`; // 秒补零
|
||||
};
|
||||
|
||||
const targetTimestamp = ref(0);
|
||||
// 计算属性:实时格式化剩余时间
|
||||
const formattedTime = ref(0);
|
||||
const formattedTime = ref('00:00');
|
||||
// 3. 更新剩余时间的核心方法
|
||||
const updateRemaining = () => {
|
||||
const now = Date.now();
|
||||
const diff = now - targetTimestamp.value;
|
||||
formattedTime.value = formatTime(Math.max(0, Math.floor(diff / 1000)));
|
||||
const seconds = Math.max(0, Math.floor(diff / 1000));
|
||||
formattedTime.value = formatTime(seconds);
|
||||
};
|
||||
|
||||
const onStartRecord = (body) => {
|
||||
@@ -143,7 +144,8 @@
|
||||
console.log('连接成功开始' + dataInfo.traInterTypDesc);
|
||||
isRecording.value = true;
|
||||
isVideo.value && talkCameraRef.value.startPreview();
|
||||
timer = setInterval(updateRemaining, 1000);
|
||||
if (timer) clearInterval(timer); // 清除旧的定时器,避免多个定时器叠加
|
||||
timer = setInterval(updateRemaining, 400);
|
||||
// 立即执行一次
|
||||
updateRemaining();
|
||||
talkMicrophoneRef.value.start({
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
const { defineConfig } = require('@vue/cli-service');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = defineConfig({
|
||||
// 基础路径(根据你的部署环境调整)
|
||||
publicPath: './',
|
||||
// 输出目录
|
||||
outputDir: 'dist',
|
||||
// 静态资源目录
|
||||
assetsDir: 'static',
|
||||
// 关闭 eslint 校验(可选,根据项目需求)
|
||||
lintOnSave: false,
|
||||
// webpack 配置
|
||||
configureWebpack: {
|
||||
// 配置路径别名(和 Vite 的 alias 功能一致)
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
'@/components': path.resolve(__dirname, 'src/components'),
|
||||
'@/utils': path.resolve(__dirname, 'src/utils')
|
||||
}
|
||||
},
|
||||
// 优化打包(可选)
|
||||
optimization: {
|
||||
minimizer: [
|
||||
// 已安装 terser,可配置压缩
|
||||
require('terser-webpack-plugin')({
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: process.env.NODE_ENV === 'production', // 生产环境移除 console
|
||||
drop_debugger: true // 移除 debugger
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
// 解决可能的依赖冲突
|
||||
resolve: {
|
||||
extensions: ['.vue', '.js', '.jsx', '.json'],
|
||||
fallback: {
|
||||
"crypto": require.resolve("crypto-js"),
|
||||
"text-encoding": require.resolve("text-encoding")
|
||||
}
|
||||
}
|
||||
},
|
||||
// 链式修改 webpack 配置
|
||||
chainWebpack: config => {
|
||||
// 处理 Vue 文件
|
||||
config.module
|
||||
.rule('vue')
|
||||
.test(/\.vue$/)
|
||||
.use('vue-loader')
|
||||
.loader('vue-loader')
|
||||
.end();
|
||||
|
||||
// 处理 SCSS(项目依赖了 sass,需配置 loader)
|
||||
config.module
|
||||
.rule('scss')
|
||||
.test(/\.scss$/)
|
||||
.use('sass-loader')
|
||||
.loader('sass-loader')
|
||||
.options({
|
||||
implementation: require('sass')
|
||||
})
|
||||
.end();
|
||||
},
|
||||
// 环境变量配置(适配你的多环境脚本)
|
||||
devServer: {
|
||||
// 开发服务器配置(如代理、端口等)
|
||||
port: 8080,
|
||||
open: true,
|
||||
proxy: {
|
||||
// 示例:配置接口代理(根据你的项目需求调整)
|
||||
'/api': {
|
||||
target: 'https://your-api-domain.com',
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '^/api': '' }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user