mrr.sj.front/pages/artisan/service-skills.vue

891 lines
27 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="service-skills-page">
<!-- 顶部导航栏 -->
<custom-navbar :title="navTitle" :showBack="true"></custom-navbar>
<!-- 页面内容容器 -->
<view class="page-content" :style="{ paddingBottom: buttonAreaHeight + 'px' }">
<!-- 服务技能选择区域 -->
<view class="skills-container box-cont">
<view class="skills-header">
<view class="title-bar"></view>
<text class="skills-title">服务技能多选</text>
</view>
<view class="skills-subtitle" v-if="editable">请选择服务技能</view>
<!-- 显示当前生效的服务技能 -->
<view class="skills-list" v-if="!showPendingSkills">
<view class="skill-item"
v-for="(skill, index) in serviceList"
:key="skill.id"
:class="{ disabled: true }">
<view class="checkbox-wrapper">
<view class="checkbox" :class="{ checked: isCurrentSkillSelected(skill.id) }">
<image v-if="isCurrentSkillSelected(skill.id)"
class="check-icon"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/66325904-4603-48fd-b03b-90c684af96e9"
mode="aspectFit">
</image>
</view>
</view>
<text class="skill-name">{{ skill.title }}</text>
</view>
</view>
<!-- 显示待审核的服务技能 -->
<view class="skills-list" v-else>
<view class="skill-item"
v-for="(skill, index) in serviceList"
:key="skill.id"
@click="toggleSkillSelect(index)"
:class="{ disabled: !editable }">
<view class="checkbox-wrapper">
<view class="checkbox" :class="{ checked: skill.checked }">
<image v-if="skill.checked"
class="check-icon"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/66325904-4603-48fd-b03b-90c684af96e9"
mode="aspectFit">
</image>
</view>
</view>
<text class="skill-name">{{ skill.title }}</text>
</view>
</view>
</view>
</view>
<!-- 底部按钮 -->
<view class="bottom-actions" ref="buttonArea">
<!-- 驳回原因提示 -->
<view class="reject-reason" v-if="shouldShowRejectReason">
<view class="reject-title">您的提交已驳回</view>
<view class="reject-detail">驳回原因:{{ backText }}</view>
</view>
<!-- 审核中提示 -->
<view class="audit-tip" v-if="showAuditTip && !showPendingSkills">
<text class="audit-text">您的提交变更正在审核中...</text>
</view>
<!-- 去变更信息按钮 -->
<view class="action-btn change-info-btn" v-if="buttonType === 'change'" @click="startChange">
<text class="btn-text">去变更信息</text>
</view>
<!-- 取消和提交按钮 -->
<view class="action-buttons-row" v-if="buttonType === 'edit'">
<view class="action-btn cancel-btn" @click="cancelChange">
<text class="btn-text cancel-text">取消</text>
</view>
<view class="action-btn submit-btn" @click="submitChange">
<text class="btn-text">提交</text>
</view>
</view>
<!-- 查看我的变更按钮 -->
<view class="action-btn view-change-btn" v-if="buttonType === 'view'" @click="togglePendingSkills">
<text class="btn-text">{{ showPendingSkills ? '返回' : '查看我的变更' }}</text>
</view>
</view>
</view>
</template>
<script>
import request from '../../utils/request';
export default {
data() {
return {
serviceList: [], // 服务技能列表
selectedSkills: [], // 已选中的技能ID待审核的
originalSkills: [], // 原始选中的技能ID当前生效的
editable: false, // 是否可编辑
buttonType: 'change', // 按钮类型: change-去变更信息, edit-取消/提交, view-查看我的变更
showAuditTip: false, // 是否显示审核中提示
auditStatus: null, // 审核状态
applyId: null, // 申请ID
isLoading: true, // 添加加载状态
showPendingSkills: false, // 是否显示待审核的技能
currentSkills: [], // 当前生效的技能ID
navTitle: '服务技能', // 导航栏标题
buttonAreaHeight: 120, // 按钮区域高度用于计算底部padding
backText: '', // 驳回原因
identity: '', // 用户身份
lastApplyTime: null, //记录最后申请时间
}
},
computed: {
selectedSkillsText() {
const selectedTitles = this.serviceList
.filter(item => item.checked)
.map(item => item.title);
return selectedTitles.join('、');
},
hasChanges() {
// 检查是否有变更
const current = [...this.selectedSkills].sort().join(',');
const original = [...this.originalSkills].sort().join(',');
return current !== original;
},
// 检查是否有待处理的申请(基于时间)
hasPendingApply() {
if (!this.lastApplyTime) return false;
// 如果最后申请时间在驳回时间之后,说明有新的申请
return true;
},
// 控制驳回提示是否显示
shouldShowRejectReason() {
// 只有在审核驳回状态、不显示待审核技能、且没有待处理申请时才显示驳回提示
return this.auditStatus === 3 &&
!this.showPendingSkills &&
this.backText &&
!this.hasPendingApply;
}
},
onLoad() {
this.initPage();
},
onShow() {
// 页面显示时重新加载数据,确保显示最新状态
this.initPage();
},
onReady() {
// 获取按钮区域高度用于设置页面内容padding
this.getButtonAreaHeight();
},
methods: {
// 初始化页面
async initPage() {
this.isLoading = true;
try {
// 先加载服务技能列表
await this.loadServiceSkills();
// 然后加载申请详情
await this.loadApplyDetails();
} catch (error) {
console.error('初始化页面失败:', error);
} finally {
this.isLoading = false;
}
},
// 清理驳回技能存储的逻辑
async cleanupRejectedSkillsIfNeeded() {
try {
const rejectedSkills = uni.getStorageSync('rejectedSkills');
const lastApplyTime = uni.getStorageSync('lastApplyTime');
if (rejectedSkills && rejectedSkills.length > 0) {
// 获取当前生效技能
const currentSkills = await this.getCurrentEffectiveSkillIds();
const currentSorted = [...currentSkills].sort().join(',');
const rejectedSorted = [...rejectedSkills].sort().join(',');
// 如果当前生效技能与被驳回技能不一致,说明有新的申请已生效
if (currentSorted !== rejectedSorted) {
console.log('检测到技能已变更,清理驳回相关存储');
uni.removeStorageSync('rejectedSkills');
uni.removeStorageSync('lastRejectTime');
}
}
} catch (error) {
console.error('清理驳回技能存储失败:', error);
}
},
// 获取按钮区域高度
getButtonAreaHeight() {
// 使用setTimeout确保DOM已渲染
setTimeout(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.bottom-actions').boundingClientRect(data => {
if (data) {
this.buttonAreaHeight = data.height + 20; // 增加一些边距
}
}).exec();
}, 100);
},
// 更新导航栏标题
updateNavTitle() {
if (this.editable || this.showPendingSkills) {
this.navTitle = '服务技能变更';
} else {
this.navTitle = '服务技能';
}
},
// 加载服务技能列表
async loadServiceSkills() {
try {
const res = await request.post('/user/firstclass');
this.serviceList = res.data.map(item => ({
...item,
checked: false
}));
console.log('服务技能列表:', this.serviceList);
} catch (error) {
console.error('加载服务技能失败:', error);
uni.showToast({
title: '加载服务技能失败',
icon: 'none'
});
}
},
// 加载申请详情 - 手艺人接口
async loadApplyDetails() {
try {
console.log('开始加载手艺人申请详情...');
const res = await request.post('/syr/userSyrAuth/details', {
apply_type: 2 // 服务技能变更
});
console.log('手艺人申请详情接口返回:', res);
if (res.code === 200 && res.data) {
const detail = res.data;
this.applyId = detail.id;
this.auditStatus = detail.apply_state;
this.backText = detail.back_text || ''; // 获取驳回原因
console.log('审核状态:', this.auditStatus);
console.log('原始servers_kill数据:', detail.servers_kill);
// 处理服务技能数据
if (detail.servers_kill) {
let skillIds = [];
if (Array.isArray(detail.servers_kill)) {
skillIds = detail.servers_kill.map(id => {
const num = parseInt(id);
return isNaN(num) ? null : num;
}).filter(id => id !== null);
} else if (typeof detail.servers_kill === 'string') {
skillIds = detail.servers_kill.split(',').map(id => {
const num = parseInt(id.trim());
return isNaN(num) ? null : num;
}).filter(id => id !== null);
}
console.log('解析后的技能ID:', skillIds);
// 根据审核状态正确处理数据
if (this.auditStatus === 1) { // 审核中
this.selectedSkills = [...skillIds];
console.log('审核中,待审核技能:', this.selectedSkills);
// 记录申请时间
uni.setStorageSync('lastApplyTime', new Date().getTime());
} else if (this.auditStatus === 3) { // 审核驳回
// 检查驳回数据是否是最新的
await this.handleRejectedSkills(skillIds);
} else if (this.auditStatus === 2) { // 审核通过
// 审核通过时,使用申请详情中的技能作为当前生效技能
this.currentSkills = [...skillIds];
this.originalSkills = [...skillIds];
this.selectedSkills = [...skillIds];
console.log('审核通过,设置当前生效技能:', this.currentSkills);
// 清理驳回相关存储
uni.removeStorageSync('rejectedSkills');
uni.removeStorageSync('lastRejectTime');
// 重要:审核通过后,强制重新加载当前生效技能以确保数据一致
await this.forceReloadCurrentSkills();
}
this.updateCheckedStatus();
}
// 如果审核状态不是审核通过,加载当前生效的技能
if (this.auditStatus !== 2) {
await this.loadCurrentEffectiveSkills();
}
} else {
console.log('申请详情返回数据为空或code不为200:', res);
// 清理可能的驳回存储
uni.removeStorageSync('rejectedSkills');
uni.removeStorageSync('lastRejectTime');
await this.loadCurrentEffectiveSkills();
}
// 更新页面状态
this.updatePageStatus();
} catch (error) {
console.error('加载申请详情失败:', error);
// 出错时也尝试加载当前生效的技能
await this.loadCurrentEffectiveSkills();
this.updatePageStatus();
}
},
// 新增方法:强制重新加载当前生效技能
async forceReloadCurrentSkills() {
try {
console.log('强制重新加载当前生效技能...');
const currentSkills = await this.getCurrentEffectiveSkillIds();
// 比较申请通过的数据和当前生效数据
const approvedSorted = [...this.currentSkills].sort().join(',');
const currentSorted = [...currentSkills].sort().join(',');
console.log('申请通过技能:', approvedSorted);
console.log('当前生效技能:', currentSorted);
if (approvedSorted !== currentSorted) {
console.log('数据不一致,使用申请通过的数据');
// 保持使用申请通过的数据
} else {
console.log('数据一致,使用当前生效数据');
this.currentSkills = [...currentSkills];
this.originalSkills = [...currentSkills];
this.selectedSkills = [...currentSkills];
}
this.updateCheckedStatus();
} catch (error) {
console.error('强制重新加载当前生效技能失败:', error);
}
},
// 处理驳回技能逻辑
async handleRejectedSkills(rejectedSkillIds) {
const storedRejectedSkills = uni.getStorageSync('rejectedSkills');
const lastRejectTime = uni.getStorageSync('lastRejectTime');
// 获取当前生效技能进行比较
const currentSkills = await this.getCurrentEffectiveSkillIds();
const rejectedSorted = [...rejectedSkillIds].sort().join(',');
const storedSorted = storedRejectedSkills ? [...storedRejectedSkills].sort().join(',') : '';
const currentSorted = [...currentSkills].sort().join(',');
console.log('驳回数据比较:', {
rejectedSorted,
storedSorted,
currentSorted
});
// 如果驳回的技能与当前生效技能相同,说明驳回数据过时
if (rejectedSorted === currentSorted) {
console.log('驳回数据与当前生效技能相同,可能数据过时,忽略本次驳回数据');
this.selectedSkills = [...currentSkills];
// 清理驳回存储
uni.removeStorageSync('rejectedSkills');
uni.removeStorageSync('lastRejectTime');
this.backText = ''; // 清空驳回原因
return;
}
// 如果驳回技能与存储的驳回技能不同,更新存储
if (rejectedSorted !== storedSorted) {
console.log('发现新的驳回数据,更新存储:', rejectedSkillIds);
uni.setStorageSync('rejectedSkills', rejectedSkillIds);
uni.setStorageSync('lastRejectTime', new Date().getTime());
}
this.selectedSkills = [...rejectedSkillIds];
console.log('审核驳回,被驳回技能:', this.selectedSkills);
},
// 获取当前生效技能ID
async getCurrentEffectiveSkillIds() {
try {
const params = {
type: 2, // 手艺人
_t: new Date().getTime() // 添加时间戳防止缓存
};
const res = await request.post('/user/getuser', params);
if (res.state === 1 && res.data && res.data.servers_kill) {
let skillIds = [];
if (Array.isArray(res.data.servers_kill)) {
skillIds = res.data.servers_kill.map(id => parseInt(id)).filter(id => !isNaN(id));
} else if (typeof res.data.servers_kill === 'string') {
skillIds = res.data.servers_kill.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id));
}
console.log('获取到的当前生效技能ID:', skillIds);
return skillIds;
}
return [];
} catch (error) {
console.error('获取当前生效技能失败:', error);
return [];
}
},
// 加载当前生效的服务技能
async loadCurrentEffectiveSkills() {
try {
console.log('开始加载当前生效的服务技能...');
const currentSkills = await this.getCurrentEffectiveSkillIds();
this.currentSkills = [...currentSkills];
this.originalSkills = [...currentSkills];
console.log('当前生效的技能ID:', this.currentSkills);
// 只有在无申请状态或审核驳回状态时,才用当前技能更新选中技能
if (this.auditStatus === null || this.auditStatus === 3) {
this.selectedSkills = [...currentSkills];
}
// 审核中状态保持原有的selectedSkills不变
this.updateCheckedStatus();
} catch (error) {
console.error('加载当前生效技能失败:', error);
this.currentSkills = [];
this.originalSkills = [];
if (this.auditStatus !== 1) {
this.selectedSkills = [];
}
this.updateCheckedStatus();
}
},
// 检查技能是否在当前生效的技能中
isCurrentSkillSelected(skillId) {
return this.currentSkills.includes(skillId);
},
// 更新选中状态(用于待审核的技能)
updateCheckedStatus() {
console.log('更新选中状态,当前服务技能列表:', this.serviceList);
console.log('要选中的技能ID:', this.selectedSkills);
this.serviceList.forEach(item => {
item.checked = this.selectedSkills.includes(item.id);
});
},
// 根据审核状态更新页面状态
updatePageStatus() {
console.log('更新页面状态,审核状态:', this.auditStatus);
if (this.auditStatus === 1) { // 审核中
this.showAuditTip = true;
this.buttonType = 'view';
this.editable = false;
this.showPendingSkills = false;
} else if (this.auditStatus === 3) { // 审核驳回
// 检查驳回数据是否有效
const rejectedSkills = uni.getStorageSync('rejectedSkills');
const rejectedSorted = rejectedSkills ? [...rejectedSkills].sort().join(',') : '';
const currentSorted = [...this.currentSkills].sort().join(',');
console.log('驳回数据有效性检查:', {
rejectedSorted,
currentSorted
});
// 如果驳回技能与当前技能相同,说明驳回数据无效
if (rejectedSorted === currentSorted) {
console.log('驳回数据无效,按无申请状态处理');
this.showAuditTip = false;
this.buttonType = 'change';
this.editable = false;
this.showPendingSkills = false;
this.backText = ''; // 清空驳回原因
// 清理存储
uni.removeStorageSync('rejectedSkills');
uni.removeStorageSync('lastRejectTime');
} else {
this.showAuditTip = false;
this.buttonType = 'change';
this.editable = false;
this.showPendingSkills = false;
}
}else if (this.auditStatus === 2) { // 审核通过
// 审核通过时,确保显示正确的状态
this.showAuditTip = false;
this.buttonType = 'change';
this.editable = false;
this.showPendingSkills = false;
console.log('审核通过状态,当前生效技能:', this.currentSkills);
} else { // 无申请
this.showAuditTip = false;
this.buttonType = 'change';
this.editable = false;
this.showPendingSkills = false;
}
this.updateNavTitle();
console.log('最终页面状态:', {
showAuditTip: this.showAuditTip,
buttonType: this.buttonType,
editable: this.editable,
showPendingSkills: this.showPendingSkills,
currentSkills: this.currentSkills,
selectedSkills: this.selectedSkills,
backText: this.backText
});
},
// 切换技能选择状态(仅用于编辑模式)
toggleSkillSelect(index) {
if (!this.editable) return;
this.$set(this.serviceList[index], 'checked', !this.serviceList[index].checked);
// 更新选中的技能ID数组
this.selectedSkills = this.serviceList
.filter(item => item.checked)
.map(item => item.id);
console.log('当前选中的技能ID:', this.selectedSkills);
},
// 切换显示待审核的技能
togglePendingSkills() {
this.showPendingSkills = !this.showPendingSkills;
// 更新导航栏标题
this.updateNavTitle();
},
// 开始变更
startChange() {
this.editable = true;
this.buttonType = 'edit';
// 进入编辑模式时,显示待审核的技能
this.showPendingSkills = true;
// 更新导航栏标题
this.updateNavTitle();
},
// 取消变更
cancelChange() {
// 恢复原始选择
this.selectedSkills = [...this.originalSkills];
this.updateCheckedStatus();
this.editable = false;
this.buttonType = 'change';
this.showPendingSkills = false; // 取消后显示当前生效的技能
// 更新导航栏标题
this.updateNavTitle();
},
// 提交变更 - 手艺人接口(修改为数组格式)
async submitChange() {
if (this.selectedSkills.length === 0) {
uni.showToast({
title: '请至少选择一个服务技能',
icon: 'none'
});
return;
}
if (!this.hasChanges) {
uni.showToast({
title: '未检测到变更',
icon: 'none'
});
return;
}
try {
uni.showLoading({
title: '提交中...'
});
const params = {
apply_type: 2, // 服务技能变更
servers_kill: this.selectedSkills // 直接传递数组
};
console.log('提交的数据:', params);
const res = await request.post('/syr/userSyrAuth/apply', params);
uni.hideLoading();
if (res.code === 200) {
uni.showToast({
title: '提交成功',
icon: 'none'
});
// 清理驳回相关存储
uni.removeStorageSync('rejectedSkills');
uni.removeStorageSync('lastRejectTime');
// 记录申请时间
uni.setStorageSync('lastApplyTime', new Date().getTime());
// 更新页面状态为审核中
this.showAuditTip = true;
this.editable = false;
this.buttonType = 'view';
this.auditStatus = 1; // 审核中
this.showPendingSkills = false; // 提交后默认显示当前生效的技能
// 更新导航栏标题
this.updateNavTitle();
// 重要:提交后强制重新加载数据
setTimeout(async () => {
await this.loadApplyDetails();
}, 1000);
// 重新加载申请详情获取最新状态
setTimeout(() => {
this.loadApplyDetails();
}, 1000);
} else {
uni.showToast({
title: res.msg || '提交失败',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
console.error('提交变更失败:', error);
uni.showToast({
title: '提交失败',
icon: 'none'
});
}
}
}
}
</script>
<style scoped>
.service-skills-page {
background-color: #f5f5f5;
min-height: 100vh;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
/* 页面内容区域 */
.page-content {
flex: 1;
overflow-y: auto;
padding: 20rpx 0;
box-sizing: border-box;
}
/* 审核中提示 */
.audit-tip {
margin: 20rpx 24rpx 20rpx 24rpx;
border-radius: 12rpx;
}
.audit-text {
font-weight: 400;
font-size: 32rpx;
color: #333333;
text-align: center;
display: block;
}
/* 驳回原因样式 */
.reject-reason {
background: transparent;
padding: 24rpx;
}
.reject-title {
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #333333;
line-height: 45rpx;
text-align: center;
font-style: normal;
}
.reject-detail {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
color: #999999;
line-height: 40rpx;
text-align: center;
font-style: normal;
margin-top: 12rpx;
}
.skills-header {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.title-bar {
width: 6rpx;
height: 30rpx;
background-color: #E8101E;
margin-right: 10rpx;
border-radius: 5rpx;
}
.skills-title {
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #1D2129;
line-height: 48rpx;
text-align: left;
font-style: normal;
}
.skills-subtitle {
margin-left: 20rpx;
margin-bottom: 20rpx;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
color: #333333;
line-height: 40rpx;
text-align: left;
font-style: normal;
}
.box-cont {
background: #ffffff;
border-radius: 20rpx;
margin: 4rpx 24rpx 24rpx 24rpx;
box-shadow: none;
}
.skills-container {
padding: 32rpx;
}
.skills-list {
display: flex;
flex-wrap: wrap;
margin: 0 4rpx;
}
.skill-item {
width: 100%;
display: flex;
align-items: center;
padding: 20rpx 16rpx;
box-sizing: border-box;
}
.checkbox-wrapper {
margin-right: 20rpx;
}
.checkbox {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #DDDDDD;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
}
.checkbox.checked {
background-color: #E8101E;
border-color: #E8101E;
}
.check-icon {
width: 42rpx;
height: 42rpx;
}
.skill-name {
font-size: 28rpx;
color: #333333;
}
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 0rpx 24rpx 40rpx 24rpx;
background: #ffffff;
z-index: 100;
}
/* 单个按钮样式 */
.action-btn {
height: 88rpx;
border-radius: 43rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: 400;
}
.change-info-btn {
margin-top: 20rpx;
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
}
.view-change-btn {
margin-top: 20rpx;
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
}
/* 双按钮行样式 */
.action-buttons-row {
display: flex;
justify-content: space-between;
margin: 20rpx 30rpx;
}
.action-buttons-row .action-btn {
width: 270rpx;
}
.cancel-btn {
background: #E5E5E5;
border-radius: 43rpx;
padding: 0 15rpx;
}
.submit-btn {
background: linear-gradient(180deg, #F52540 0%, #E8101E 100%, #E8101E 100%);
border-radius: 43rpx;
padding: 0 15rpx;
}
.btn-text {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 36rpx;
color: #FFFFFF;
line-height: 50rpx;
text-align: left;
font-style: normal;
}
.cancel-text {
color: #666666;
}
/* 响应式适配 */
/* @media (max-width: 375px) {
.skill-item {
width: 100%;
}
.action-buttons-row .action-btn {
width: 260rpx;
}
}
@media (min-width: 750px) {
.skill-item {
width: 33.333%;
}
} */
</style>