Merge branch 'main' of http://124.243.245.42:3000/sdz/ks-app-employment-service 素质测评合并
This commit is contained in:
36
package-lock.json
generated
36
package-lock.json
generated
@@ -1,6 +1,38 @@
|
|||||||
{
|
{
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"lockfileVersion": 1,
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"@dcloudio/uni-ui": "^1.5.11",
|
||||||
|
"dayjs": "^1.11.19",
|
||||||
|
"sm-crypto": "^0.3.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dcloudio/uni-ui": {
|
||||||
|
"version": "1.5.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dcloudio/uni-ui/-/uni-ui-1.5.11.tgz",
|
||||||
|
"integrity": "sha512-DBtk046ofmeFd82zRI7d89SoEwrAxYzUN3WVPm1DIBkpLPG5F5QDNkHMnZGu2wNrMEmGBjBpUh3vqEY1L3jaMw=="
|
||||||
|
},
|
||||||
|
"node_modules/dayjs": {
|
||||||
|
"version": "1.11.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
||||||
|
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="
|
||||||
|
},
|
||||||
|
"node_modules/jsbn": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
|
||||||
|
},
|
||||||
|
"node_modules/sm-crypto": {
|
||||||
|
"version": "0.3.13",
|
||||||
|
"resolved": "https://registry.npmmirror.com/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||||
|
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jsbn": "^1.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dcloudio/uni-ui": {
|
"@dcloudio/uni-ui": {
|
||||||
"version": "1.5.11",
|
"version": "1.5.11",
|
||||||
@@ -19,7 +51,7 @@
|
|||||||
},
|
},
|
||||||
"sm-crypto": {
|
"sm-crypto": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
"resolved": "https://registry.npmmirror.com/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||||
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"jsbn": "^1.1.0"
|
"jsbn": "^1.1.0"
|
||||||
|
|||||||
@@ -21,15 +21,25 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="companyinfo-right">
|
<view class="companyinfo-right">
|
||||||
<view class="row1">{{ companyInfo?.companyName }}</view>
|
<view class="row1">{{ companyInfo?.companyName }}</view>
|
||||||
<view class="row2">
|
<view class="row2" v-if="companyInfo?.industry || companyInfo?.scale">
|
||||||
{{ companyInfo?.scale }}
|
<dict-tree-Label
|
||||||
|
v-if="companyInfo?.industry"
|
||||||
|
dictType="industry"
|
||||||
|
:value="companyInfo?.industry"
|
||||||
|
></dict-tree-Label>
|
||||||
|
<span v-if="companyInfo?.industry && companyInfo?.scale"> · </span>
|
||||||
|
<dict-Label
|
||||||
|
v-if="companyInfo?.scale"
|
||||||
|
dictType="scale"
|
||||||
|
:value="companyInfo?.scale"
|
||||||
|
></dict-Label>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="conetent-info" :class="{ expanded: isExpanded }">
|
<view class="conetent-info" :class="{ expanded: isExpanded }">
|
||||||
<view class="info-title">公司介绍</view>
|
<view class="info-title">公司介绍</view>
|
||||||
<view class="info-desirption">{{
|
<view class="info-desirption">{{
|
||||||
companyInfo.companyIntroduction
|
companyInfo.description
|
||||||
}}</view>
|
}}</view>
|
||||||
<!-- <view class="info-title title2">公司地址</view>
|
<!-- <view class="info-title title2">公司地址</view>
|
||||||
<view class="locationCompany"></view> -->
|
<view class="locationCompany"></view> -->
|
||||||
@@ -46,32 +56,39 @@
|
|||||||
<view class="views">
|
<view class="views">
|
||||||
<view class="Detail-title"><text class="title">在招职位</text></view>
|
<view class="Detail-title"><text class="title">在招职位</text></view>
|
||||||
<template v-if="companyInfo.jobInfoList.length != 0">
|
<template v-if="companyInfo.jobInfoList.length != 0">
|
||||||
<view v-for="job in companyInfo.jobInfoList" :key="job.id">
|
<view v-for="job in companyInfo.jobInfoList" :key="job.jobId" class="job-card-wrapper">
|
||||||
<!-- @click="navTo(`/packageA/pages/post/post?jobId=${JSON.stringify(job)}`)" -->
|
<view class="cards" @click="navTo(`/packageA/pages/post/post?jobId=${job.jobId}`)">
|
||||||
<view class="cards" :style="getItemBackgroundStyle('bj2.png')">
|
<view class="card-header">
|
||||||
<view class="card-company">
|
<view class="card-title-row">
|
||||||
<text class="company">{{ job.jobTitle }}</text>
|
<text class="job-title">{{ job.jobTitle }}</text>
|
||||||
<view class="salary"> ¥{{ job.salaryRange }}/月 </view>
|
<view class="card-pay">
|
||||||
</view>
|
<view class="pay-text">
|
||||||
<view class="card-tags">
|
<text class="salary-amount">¥{{ formatSalary(job.minSalary, job.maxSalary) }}</text>
|
||||||
<view class="tag jy">
|
<text class="salary-unit">/月</text>
|
||||||
<image :src="`${baseUrl}/jobfair/jy.png`" mode=""></image>
|
</view>
|
||||||
{{ job.experienceRequirement }}
|
</view>
|
||||||
</view>
|
|
||||||
<view class="tag xl">
|
|
||||||
<image :src="`${baseUrl}/jobfair/xx.png`" mode=""></image>
|
|
||||||
{{ job.educationRequirement }}
|
|
||||||
</view>
|
|
||||||
<view class="tag yd" v-if="job.jobRequirement">
|
|
||||||
<image :src="`${baseUrl}/jobfair/lx-1.png`" mode=""></image>
|
|
||||||
{{ job.jobRequirement }}
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-companyName">
|
|
||||||
<image :src="`${baseUrl}/jobfair/hd.png`" mode=""></image>
|
|
||||||
{{ job.jobDescription }}
|
|
||||||
</view>
|
|
||||||
|
|
||||||
|
<view class="card-tags" v-if="job.experience || job.education">
|
||||||
|
<view class="tag tag-experience" v-if="job.experience">
|
||||||
|
<image class="tag-icon" :src="`${baseUrl}/jobfair/jy.png`" mode="aspectFit"></image>
|
||||||
|
<view class="tag-text">
|
||||||
|
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="tag tag-education" v-if="job.education">
|
||||||
|
<image class="tag-icon" :src="`${baseUrl}/jobfair/xx.png`" mode="aspectFit"></image>
|
||||||
|
<view class="tag-text">
|
||||||
|
<dict-Label dictType="education" :value="job.education"></dict-Label>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="card-location" v-if="job.jobLocation">
|
||||||
|
<image class="location-icon" src="/static/icon/point3.png" mode="aspectFit"></image>
|
||||||
|
<text class="location-text">{{ job.jobLocation }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -90,7 +107,7 @@ import config from "@/config.js";
|
|||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import useLocationStore from "@/stores/useLocationStore";
|
import useLocationStore from "@/stores/useLocationStore";
|
||||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||||
const { $api, navTo, vacanciesTo, navBack } = inject("globalFunction");
|
const { $api, navTo, vacanciesTo, navBack, parseQueryParams } = inject("globalFunction");
|
||||||
const isExpanded = ref(false);
|
const isExpanded = ref(false);
|
||||||
const pageState = reactive({
|
const pageState = reactive({
|
||||||
page: 0,
|
page: 0,
|
||||||
@@ -101,9 +118,16 @@ const pageState = reactive({
|
|||||||
});
|
});
|
||||||
const companyInfo = ref({
|
const companyInfo = ref({
|
||||||
jobInfoList: [],
|
jobInfoList: [],
|
||||||
|
companyName: '',
|
||||||
|
scale: '',
|
||||||
|
industry: '',
|
||||||
|
description: '',
|
||||||
|
isCollection: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const baseUrl = config.imgBaseUrl;
|
const baseUrl = config.imgBaseUrl;
|
||||||
|
const companyIdRef = ref(null);
|
||||||
|
|
||||||
const getItemBackgroundStyle = (imageName) => ({
|
const getItemBackgroundStyle = (imageName) => ({
|
||||||
backgroundImage: `url(${baseUrl}/jobfair/${imageName})`,
|
backgroundImage: `url(${baseUrl}/jobfair/${imageName})`,
|
||||||
backgroundSize: "100% 100%", // 覆盖整个容器
|
backgroundSize: "100% 100%", // 覆盖整个容器
|
||||||
@@ -111,14 +135,167 @@ const getItemBackgroundStyle = (imageName) => ({
|
|||||||
backgroundRepeat: "no-repeat",
|
backgroundRepeat: "no-repeat",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 获取公司详情
|
||||||
|
function getCompanyDetail(companyId) {
|
||||||
|
if (!companyId) {
|
||||||
|
console.error('companyId 不能为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试获取公司详情,如果接口不存在,可能公司详情会包含在职位数据中
|
||||||
|
$api.createRequest(`/app/company/${companyId}`).then((resData) => {
|
||||||
|
if (resData && resData.data) {
|
||||||
|
const data = resData.data;
|
||||||
|
companyInfo.value = {
|
||||||
|
...companyInfo.value,
|
||||||
|
...data,
|
||||||
|
companyName: data.name || data.companyName || data.company?.name || '',
|
||||||
|
scale: data.scale || data.company?.scale || '',
|
||||||
|
industry: data.industry || data.company?.industry || '',
|
||||||
|
description: data.description || data.companyIntroduction || data.introduction || data.company?.introduction || '',
|
||||||
|
isCollection: data.isCollection || false,
|
||||||
|
// 如果接口直接返回了职位列表,也设置进去
|
||||||
|
jobInfoList: data.jobInfoList || data.jobs || data.list || companyInfo.value.jobInfoList || []
|
||||||
|
};
|
||||||
|
console.log('companyInfo',companyInfo.value);
|
||||||
|
}
|
||||||
|
// 获取在招职位列表
|
||||||
|
getCompanyJobs(companyId);
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('获取公司详情失败:', error);
|
||||||
|
// 如果获取公司详情失败,尝试通过职位列表接口获取公司信息
|
||||||
|
// 或者直接获取职位列表
|
||||||
|
getCompanyJobs(companyId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取公司在招职位列表
|
||||||
|
function getCompanyJobs(companyId) {
|
||||||
|
if (!companyId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用正确的 API 路径:/app/company/job/{companyId}
|
||||||
|
$api.createRequest(`/app/company/job/${companyId}`, {}, 'GET').then((resData) => {
|
||||||
|
console.log('获取职位列表返回数据:', resData);
|
||||||
|
if (resData) {
|
||||||
|
// 优先检查 rows 字段(根据实际返回的数据结构)
|
||||||
|
if (resData.rows && Array.isArray(resData.rows)) {
|
||||||
|
companyInfo.value.jobInfoList = resData.rows;
|
||||||
|
}
|
||||||
|
// 如果返回的是数组
|
||||||
|
else if (Array.isArray(resData)) {
|
||||||
|
companyInfo.value.jobInfoList = resData;
|
||||||
|
}
|
||||||
|
// 如果返回的是对象,包含列表字段
|
||||||
|
else if (resData.data) {
|
||||||
|
if (Array.isArray(resData.data)) {
|
||||||
|
companyInfo.value.jobInfoList = resData.data;
|
||||||
|
} else if (resData.data.rows && Array.isArray(resData.data.rows)) {
|
||||||
|
companyInfo.value.jobInfoList = resData.data.rows;
|
||||||
|
} else if (resData.data.list && Array.isArray(resData.data.list)) {
|
||||||
|
companyInfo.value.jobInfoList = resData.data.list;
|
||||||
|
} else if (resData.data.jobInfoList && Array.isArray(resData.data.jobInfoList)) {
|
||||||
|
companyInfo.value.jobInfoList = resData.data.jobInfoList;
|
||||||
|
} else {
|
||||||
|
companyInfo.value.jobInfoList = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
companyInfo.value.jobInfoList = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
companyInfo.value.jobInfoList = [];
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('获取在招职位列表失败:', error);
|
||||||
|
companyInfo.value.jobInfoList = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
companyInfo.value = JSON.parse(options.job);
|
console.log('options',options);
|
||||||
console.log(companyInfo.value, "companyInfo.value");
|
let companyId = null;
|
||||||
|
|
||||||
|
// 优先从 options 中获取 companyId(小程序和 H5 都支持)
|
||||||
|
if (options && options.companyId) {
|
||||||
|
companyId = decodeURIComponent(options.companyId);
|
||||||
|
}
|
||||||
|
// 如果 options 中没有,尝试从 URL 解析(仅 H5 环境)
|
||||||
|
else {
|
||||||
|
// 使用 try-catch 包裹,避免在小程序环境中访问 window.location 报错
|
||||||
|
try {
|
||||||
|
// #ifdef H5
|
||||||
|
const params = parseQueryParams();
|
||||||
|
companyId = params.companyId;
|
||||||
|
// #endif
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('解析 URL 参数失败:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('companyId', companyId);
|
||||||
|
|
||||||
|
if (companyId) {
|
||||||
|
companyIdRef.value = companyId;
|
||||||
|
getCompanyDetail(companyId);
|
||||||
|
} else {
|
||||||
|
console.error('未获取到 companyId 参数');
|
||||||
|
// 如果参数名是 job,尝试兼容旧的方式
|
||||||
|
if (options && options.job) {
|
||||||
|
try {
|
||||||
|
const parsedData = JSON.parse(options.job);
|
||||||
|
if (parsedData.companyId) {
|
||||||
|
companyIdRef.value = parsedData.companyId;
|
||||||
|
getCompanyDetail(parsedData.companyId);
|
||||||
|
} else {
|
||||||
|
companyInfo.value = { ...companyInfo.value, ...parsedData };
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析 job 参数失败:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
// 仅在 H5 环境中从 URL 获取参数(小程序环境中 onShow 不会传递 URL 参数)
|
||||||
|
// #ifdef H5
|
||||||
|
try {
|
||||||
|
const params = parseQueryParams();
|
||||||
|
const companyId = params.companyId;
|
||||||
|
|
||||||
|
if (companyId && companyId !== companyIdRef.value) {
|
||||||
|
companyIdRef.value = companyId;
|
||||||
|
getCompanyDetail(companyId);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('onShow 中解析 URL 参数失败:', e);
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
});
|
});
|
||||||
|
|
||||||
function expand() {
|
function expand() {
|
||||||
isExpanded.value = !isExpanded.value;
|
isExpanded.value = !isExpanded.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 格式化薪资范围
|
||||||
|
function formatSalary(minSalary, maxSalary) {
|
||||||
|
if (minSalary && maxSalary) {
|
||||||
|
return `${minSalary}-${maxSalary}`;
|
||||||
|
} else if (minSalary) {
|
||||||
|
return `${minSalary}起`;
|
||||||
|
} else if (maxSalary) {
|
||||||
|
return `最高${maxSalary}`;
|
||||||
|
}
|
||||||
|
return '面议';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 截断文本,超过指定长度显示省略号
|
||||||
|
function truncateText(text, maxLength) {
|
||||||
|
if (!text) return '';
|
||||||
|
if (text.length <= maxLength) return text;
|
||||||
|
return text.substring(0, maxLength) + '...';
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
@@ -259,93 +436,135 @@ image {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cards {
|
.job-card-wrapper {
|
||||||
padding: 32rpx;
|
|
||||||
background: #FFFFFF;
|
|
||||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0, 0, 0, 0.04);
|
|
||||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
|
||||||
margin-top: 22rpx;
|
margin-top: 22rpx;
|
||||||
padding-bottom: 18rpx;
|
|
||||||
|
|
||||||
.card-company {
|
&:first-child {
|
||||||
display: flex;
|
margin-top: 0;
|
||||||
justify-content: space-between;
|
}
|
||||||
align-items: flex-start;
|
}
|
||||||
|
|
||||||
.company {
|
.cards {
|
||||||
font-weight: 600;
|
padding: 30rpx;
|
||||||
font-size: 32rpx;
|
background: #FFFFFF;
|
||||||
color: #333333;
|
box-shadow: 0rpx 2rpx 12rpx 0rpx rgba(0, 0, 0, 0.08);
|
||||||
}
|
border-radius: 24rpx;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
.salary {
|
&:active {
|
||||||
font-weight: 600;
|
transform: scale(0.98);
|
||||||
font-size: 28rpx;
|
box-shadow: 0rpx 1rpx 8rpx 0rpx rgba(0, 0, 0, 0.12);
|
||||||
color: #F83A3C;
|
|
||||||
white-space: nowrap;
|
|
||||||
line-height: 48rpx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-companyName {
|
.card-header {
|
||||||
font-weight: 400;
|
margin-bottom: 0;
|
||||||
font-size: 28rpx;
|
|
||||||
color: #fff;
|
.card-title-row {
|
||||||
margin-top: 23rpx;
|
display: flex;
|
||||||
display: flex;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
image{
|
gap: 20rpx;
|
||||||
width: 24rpx;
|
|
||||||
height: 24rpx;
|
.job-title {
|
||||||
margin-right: 8rpx;
|
flex: 1;
|
||||||
|
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||||
|
text-align: left;
|
||||||
|
word-break: break-all;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-pay {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.pay-text {
|
||||||
|
font-family: DIN-Medium;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #4C6EFB;
|
||||||
|
line-height: 45rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.salary-amount {
|
||||||
|
font-family: DIN-Medium;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #4C6EFB;
|
||||||
|
line-height: 45rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.salary-unit {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #4C6EFB;
|
||||||
|
margin-left: 4rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-tags {
|
.card-tags {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: 25rpx 0 35rpx;
|
gap: 10rpx;
|
||||||
image{
|
margin-top: 20rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
height: 30rpx;
|
||||||
|
padding: 6rpx 20rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
background: #F4F4F4;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #6C7282;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.tag-icon {
|
||||||
width: 24rpx;
|
width: 24rpx;
|
||||||
height: 24rpx;
|
height: 24rpx;
|
||||||
margin-right: 8rpx;
|
margin-right: 8rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.jy {
|
|
||||||
background: #D9EDFF;
|
|
||||||
color: #0086FF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xl {
|
.tag-text {
|
||||||
background: #FFF1D5;
|
line-height: 1;
|
||||||
color: #FF7F01;
|
}
|
||||||
}
|
|
||||||
.yd {
|
|
||||||
background: #FFD8D8;
|
|
||||||
color: #F83A3C;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag {
|
|
||||||
width: fit-content;
|
|
||||||
height: 30rpx;
|
|
||||||
border-radius: 4rpx;
|
|
||||||
padding: 6rpx 20rpx;
|
|
||||||
line-height: 30rpx;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 24rpx;
|
|
||||||
text-align: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-bottom {
|
.card-location {
|
||||||
margin-top: 32rpx;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
align-items: flex-start;
|
||||||
font-size: 28rpx;
|
margin-top: 20rpx;
|
||||||
color: #6C7282;
|
|
||||||
|
.location-icon {
|
||||||
|
width: 28rpx;
|
||||||
|
height: 28rpx;
|
||||||
|
margin-right: 4rpx;
|
||||||
|
margin-top: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-text {
|
||||||
|
flex: 1;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999999;
|
||||||
|
line-height: 25rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppLayout title="我的浏览" :show-bg-image="false" :use-scroll-view="false">
|
<AppLayout title="我的浏览" :show-bg-image="false" :use-scroll-view="false">
|
||||||
<template #headerleft>
|
|
||||||
<view class="btnback">
|
|
||||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
<view class="collection-content">
|
<view class="collection-content">
|
||||||
<view class="collection-search">
|
<view class="collection-search">
|
||||||
<view class="search-content">
|
<view class="search-content">
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppLayout title="我的收藏" :show-bg-image="false" :use-scroll-view="false">
|
<AppLayout title="我的收藏" :show-bg-image="false" :use-scroll-view="false">
|
||||||
<template #headerleft>
|
|
||||||
<view class="btn">
|
|
||||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
<view class="collection-content">
|
<view class="collection-content">
|
||||||
<view class="header">
|
<view class="header">
|
||||||
<view class="button-click" :class="{ active: type === 0 }" @click="changeType(0)">工作职位</view>
|
<view class="button-click" :class="{ active: type === 0 }" @click="changeType(0)">工作职位</view>
|
||||||
|
|||||||
@@ -16,25 +16,52 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 获取雷达图数据
|
||||||
|
function getRadarData() {
|
||||||
|
if (!props.value || !props.value.radarChart) {
|
||||||
|
// 如果没有数据,使用默认值0
|
||||||
|
const defaultRadarChart = {
|
||||||
|
skill: 0,
|
||||||
|
experience: 0,
|
||||||
|
education: 0,
|
||||||
|
salary: 0,
|
||||||
|
age: 0,
|
||||||
|
location: 0
|
||||||
|
};
|
||||||
|
const labels = ['学历', '年龄', '工作地', '技能', '工作经验', '期望薪资'];
|
||||||
|
const data = [defaultRadarChart.education, defaultRadarChart.age, defaultRadarChart.location,
|
||||||
|
defaultRadarChart.skill, defaultRadarChart.experience, defaultRadarChart.salary].map((item) => item * 0.05);
|
||||||
|
return { labels, data };
|
||||||
|
}
|
||||||
|
|
||||||
|
const { skill, experience, education, salary, age, location } = props.value.radarChart;
|
||||||
|
const labels = ['学历', '年龄', '工作地', '技能', '工作经验', '期望薪资'];
|
||||||
|
const data = [education, age, location, skill, experience, salary].map((item) => item * 0.05);
|
||||||
|
return { labels, data };
|
||||||
|
}
|
||||||
|
|
||||||
// 监听页面初始化
|
// 监听页面初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (Object.keys(props.value).length > 0) {
|
// 延迟执行,确保 canvas 已经渲染
|
||||||
rawRadarChart();
|
setTimeout(() => {
|
||||||
}
|
const { labels, data } = getRadarData();
|
||||||
|
rawRadarChart(labels, data);
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听 props.value 变化
|
// 监听 props.value 变化
|
||||||
watch(
|
watch(
|
||||||
() => props.value,
|
() => props.value,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal && Object.keys(newVal).length > 0) {
|
if (newVal) {
|
||||||
const { skill, experience, education, salary, age, location } = newVal.radarChart;
|
// 延迟执行,确保数据更新完成
|
||||||
const labels = ['学历', '年龄', '工作地', '技能', '工作经验', '期望薪资'];
|
setTimeout(() => {
|
||||||
const data = [education, age, location, skill, experience, salary].map((item) => item * 0.05);
|
const { labels, data } = getRadarData();
|
||||||
rawRadarChart(labels, data);
|
rawRadarChart(labels, data);
|
||||||
|
}, 50);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: false } // deep 递归监听对象内部变化
|
{ deep: true, immediate: true } // deep 递归监听对象内部变化,immediate 立即执行一次
|
||||||
);
|
);
|
||||||
|
|
||||||
function rawRadarChart(labels, data) {
|
function rawRadarChart(labels, data) {
|
||||||
|
|||||||
@@ -208,7 +208,20 @@ const jobInfo = ref({});
|
|||||||
const state = reactive({});
|
const state = reactive({});
|
||||||
const mapCovers = ref([]);
|
const mapCovers = ref([]);
|
||||||
const jobIdRef = ref();
|
const jobIdRef = ref();
|
||||||
const raderData = ref({});
|
// 竞争力分析数据,初始化为包含默认值的完整结构,确保雷达图能正常渲染
|
||||||
|
const raderData = ref({
|
||||||
|
matchScore: 0,
|
||||||
|
rank: 0,
|
||||||
|
percentile: 0,
|
||||||
|
radarChart: {
|
||||||
|
skill: 0,
|
||||||
|
experience: 0,
|
||||||
|
education: 0,
|
||||||
|
salary: 0,
|
||||||
|
age: 0,
|
||||||
|
location: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
const videoPalyerRef = ref(null);
|
const videoPalyerRef = ref(null);
|
||||||
const explainUrlRef = ref('');
|
const explainUrlRef = ref('');
|
||||||
|
|
||||||
@@ -246,10 +259,17 @@ onLoad((option) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
const option = parseQueryParams(); // 兼容微信内置浏览器
|
// 仅在 H5 环境中从 URL 获取参数(小程序环境中 onShow 不会传递 URL 参数)
|
||||||
if (option.jobId) {
|
// #ifdef H5
|
||||||
initLoad(option);
|
try {
|
||||||
|
const option = parseQueryParams(); // 兼容微信内置浏览器
|
||||||
|
if (option.jobId) {
|
||||||
|
initLoad(option);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('onShow 中解析 URL 参数失败:', e);
|
||||||
}
|
}
|
||||||
|
// #endif
|
||||||
});
|
});
|
||||||
|
|
||||||
function initLoad(option) {
|
function initLoad(option) {
|
||||||
@@ -317,8 +337,59 @@ function getTextWidth(text, size = 12) {
|
|||||||
|
|
||||||
function getCompetivetuveness(jobId) {
|
function getCompetivetuveness(jobId) {
|
||||||
$api.createRequest(`/app/job/competitiveness/${jobId}`, {}, 'GET').then((resData) => {
|
$api.createRequest(`/app/job/competitiveness/${jobId}`, {}, 'GET').then((resData) => {
|
||||||
raderData.value = resData.data;
|
// 如果接口返回的数据为 null 或空,使用默认值0
|
||||||
currentStep.value = resData.data.matchScore * 0.04;
|
if (resData && resData.data) {
|
||||||
|
// 确保 radarChart 字段存在,如果不存在则使用默认值
|
||||||
|
const radarChart = resData.data.radarChart || {
|
||||||
|
skill: 0,
|
||||||
|
experience: 0,
|
||||||
|
education: 0,
|
||||||
|
salary: 0,
|
||||||
|
age: 0,
|
||||||
|
location: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
raderData.value = {
|
||||||
|
matchScore: resData.data.matchScore || 0,
|
||||||
|
rank: resData.data.rank || 0,
|
||||||
|
percentile: resData.data.percentile || 0,
|
||||||
|
radarChart: radarChart
|
||||||
|
};
|
||||||
|
currentStep.value = (resData.data.matchScore || 0) * 0.04;
|
||||||
|
} else {
|
||||||
|
// 接口返回 null 或空数据时,使用默认值0
|
||||||
|
raderData.value = {
|
||||||
|
matchScore: 0,
|
||||||
|
rank: 0,
|
||||||
|
percentile: 0,
|
||||||
|
radarChart: {
|
||||||
|
skill: 0,
|
||||||
|
experience: 0,
|
||||||
|
education: 0,
|
||||||
|
salary: 0,
|
||||||
|
age: 0,
|
||||||
|
location: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
currentStep.value = 0;
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
// 接口请求失败时,使用默认值0
|
||||||
|
console.error('获取竞争力分析失败:', error);
|
||||||
|
raderData.value = {
|
||||||
|
matchScore: 0,
|
||||||
|
rank: 0,
|
||||||
|
percentile: 0,
|
||||||
|
radarChart: {
|
||||||
|
skill: 0,
|
||||||
|
experience: 0,
|
||||||
|
education: 0,
|
||||||
|
salary: 0,
|
||||||
|
age: 0,
|
||||||
|
location: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
currentStep.value = 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
<image src="../../../static/images/train/bj.jpg" class="bjImg" mode=""></image>
|
<image src="../../../static/images/train/bj.jpg" class="bjImg" mode=""></image>
|
||||||
<div class="con-box">
|
<div class="con-box">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div>正确率:0%</div>
|
<div>正确率:{{accuracyRate}}%</div>
|
||||||
<div>用时:00:00</div>
|
<div>用时:{{formattedTime}}</div>
|
||||||
<div class="headBtn">暂停</div>
|
<div class="headBtn" v-if="isRunning" @click="pause">暂停</div>
|
||||||
|
<div class="headBtn" v-if="!isRunning" @click="start">继续</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="problemCard">
|
<div class="problemCard">
|
||||||
<div v-for="(item,index) in problemData" :key="index">
|
<div v-for="(item,index) in problemData" :key="index">
|
||||||
@@ -37,15 +38,15 @@
|
|||||||
<span>错误</span>
|
<span>错误</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="analysis">
|
<div class="analysis" v-if="analysis">
|
||||||
<div class="analysisHead correct">
|
<div class="analysisHead correct" v-if="judgWhether=='正确'">
|
||||||
<div>回答正确!</div>
|
<div>回答正确!</div>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="analysisHead errors" v-if="judgWhether=='错误'">
|
<div class="analysisHead errors" v-if="judgWhether=='错误'">
|
||||||
<div>回答错误!</div>
|
<div>回答错误!</div>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div> -->
|
</div>
|
||||||
<div class="analysisCon">
|
<div class="analysisCon">
|
||||||
<div class="parse1">正确答案:</div>
|
<div class="parse1">正确答案:</div>
|
||||||
<div class="parse2" v-if="item.type=='single'" style="color: #30A0FF;font-weight: bold;">{{String.fromCharCode(65 + Number(item.answer))}}.</div>
|
<div class="parse2" v-if="item.type=='single'" style="color: #30A0FF;font-weight: bold;">{{String.fromCharCode(65 + Number(item.answer))}}.</div>
|
||||||
@@ -66,38 +67,38 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="problemBtns">
|
<div class="problemBtns">
|
||||||
<div class="events">提交答案</div>
|
<div v-if="analysis&&judgWhether!=''&&questionIndex!=problemData.length" @click="questionIndex.value+=1">下一题</div>
|
||||||
<div>下一题</div>
|
<div v-else :class="(radio==''&&radio2==''&&checkList.length==0&&isRunning)?'events':''">提交答案</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="footerLeft">
|
<div class="footerLeft">
|
||||||
<div class="zuo events"></div>
|
<div class="zuo" :class="questionIndex==1?'events':''" @click="questionIndex-=1"></div>
|
||||||
<div class="you"></div>
|
<div class="you" :class="questionIndex==problemData.length?'events':''" @click="questionIndex+=1"></div>
|
||||||
<div style="text-align: center;font-size: 24rpx;">
|
<div @click="collect(1)" style="text-align: center;font-size: 24rpx;" v-if="(problemData[questionIndex - 1]?.isCollect || 0)!=1">
|
||||||
<image :src="urls+'wsc.png'" mode=""></image>
|
<image :src="urls+'wsc.png'" mode="" style="width: 34rpx;height: 32rpx;"></image>
|
||||||
<div>收藏</div>
|
<div>收藏</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div style="text-align: center;font-size: 24rpx;">
|
<div @click="collect(0)" style="text-align: center;font-size: 24rpx;" v-if="(problemData[questionIndex - 1]?.isCollect || 0)==1">
|
||||||
<image :src="urls+'video-sc.png'" mode=""></image>
|
<image :src="urls+'video-sc.png'" mode="" style="width: 34rpx;height: 32rpx;"></image>
|
||||||
<div>取消</div>
|
<div>取消</div>
|
||||||
</div> -->
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footerBtn">完成练习</div>
|
<div class="footerBtn">完成练习</div>
|
||||||
<div class="footerLeft">
|
<div class="footerLeft">
|
||||||
<div>
|
<div>
|
||||||
<div class="icons" style="background-color: #1CADF5;">√</div>
|
<div class="icons" style="background-color: #1CADF5;">√</div>
|
||||||
<div class="texts" style="color: #1CADF5;">1</div>
|
<div class="texts" style="color: #1CADF5;">{{correctIndex}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="icons" style="background-color: #FF6668;">×</div>
|
<div class="icons" style="background-color: #FF6668;">×</div>
|
||||||
<div class="texts" style="color: #FF6668;">0</div>
|
<div class="texts" style="color: #FF6668;">{{errorsIndex}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div @click="dialogVisible=true">
|
||||||
<div></div>
|
<div><span style="color: #1CADF5;">{{questionIndex}}</span>/{{problemData.length}}</div>
|
||||||
<div></div>
|
<div>题号</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -108,18 +109,22 @@
|
|||||||
<div>题号</div>
|
<div>题号</div>
|
||||||
<div style="font-size: 40rpx;" @click="clones()">×</div>
|
<div style="font-size: 40rpx;" @click="clones()">×</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="questionNums">
|
||||||
|
<div class="questions" :class="item.whether=='正确'?'questionCorrect':item.whether=='错误'?'questionError':questionIndex==(index+1)?'questionsActive':''" @click="switchs(index)" v-for="(item,index) in problemList" :key="index">{{index+1}}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
import { reactive, inject, watch, ref, onMounted,onBeforeUnmount,computed } from 'vue';
|
||||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||||
const { $api,urls , navTo, vacanciesTo, formatTotal, config } = inject('globalFunction');
|
const { $api,urls , navTo, vacanciesTo, formatTotal, config } = inject('globalFunction');
|
||||||
import useUserStore from '@/stores/useUserStore';
|
import useUserStore from '@/stores/useUserStore';
|
||||||
import useDictStore from '@/stores/useDictStore';
|
import useDictStore from '@/stores/useDictStore';
|
||||||
|
const userInfo = ref({});
|
||||||
|
const Authorization = ref('');
|
||||||
const radio = ref('');
|
const radio = ref('');
|
||||||
const radio2 = ref('');
|
const radio2 = ref('');
|
||||||
const checkList = ref([]);
|
const checkList = ref([]);
|
||||||
@@ -127,30 +132,121 @@ const questionIndex = ref(1);
|
|||||||
const correctIndex = ref(0);
|
const correctIndex = ref(0);
|
||||||
const errorsIndex = ref(0);
|
const errorsIndex = ref(0);
|
||||||
const accuracyRate = ref(0);
|
const accuracyRate = ref(0);
|
||||||
const dialogVisible = ref(true);
|
const elapsedTime = ref(0);
|
||||||
const problemData = reactive([
|
const analysis = ref(false);
|
||||||
{
|
const judgWhether = ref('');
|
||||||
type:'single',
|
const isRunning = ref(false);
|
||||||
content:"君不见黄河之水天上来,下一句是?",
|
const dialogVisible = ref(false);
|
||||||
fraction:5,
|
const problemData = ref([]);
|
||||||
trainChooses:"奔流到海不复回,朝如青丝暮成雪,人生得意须尽欢,莫使金樽空对月",
|
const problemList = ref([]);
|
||||||
},{
|
let timer = null;
|
||||||
type:'multiple',
|
const formattedTime = computed(() => {
|
||||||
content:"以下哪些是欧姆定律的适用条件?",
|
const minutes = Math.floor(elapsedTime.value / 60)
|
||||||
fraction:8,
|
const seconds = elapsedTime.value % 60
|
||||||
trainChooses:"线性电阻,恒定温度,金属导体,半导体材料",
|
return `${padTime(minutes)}:${padTime(seconds)}`
|
||||||
|
});
|
||||||
|
watch(questionIndex, (newVal, oldVal) => {
|
||||||
|
radio.value=""
|
||||||
|
radio2.value=""
|
||||||
|
checkList.value=[]
|
||||||
|
analysis.value=false
|
||||||
|
judgWhether.value=""
|
||||||
|
});
|
||||||
|
|
||||||
},{
|
// watch(problemData, (newVal, oldVal) => {
|
||||||
type:'judge',
|
// problemList.value=[];
|
||||||
content:"功率越大的电器,其电阻值越小",
|
// newVal.forEach((item,i)=>{
|
||||||
fraction:2,
|
// problemList.value.push({index:i+1,whether:""})
|
||||||
trainChooses:[
|
// })
|
||||||
"正确",
|
// });
|
||||||
"错误",
|
|
||||||
]
|
onLoad((options) => {
|
||||||
|
userInfo.value = uni.getStorageSync('userInfo') || {};
|
||||||
|
Authorization.value=uni.getStorageSync('Padmin-Token')||''
|
||||||
|
queryData();
|
||||||
|
});
|
||||||
|
onShow(()=>{
|
||||||
|
|
||||||
|
})
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(timer); // 清除定时器
|
||||||
|
timer = null; // 防止内存泄漏,确保下次不会再误用已清除的定时器
|
||||||
|
}
|
||||||
|
});
|
||||||
|
function queryData(){
|
||||||
|
problemData.value=[]
|
||||||
|
let header={
|
||||||
|
'Authorization':Authorization.value,
|
||||||
|
'Content-Type':"application/x-www-form-urlencoded"
|
||||||
|
}
|
||||||
|
$api.myRequest('/train/public/trainPractice/getQuestions', {
|
||||||
|
userId: userInfo.value.userId
|
||||||
|
},'post',9100,header).then((resData) => {
|
||||||
|
resData.forEach((item,i)=>{
|
||||||
|
problemData.value.push(item)
|
||||||
|
problemList.value.push({index:i+1,whether:""})
|
||||||
|
})
|
||||||
|
start()
|
||||||
|
accuracyRates()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function collect(is){
|
||||||
|
let header={
|
||||||
|
'Authorization':Authorization.value,
|
||||||
|
'Content-Type':"application/x-www-form-urlencoded"
|
||||||
|
}
|
||||||
|
$api.myRequest('/train/public/questionUser/addOrUpdateCollect', {
|
||||||
|
userId: userInfo.value.userId,
|
||||||
|
questionId:problemData.value[this.questionIndex-1].questionId,
|
||||||
|
collect:is
|
||||||
|
},'post',9100,header).then((resData) => {
|
||||||
|
problemData.value[questionIndex.value-1].isCollect=is
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//正确率
|
||||||
|
function accuracyRates(){
|
||||||
|
let header={
|
||||||
|
'Authorization':Authorization.value,
|
||||||
|
'Content-Type':"application/x-www-form-urlencoded"
|
||||||
|
}
|
||||||
|
$api.myRequest('/train/public/trainPractice/getCount', {
|
||||||
|
userId: userInfo.value.userId,
|
||||||
|
},'post',9100,header).then((resData) => {
|
||||||
|
// debugger
|
||||||
|
// accuracyRate.value=resData.truePresent
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//提交答案
|
||||||
|
function submit(){
|
||||||
|
let indexs=questionIndex.value-1
|
||||||
|
let parm={
|
||||||
|
questionId:problemData.value[indexs].questionId,
|
||||||
|
userId:userInfo.value.userId,
|
||||||
|
answer:this.problemData.value[indexs].answer
|
||||||
|
}
|
||||||
|
if(problemData.value[indexs].type=='single'){
|
||||||
|
parm.submitAnswer=radio.value
|
||||||
|
}else if(this.problemData[indexs].type=='multiple'){
|
||||||
|
parm.submitAnswer=this.checkList.join(',')
|
||||||
|
}else if(this.problemData[indexs].type=='judge'){
|
||||||
|
parm.submitAnswer=this.radio2
|
||||||
|
}
|
||||||
|
startTrainingApi.submitAnswer(parm).then((res)=>{
|
||||||
|
|
||||||
|
if(res&&res.code==200){
|
||||||
|
this.analysis=true
|
||||||
|
this.judgWhether=res.msg
|
||||||
|
this.problemList[indexs].whether=res.msg
|
||||||
|
if(res.msg=='正确'){
|
||||||
|
this.correctIndex++
|
||||||
|
}else if(res.msg=='错误'){
|
||||||
|
this.errorsIndex++
|
||||||
|
}
|
||||||
|
this.accuracyRates()
|
||||||
}
|
}
|
||||||
]);
|
})
|
||||||
|
};
|
||||||
function selected(i){
|
function selected(i){
|
||||||
radio.value=i
|
radio.value=i
|
||||||
};
|
};
|
||||||
@@ -194,9 +290,28 @@ function indexToLetter(index) {
|
|||||||
// 将索引转换为对应的字母
|
// 将索引转换为对应的字母
|
||||||
return String.fromCharCode(65 + index);
|
return String.fromCharCode(65 + index);
|
||||||
};
|
};
|
||||||
|
function padTime(time) {
|
||||||
|
return time < 10 ? `0${time}` : time
|
||||||
|
};
|
||||||
|
function start() {
|
||||||
|
if (isRunning.value) return
|
||||||
|
isRunning.value = true
|
||||||
|
timer = setInterval(() => {
|
||||||
|
elapsedTime.value++
|
||||||
|
}, 1000)
|
||||||
|
};
|
||||||
|
function pause() {
|
||||||
|
if (!isRunning.value) return
|
||||||
|
clearInterval(timer)
|
||||||
|
isRunning.value = false
|
||||||
|
};
|
||||||
function clones(){
|
function clones(){
|
||||||
dialogVisible.value=false
|
dialogVisible.value=false
|
||||||
}
|
};
|
||||||
|
function switchs(i){
|
||||||
|
questionIndex.value=(i+1)
|
||||||
|
dialogVisible.value=false
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
@@ -358,20 +473,20 @@ function clones(){
|
|||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
text-align: center
|
text-align: center
|
||||||
.zuo{
|
.zuo{
|
||||||
width: 24rpx;
|
width: 26rpx;
|
||||||
height: 24rpx;
|
height: 26rpx;
|
||||||
border-top: 2px solid #666
|
border-top: 2px solid #666
|
||||||
border-left: 2px solid #666
|
border-left: 2px solid #666
|
||||||
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
||||||
margin-left: 50rpx;
|
margin-left: 60rpx;
|
||||||
}
|
}
|
||||||
.you{
|
.you{
|
||||||
width: 24rpx;
|
width: 26rpx;
|
||||||
height: 24rpx;
|
height: 26rpx;
|
||||||
border-right: 2px solid #666
|
border-right: 2px solid #666
|
||||||
border-bottom: 2px solid #666
|
border-bottom: 2px solid #666
|
||||||
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
||||||
margin-left: 30rpx;
|
// margin-left: 30rpx;
|
||||||
margin-right: 50rpx;
|
margin-right: 50rpx;
|
||||||
}
|
}
|
||||||
.icons{
|
.icons{
|
||||||
@@ -423,6 +538,36 @@ function clones(){
|
|||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
.questionNums{
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.questions{
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 60rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
border: 2px solid #E0E0E0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
margin-right: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.questionsActive{
|
||||||
|
background-color: #F0F9FF;
|
||||||
|
border: 2px solid #409EFF;
|
||||||
|
}
|
||||||
|
.questionCorrect{
|
||||||
|
background-color: #F0F9FF;
|
||||||
|
border: 2px solid #64BC38;
|
||||||
|
color: #6BC441;
|
||||||
|
}
|
||||||
|
.questionError{
|
||||||
|
background-color: #FFF1F0;
|
||||||
|
border: 2px solid #F56C6C;
|
||||||
|
color: #F36B6B;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
<view class="video-detail-container">
|
<view class="video-detail-container">
|
||||||
<!-- 视频播放组件 -->
|
<!-- 视频播放组件 -->
|
||||||
<view class="video-wrapper">
|
<view class="video-wrapper">
|
||||||
<video id="myVideo" :src="videoInfo.currentUrl" :poster="trainVideoImgUrl+ videoInfo.cover"
|
<video id="myVideo" :src="videoInfo.currentUrl" :poster="trainVideoImgUrl+ videoInfo.cover" @seeked="onSeeked"
|
||||||
enable-danmu controls style="width: 100%;"></video>
|
enable-danmu controls style="width: 100%;" @pause="onPause" @timeupdate="onTimeupdate" @ended="onEnded"></video>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="video-info" :style="getItemBackgroundStyle('video-bj2.png')">
|
<view class="video-info" :style="getItemBackgroundStyle('video-bj2.png')">
|
||||||
@@ -21,18 +21,18 @@
|
|||||||
<view class="info-detail">
|
<view class="info-detail">
|
||||||
<view class="info-left">
|
<view class="info-left">
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
|
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||||
<view class="info-label">
|
<view class="info-label">
|
||||||
分类:
|
分类:
|
||||||
</view>
|
</view>
|
||||||
<view class="info-value">
|
<view class="info-value" :data-content="getCategoryLabelByValue(videoInfo.category)">
|
||||||
{{getCategoryLabelByValue(videoInfo.category)}}
|
{{getCategoryLabelByValue(videoInfo.category)}}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-right">
|
<view class="info-right">
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
|
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||||
<view class="info-label">
|
<view class="info-label">
|
||||||
等级:
|
等级:
|
||||||
</view>
|
</view>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
|
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||||
<view class="info-label">
|
<view class="info-label">
|
||||||
讲师:
|
讲师:
|
||||||
</view>
|
</view>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
<view class="info-detail">
|
<view class="info-detail">
|
||||||
<view class="info-left">
|
<view class="info-left">
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
|
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||||
<view class="info-label">
|
<view class="info-label">
|
||||||
时长:
|
时长:
|
||||||
</view>
|
</view>
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="info-right">
|
<view class="info-right">
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
|
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||||
<view class="info-label">
|
<view class="info-label">
|
||||||
发布时间:
|
发布时间:
|
||||||
</view>
|
</view>
|
||||||
@@ -77,14 +77,14 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="video-intro" :style="videoIntroBackgroundStyle('video-bj.png')">
|
<view class="video-intro" :style="videoIntroBackgroundStyle('video-bj.png')">
|
||||||
<view class="intro-title">
|
<view class="intro-title">
|
||||||
<image class="intro-img1" src="../../../static/images/train/video-kc.png" mode=""></image>
|
<image class="intro-img1" :src="baseUrl+'/train/video-kc.png'" mode=""></image>
|
||||||
<view class="title1">
|
<view class="title1">
|
||||||
课程
|
课程
|
||||||
</view>
|
</view>
|
||||||
<view class="title2">
|
<view class="title2">
|
||||||
简介
|
简介
|
||||||
</view>
|
</view>
|
||||||
<image class="intro-img2" src="../../../static/images/train/video-sc.png" mode=""></image>
|
<image class="intro-img2" :src="baseUrl+'/train/video-sc.png'" mode=""></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="intro-content">
|
<view class="intro-content">
|
||||||
{{videoInfo.introduce}}
|
{{videoInfo.introduce}}
|
||||||
@@ -105,6 +105,25 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="video-title" v-if="videoInfo.trainClassList && videoInfo.trainClassList.length>0">
|
||||||
|
<text>课程章节</text>
|
||||||
|
<view class="title-line"></view>
|
||||||
|
</view>
|
||||||
|
<view class="chapter-box" v-if="videoInfo.trainClassList && videoInfo.trainClassList.length>0">
|
||||||
|
<view class="chapter-item" :class="{ active: currentChapter === index}" @click="chapterChange(item,index)" v-for="(item ,index) in videoInfo.trainClassList" :key="index">
|
||||||
|
<view class="chapter-left">
|
||||||
|
<view class="chapter-number">
|
||||||
|
{{ index + 1 }}
|
||||||
|
</view>
|
||||||
|
<view class="chapter-info">
|
||||||
|
{{item.className}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="chapter-icon" v-if="currentChapter === index">
|
||||||
|
<uni-icons type="videocam" size="24"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
@@ -114,7 +133,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { inject, reactive,ref, onMounted, onUnmounted, nextTick } from 'vue';
|
import { inject, reactive,ref, onMounted, onUnmounted, nextTick } from 'vue';
|
||||||
import { onLoad } from '@dcloudio/uni-app';
|
import { onLoad,onHide,onUnload } from '@dcloudio/uni-app';
|
||||||
const { $api, navTo, navBack } = inject('globalFunction');
|
const { $api, navTo, navBack } = inject('globalFunction');
|
||||||
import config from "@/config.js"
|
import config from "@/config.js"
|
||||||
|
|
||||||
@@ -126,11 +145,11 @@ const videoInfo=ref({})
|
|||||||
const trainVideoImgUrl=config.trainVideoImgUrl
|
const trainVideoImgUrl=config.trainVideoImgUrl
|
||||||
const categories=ref([])
|
const categories=ref([])
|
||||||
const levalLabels=ref([])
|
const levalLabels=ref([])
|
||||||
const videoContext = ref(null);
|
const latestTime = ref(0)
|
||||||
const videoUrl = ref('');
|
const totalTime=ref(0)
|
||||||
const posterUrl = ref('');
|
|
||||||
const videoTitle = ref('');
|
|
||||||
const baseUrl = config.imgBaseUrl
|
const baseUrl = config.imgBaseUrl
|
||||||
|
const pageEnterTime = ref(0)
|
||||||
|
const currentChapter = ref(0)
|
||||||
const getItemBackgroundStyle = (imageName) => ({
|
const getItemBackgroundStyle = (imageName) => ({
|
||||||
backgroundImage: `url(${baseUrl}/train/${imageName})`,
|
backgroundImage: `url(${baseUrl}/train/${imageName})`,
|
||||||
backgroundSize: '100% 100%', // 覆盖整个容器
|
backgroundSize: '100% 100%', // 覆盖整个容器
|
||||||
@@ -144,23 +163,23 @@ const videoIntroBackgroundStyle = (imageName) => ({
|
|||||||
backgroundRepeat: 'no-repeat'
|
backgroundRepeat: 'no-repeat'
|
||||||
});
|
});
|
||||||
const params = reactive({
|
const params = reactive({
|
||||||
videoId: '',
|
videoId: '',
|
||||||
userId: ''
|
userId: ''
|
||||||
})
|
})
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
console.log("options",options)
|
getHeart()
|
||||||
|
pageEnterTime.value = Date.now() // 记录毫秒时间戳
|
||||||
videoId.value=options.id
|
videoId.value=options.id
|
||||||
userId.value=uni.getStorageSync('userInfo').userId
|
|
||||||
getDictionary()
|
getDictionary()
|
||||||
getData()
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 初始化视频上下文
|
|
||||||
// nextTick(() => {
|
|
||||||
// videoContext.value = uni.createVideoContext('videoPlayer');
|
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
onHide(() => {
|
||||||
|
updateVideoInfo() // 用缓存值,不要调 getCurrentTime
|
||||||
|
reportPageDuration()
|
||||||
|
})
|
||||||
|
onUnload(() => {
|
||||||
|
updateVideoInfo()
|
||||||
|
reportPageDuration()
|
||||||
|
})
|
||||||
function getData() {
|
function getData() {
|
||||||
params.videoId=videoId.value
|
params.videoId=videoId.value
|
||||||
params.userId=userId.value
|
params.userId=userId.value
|
||||||
@@ -172,16 +191,35 @@ function getData() {
|
|||||||
'Content-Type': "application/x-www-form-urlencoded"
|
'Content-Type': "application/x-www-form-urlencoded"
|
||||||
}
|
}
|
||||||
$api.myRequest('/train/public/trainVideo/model', params,'post',9100,header).then((resData) => {
|
$api.myRequest('/train/public/trainVideo/model', params,'post',9100,header).then((resData) => {
|
||||||
console.log("resData",resData)
|
|
||||||
videoInfo.value=resData
|
videoInfo.value=resData
|
||||||
videoInfo.value.currentUrl=trainVideoImgUrl+videoInfo.value.trainClassList[0].url
|
videoInfo.value.currentUrl=trainVideoImgUrl+videoInfo.value.trainClassList[0].url
|
||||||
console.log("videoInfo.value.currentUrl",videoInfo.value.currentUrl)
|
videoInfo.value.percentage=((videoInfo.value.process/(videoInfo.value.hour*60))*100).toFixed(2)
|
||||||
videoInfo.value.percentage=(videoInfo.value.process/(videoInfo.value.hour*60))*100
|
videoInfo.value.uploadTime=videoInfo.value.uploadTime.split(' ')[0]
|
||||||
console.log("videoInfo",videoInfo.value)
|
});
|
||||||
|
}
|
||||||
|
function getHeart() {
|
||||||
|
const raw = uni.getStorageSync("Padmin-Token");
|
||||||
|
const token = typeof raw === "string" ? raw.trim() : "";
|
||||||
|
const headers = token ? { Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}` }: {}
|
||||||
|
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
|
||||||
|
if (resData.code == 200) {
|
||||||
|
getUserInfo();
|
||||||
|
} else {
|
||||||
|
navTo('/packageB/login')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getUserInfo(){
|
||||||
|
let header={
|
||||||
|
'Authorization':uni.getStorageSync('Padmin-Token')
|
||||||
|
}
|
||||||
|
$api.myRequest('/system/user/login/user/info', {},'get',10100,header).then((resData) => {
|
||||||
|
userId.value=resData.info.userId
|
||||||
|
getData()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function getDictionary(){
|
function getDictionary(){
|
||||||
$api.myRequest('/system/public/dict/data/type/train_category', {},'get',9100).then((resData) => {
|
$api.myRequest('/system/public/dict/data/type/question_classification', {},'get',9100).then((resData) => {
|
||||||
categories.value=resData.data
|
categories.value=resData.data
|
||||||
});
|
});
|
||||||
$api.myRequest('/system/public/dict/data/type/train_level', {},'get',9100).then((resData) => {
|
$api.myRequest('/system/public/dict/data/type/train_level', {},'get',9100).then((resData) => {
|
||||||
@@ -204,13 +242,76 @@ function getLevelLabelByValue(value) {
|
|||||||
const item = levalLabels.value.find(item => item.dictValue === String(value))
|
const item = levalLabels.value.find(item => item.dictValue === String(value))
|
||||||
return item ? item.dictLabel : '暂无等级'
|
return item ? item.dictLabel : '暂无等级'
|
||||||
}
|
}
|
||||||
|
function onPause(e){
|
||||||
|
updateVideoInfo()
|
||||||
|
}
|
||||||
|
function onEnded(e){
|
||||||
|
updateVideoInfo()
|
||||||
|
}
|
||||||
|
function onTimeupdate(e){
|
||||||
|
latestTime.value = e.detail.currentTime
|
||||||
|
}
|
||||||
|
function onSeeked(){
|
||||||
|
updateVideoInfo()
|
||||||
|
}
|
||||||
|
// 更新播放时长
|
||||||
|
function updateVideoInfo(){
|
||||||
|
totalTime.value=0
|
||||||
|
if(currentChapter.value>0){
|
||||||
|
videoInfo.value.trainClassList.forEach((item,index)=>{
|
||||||
|
if(index<currentChapter.value){
|
||||||
|
totalTime.value+=Number(item.hour)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
totalTime.value+=Number(latestTime.value)
|
||||||
|
let paramsData={
|
||||||
|
userId:userId.value,
|
||||||
|
videoId:videoId.value,
|
||||||
|
collect:'',
|
||||||
|
process:Math.floor(Number(totalTime.value))
|
||||||
|
}
|
||||||
|
let header={
|
||||||
|
'Authorization':uni.getStorageSync('Padmin-Token'),
|
||||||
|
'Content-Type': "application/x-www-form-urlencoded"
|
||||||
|
}
|
||||||
|
if(videoInfo.value.isCollect===null && videoInfo.value.process ===null){
|
||||||
|
$api.myRequest('/train/public/videoUser/add', paramsData,'post',9100,header).then((resData) => {
|
||||||
|
console.log("视频播放时长更新成功")
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
$api.myRequest('/train/public/videoUser/update', paramsData,'post',9100,header).then((resData) => {
|
||||||
|
console.log("视频播放时长更新成功")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 计算并上报停留时长
|
||||||
|
function reportPageDuration() {
|
||||||
|
const duration = Date.now() - pageEnterTime.value // 毫秒
|
||||||
|
const durationSeconds = Math.floor(duration / 1000) // 转为秒
|
||||||
|
if (durationSeconds > 0) {
|
||||||
|
let paramsData={
|
||||||
|
type:'video',
|
||||||
|
hour:durationSeconds,
|
||||||
|
videoId:videoId.value,
|
||||||
|
userId:userId.value,
|
||||||
|
title:videoInfo.value.videoTitle
|
||||||
|
}
|
||||||
|
let header={
|
||||||
|
'Authorization':uni.getStorageSync('Padmin-Token'),
|
||||||
|
'Content-Type': "application/x-www-form-urlencoded"
|
||||||
|
}
|
||||||
|
$api.myRequest('/train/public/userHour/add', paramsData,'post',9100,header).then((resData) => {
|
||||||
|
console.log("学习时长更新成功")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function chapterChange(video,index){
|
||||||
|
currentChapter.value=index
|
||||||
|
videoInfo.value.currentUrl=trainVideoImgUrl+video.url
|
||||||
|
}
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
// 组件卸载时停止播放并退出全屏
|
|
||||||
if (videoContext.value) {
|
|
||||||
videoContext.value.pause();
|
|
||||||
videoContext.value.exitFullScreen();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -277,15 +378,20 @@ onUnmounted(() => {
|
|||||||
.icon-img{
|
.icon-img{
|
||||||
width: 24rpx;
|
width: 24rpx;
|
||||||
height: 28rpx;
|
height: 28rpx;
|
||||||
|
margin-right: 4rpx;
|
||||||
}
|
}
|
||||||
.info-label{
|
.info-label{
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #0068C8;
|
color: #0068C8;
|
||||||
|
min-width: 86rpx;
|
||||||
}
|
}
|
||||||
.info-value{
|
.info-value{
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #404040;
|
color: #404040;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.video-intro{
|
.video-intro{
|
||||||
padding: 20rpx;
|
padding: 20rpx;
|
||||||
@@ -326,6 +432,7 @@ onUnmounted(() => {
|
|||||||
box-shadow: 0px 0px 10px 0px rgba(0,48,107,0.1);
|
box-shadow: 0px 0px 10px 0px rgba(0,48,107,0.1);
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
padding: 40rpx 30rpx;
|
padding: 40rpx 30rpx;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
}
|
}
|
||||||
.progress-info{
|
.progress-info{
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -335,4 +442,51 @@ onUnmounted(() => {
|
|||||||
color: #333333;
|
color: #333333;
|
||||||
margin-top: 20rpx;
|
margin-top: 20rpx;
|
||||||
}
|
}
|
||||||
|
.chapter-box{
|
||||||
|
background: linear-gradient(0deg, #DFEDFF 0%, #F8FCFF 100%);
|
||||||
|
box-shadow: 0px 0px 10px 0px rgba(0,48,107,0.1);
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 40rpx 30rpx;
|
||||||
|
}
|
||||||
|
.chapter-item{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16rpx 24rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
border: 2rpx solid #F0F0F0;
|
||||||
|
background: #F9F9F9;
|
||||||
|
}
|
||||||
|
.chapter-item.active {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
color: #409EFF;
|
||||||
|
}
|
||||||
|
.chapter-left{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.chapter-number{
|
||||||
|
width: 50rpx;
|
||||||
|
height: 50rpx;
|
||||||
|
background: #cccccc;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-right: 16rpx;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.chapter-item.active .chapter-number {
|
||||||
|
background: #409EFF;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.chapter-info {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
943
pages.json
943
pages.json
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,10 @@
|
|||||||
<view class="app-container">
|
<view class="app-container">
|
||||||
<!-- 顶部头部区域 -->
|
<!-- 顶部头部区域 -->
|
||||||
<view class="container-header">
|
<view class="container-header">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序使用 image 标签作为背景 -->
|
||||||
|
<image class="header-bg-image" src="/static/icon/background2.png" mode="aspectFill"></image>
|
||||||
|
<!-- #endif -->
|
||||||
<view class="header-top">
|
<view class="header-top">
|
||||||
<view
|
<view
|
||||||
class="header-btnLf button-click"
|
class="header-btnLf button-click"
|
||||||
@@ -507,14 +511,33 @@ function getNextDates({ startDate = "", count = 6 }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-container .container-header {
|
.app-container .container-header {
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef MP-WEIXIN */
|
||||||
background: url("@/static/icon/background2.png") 0 0 no-repeat;
|
background: url("@/static/icon/background2.png") 0 0 no-repeat;
|
||||||
background-size: 100% 400rpx;
|
background-size: 100% 400rpx;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifdef MP-WEIXIN */
|
||||||
|
/* 小程序使用 image 标签,背景样式在 image 上设置 */
|
||||||
|
/* #endif */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* #ifdef MP-WEIXIN */
|
||||||
|
.app-container .container-header .header-bg-image {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 400rpx;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
.app-container .container-header .header-top {
|
.app-container .container-header .header-top {
|
||||||
display: flex;
|
display: flex;
|
||||||
line-height: calc(88rpx - 14rpx);
|
line-height: calc(88rpx - 14rpx);
|
||||||
padding: 16rpx 44rpx 14rpx 44rpx;
|
padding: 16rpx 44rpx 14rpx 44rpx;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-container .container-header .header-top .header-btnLf {
|
.app-container .container-header .header-top .header-btnLf {
|
||||||
@@ -551,6 +574,7 @@ function getNextDates({ startDate = "", count = 6 }) {
|
|||||||
padding: 0 24rpx;
|
padding: 0 24rpx;
|
||||||
width: calc(100% - 48rpx);
|
width: calc(100% - 48rpx);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-container .container-header .header-input .iconsearch {
|
.app-container .container-header .header-input .iconsearch {
|
||||||
|
|||||||
@@ -701,9 +701,43 @@ const handleServiceClick = (serviceType) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理直播按钮点击
|
// 处理直播按钮点击 - 跳转微信视频号
|
||||||
const handleLiveClick = () => {
|
const handleLiveClick = () => {
|
||||||
$api.msg('该功能正在开发中');
|
// #ifdef MP-WEIXIN
|
||||||
|
const feedId = 'sphKH1AEeLfTJJE';
|
||||||
|
|
||||||
|
// 使用微信原生 API 打开视频号直播
|
||||||
|
if (typeof wx !== 'undefined' && wx.openChannelsUserProfile) {
|
||||||
|
wx.openChannelsUserProfile({
|
||||||
|
// feedId: feedId,
|
||||||
|
finderUserName: feedId, // 视频号 finderUserName,如果feedId足够可以留空
|
||||||
|
success: (res) => {
|
||||||
|
console.log('打开视频号成功', res);
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('打开视频号失败', err);
|
||||||
|
$api.msg(err.errMsg || '无法打开直播,请稍后重试');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 如果 API 不存在,尝试使用 uni API
|
||||||
|
uni.openChannelsLive({
|
||||||
|
feedId: feedId,
|
||||||
|
success: (res) => {
|
||||||
|
console.log('打开视频号成功', res);
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('打开视频号失败', err);
|
||||||
|
$api.msg('无法打开直播,请检查微信版本或稍后重试');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
// 非微信小程序环境提示
|
||||||
|
$api.msg('该功能仅在微信小程序中可用');
|
||||||
|
// #endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// 跳转到测试页面
|
// 跳转到测试页面
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppLayout title="我的" back-gorund-color="#F4F4F4">
|
<AppLayout back-gorund-color="#F4F4F4">
|
||||||
<!-- 自定义tabbar -->
|
<!-- 自定义tabbar -->
|
||||||
<CustomTabBar :currentPage="4" />
|
<CustomTabBar :currentPage="4" />
|
||||||
<!-- 企业用户信息卡片 -->
|
<!-- 企业用户信息卡片 -->
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppLayout title="附近" :use-scroll-view="false">
|
<AppLayout :use-scroll-view="false">
|
||||||
<template #headerleft>
|
<template #headerleft>
|
||||||
<view class="btnback">
|
<view class="btnback">
|
||||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||||
@@ -19,10 +19,10 @@
|
|||||||
<component :is="components[index]" :ref="(el) => handelComponentsRef(el, index)" />
|
<component :is="components[index]" :ref="(el) => handelComponentsRef(el, index)" />
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
<oneComponent v-show="currentIndex === 0" :ref="(el) => handelComponentsRef(el, index)" />
|
<oneComponent v-if="index === 0" :ref="(el) => handelComponentsRef(el, index)" />
|
||||||
<twoComponent v-show="currentIndex === 1" :ref="(el) => handelComponentsRef(el, index)" />
|
<twoComponent v-if="index === 1" :ref="(el) => handelComponentsRef(el, index)" />
|
||||||
<threeComponent v-show="currentIndex === 2" :ref="(el) => handelComponentsRef(el, index)" />
|
<threeComponent v-if="index === 2" :ref="(el) => handelComponentsRef(el, index)" />
|
||||||
<fourComponent v-show="currentIndex === 3" :ref="(el) => handelComponentsRef(el, index)" />
|
<fourComponent v-if="index === 3" :ref="(el) => handelComponentsRef(el, index)" />
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
|
|||||||
Reference in New Issue
Block a user