Compare commits
No commits in common. "573aef3210396b48ff06d5ce9b0be1c0acbfa7ac" and "79ee295c18e5c333da3f72ee4fd481e26758bb1a" have entirely different histories.
573aef3210
...
79ee295c18
501
App.vue
501
App.vue
|
|
@ -1,263 +1,276 @@
|
|||
<script>
|
||||
// #ifdef APP-PLUS
|
||||
import {
|
||||
isNotificationsEnabled,
|
||||
permissions,
|
||||
registPush
|
||||
} from '@/utils/AS-NotifyTheAuthority.js'
|
||||
import {
|
||||
permissionListener
|
||||
} from './utils/permissionTips.js'
|
||||
// import { appUpdateListener } from '@/common/utils/appUpdateTips.js'
|
||||
import locationService from './utils/locationService.js'
|
||||
// import uploadApp from './utils/uploadApp.js'
|
||||
// #endif
|
||||
import request from './utils/request'
|
||||
import {
|
||||
setVersion
|
||||
} from './utils/version.js'
|
||||
import {
|
||||
APP_BACK_BASE_URL
|
||||
} from './utils/appBackBase.js'
|
||||
//初始化一键登录插件
|
||||
const aLiSDKModule = uni.requireNativePlugin('AliCloud-NirvanaPns');
|
||||
export default {
|
||||
globalData: {
|
||||
artisanType: 2,
|
||||
latitude: '38.366667',
|
||||
longitude: '117.333333',
|
||||
address: '黄骅市',
|
||||
servers_region: `河北省-沧州市-黄骅市`,
|
||||
deviceid: '',
|
||||
addressRes: {
|
||||
"type": "gcj02",
|
||||
"altitude": 0,
|
||||
"latitude": 38.372266,
|
||||
"longitude": 117.332895,
|
||||
"speed": 0,
|
||||
"accuracy": 30,
|
||||
"adcode": "130983",
|
||||
"cCode": "130900",
|
||||
"pcode": "130000",
|
||||
"address": {
|
||||
"country": "中国",
|
||||
"province": "河北省",
|
||||
"city": "沧州市",
|
||||
"district": "黄骅市",
|
||||
"street": "渤海西路",
|
||||
"streetNum": "35号",
|
||||
// "poiName": "请开启位置权限",
|
||||
"poiName": "黄骅市人民政府",
|
||||
"cityCode": "0317",
|
||||
// #ifdef APP-PLUS
|
||||
import {
|
||||
isNotificationsEnabled,
|
||||
permissions,
|
||||
registPush
|
||||
} from '@/utils/AS-NotifyTheAuthority.js'
|
||||
import {
|
||||
permissionListener
|
||||
} from './utils/permissionTips.js'
|
||||
// import { appUpdateListener } from '@/common/utils/appUpdateTips.js'
|
||||
import locationService from './utils/locationService.js'
|
||||
// import uploadApp from './utils/uploadApp.js'
|
||||
// #endif
|
||||
import request from './utils/request'
|
||||
import {
|
||||
setVersion
|
||||
} from './utils/version.js'
|
||||
//初始化一键登录插件
|
||||
const aLiSDKModule = uni.requireNativePlugin('AliCloud-NirvanaPns');
|
||||
export default {
|
||||
globalData: {
|
||||
artisanType: 2,
|
||||
latitude: '38.366667',
|
||||
longitude: '117.333333',
|
||||
address: '黄骅市',
|
||||
servers_region: `河北省-沧州市-黄骅市`,
|
||||
deviceid: '',
|
||||
addressRes: {
|
||||
"type": "gcj02",
|
||||
"altitude": 0,
|
||||
"latitude": 38.372266,
|
||||
"longitude": 117.332895,
|
||||
"speed": 0,
|
||||
"accuracy": 30,
|
||||
"adcode": "130983",
|
||||
"cCode": "130900",
|
||||
"pcode": "130000",
|
||||
"address": {
|
||||
"country": "中国",
|
||||
"province": "河北省",
|
||||
"city": "沧州市",
|
||||
"district": "黄骅市",
|
||||
"street": "渤海西路",
|
||||
"streetNum": "35号",
|
||||
// "poiName": "请开启位置权限",
|
||||
"poiName": "黄骅市人民政府",
|
||||
"cityCode": "0317",
|
||||
"adcode": "130983",
|
||||
"cCode": "130900",
|
||||
"pcode": "130000",
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onLaunch: async function () {
|
||||
// #ifdef APP-PLUS
|
||||
uni.hideTabBar();
|
||||
if (uni.getStorageSync('accessToken')) {
|
||||
registPush()
|
||||
//跟新底部消息数量
|
||||
this.messageUpudateNum()
|
||||
}
|
||||
// #endif
|
||||
|
||||
//缓存手机版本号
|
||||
// await setVersion()
|
||||
|
||||
//获取访问路由
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.setStorageSync('baseUrl', APP_BACK_BASE_URL)
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.setStorageSync('baseUrl', APP_BACK_BASE_URL)
|
||||
// #endif
|
||||
this.$store.commit("setLocation", true)
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
//禁止手机横屏
|
||||
plus.screen.lockOrientation("portrait-primary")
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
//权限提示监听
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
let platform = systemInfo.platform;
|
||||
if (platform === 'android') {
|
||||
// console.log('安卓用户')
|
||||
permissionListener()
|
||||
} else if (platform === 'ios') {
|
||||
// console.log('苹果用户')
|
||||
} else {
|
||||
// console.log('平台未知')
|
||||
}
|
||||
|
||||
//一键登录密钥设置
|
||||
let sdkInfo = '';
|
||||
//设置秘钥
|
||||
if (platform == 'android') {
|
||||
//开启SDK日志打印
|
||||
aLiSDKModule.setLoggerEnable(true);
|
||||
aLiSDKModule.expandAuthPageCheckedScope(true);
|
||||
//禁用物理返回键
|
||||
//aLiSDKModule.closeAuthPageReturnBack(true);
|
||||
//开启区分界面返回及物理返回功能,自动控制后续返回事件
|
||||
aLiSDKModule.userControlAuthPageCancel();
|
||||
//是否跟随系统深色模式
|
||||
aLiSDKModule.setAuthPageUseDayLight(false);
|
||||
sdkInfo =
|
||||
'cvJWYFO9s7xgJrzD+Ok2m2kCh3x0kdRkfJzGI0oxnyUXGlNAwAzvj87Yd6y030BWposVHUT84av2adBG9SdHl5CJpL0mGi+BRtachnyADJjfdpkJC0e0Uqb45pO7h7ZZvT+sNWQs1sa4JpL0U7hYKkgCP1iVXHoA1zKfzZynON6eKyvkzL1xpoPPag4O50slww4+6XuRVplCOSNCcsLRtot4CYnfsdcMvlV34MY5qB/rV+HNb1velpx4rg5atk3iTEiSLjla69c6pOT6vpjkK1qFVpNMxrEY';
|
||||
} else if (platform == 'ios') {
|
||||
sdkInfo =
|
||||
'BONXQSabNMt1a8Cru1TjeW94aXen5rQHeAxzLGgpFzIUicDYeb9SD0l35MkKvjq7gQemE2HDp6B7adKZ8nrdUk4wgg1LIYSGDYVSc/Q1CwrJ9A3lMUeBfS1UUu3nBBg58bDvG1bl3j6tS4h6FjnYmP5+dDsyqb0YNmIhlSmia5Et7cfBMv2OT85N9WLJc/tOMQ9ZQCnuizKVlofkmDGFgjsBN/Bf2gLq6lTQyVqsgPJE5yEPd4riNg=='
|
||||
}
|
||||
aLiSDKModule.setAuthSDKInfo(sdkInfo)
|
||||
|
||||
|
||||
|
||||
// await uploadApp.uploadApp('onLaunch');
|
||||
// #endif
|
||||
|
||||
|
||||
console.log('App Launch')
|
||||
this.globalData.deviceId = uni.getDeviceInfo().deviceId;
|
||||
// this.globalData.deviceid = 'AC6F605124DFA87DCE40D5C062C94C3B';
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
if (uni.getStorageSync('refreshToken')) {
|
||||
let endTime = uni.getStorageSync('refresh_token_expries');
|
||||
endTime = new Date(endTime)
|
||||
// 当前系统时间
|
||||
var nowTime = new Date();
|
||||
var residueTime = (endTime.getTime() - nowTime.getTime() / 1000);
|
||||
// 4小时 14400
|
||||
if (residueTime < 4 * 60 * 60) {
|
||||
console.log('----------------------------')
|
||||
|
||||
uni.removeStorageSync('accessToken')
|
||||
uni.removeStorageSync('refreshToken')
|
||||
},
|
||||
onLaunch: async function() {
|
||||
// #ifdef APP-PLUS
|
||||
uni.hideTabBar();
|
||||
if (uni.getStorageSync('accessToken')) {
|
||||
registPush()
|
||||
//跟新底部消息数量
|
||||
this.messageUpudateNum()
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
if (wx.getStorageSync('refreshToken')) {
|
||||
let endTime = wx.getStorageSync('refresh_token_expries');
|
||||
endTime = new Date(endTime)
|
||||
// 当前系统时间
|
||||
var nowTime = new Date();
|
||||
var residueTime = (endTime.getTime() - nowTime.getTime() / 1000);
|
||||
// 4小时 14400
|
||||
if (residueTime < 4 * 60 * 60) {
|
||||
console.log('----------------------------')
|
||||
// #endif
|
||||
|
||||
//缓存手机版本号
|
||||
// await setVersion()
|
||||
|
||||
wx.removeStorageSync('accessToken')
|
||||
wx.removeStorageSync('refreshToken')
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
onShow: function () {
|
||||
uni.hideTabBar();
|
||||
console.log('App Show')
|
||||
uni.$emit('appShowRefresh')
|
||||
},
|
||||
onHide: function () {
|
||||
console.log('App Hide')
|
||||
},
|
||||
methods: {
|
||||
// 验证登陆的全局方法
|
||||
verifyLogin() {
|
||||
if (!vuex.state.userInfo.token) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '您需要登陆后才能进行此操作',
|
||||
confirmColor: '#F1AC66',
|
||||
success(e) {
|
||||
if (e.confirm) {
|
||||
// uni.oprPresentLogin()
|
||||
uni.navigateTo({
|
||||
url: '/pages/blogPopup/blogPopup'
|
||||
});
|
||||
}
|
||||
//获取访问路由
|
||||
// 发起 GET 请求
|
||||
let version = uni.getStorageSync('setVersion')
|
||||
let baseUrl
|
||||
await uni.request({
|
||||
url: 'https://api.mrrwlkj.top/api/openPuc/getSjApiUrl', // 接口地址
|
||||
method: 'GET', // 请求方法(默认 GET)
|
||||
header: {
|
||||
'Content-Type': 'application/json', // 请求头
|
||||
'VersionCode': version.VersionCode,
|
||||
'DeviceBrand': version.DeviceBrand,
|
||||
'DeviceType': version.DeviceType
|
||||
},
|
||||
success: (res) => {
|
||||
|
||||
if (res.data.code == 200) {
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.setStorageSync('baseUrl', res.data.data.url)
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.setStorageSync('baseUrl', res.data.data.url)
|
||||
// #endif
|
||||
this.$store.commit("setLocation", true)
|
||||
}
|
||||
})
|
||||
console.log('请求成功', res.data);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('请求失败', err);
|
||||
},
|
||||
complete: () => {
|
||||
console.log('请求完成(无论成功失败都会执行)');
|
||||
}
|
||||
});
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
//禁止手机横屏
|
||||
plus.screen.lockOrientation("portrait-primary")
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
//权限提示监听
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
let platform = systemInfo.platform;
|
||||
if (platform === 'android') {
|
||||
// console.log('安卓用户')
|
||||
permissionListener()
|
||||
} else if (platform === 'ios') {
|
||||
// console.log('苹果用户')
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 区/县adcode转换为6位市adcode(后两位补0)
|
||||
* @param {string|number} districtAdcode - 6位区/县编码(字符串或数字类型)
|
||||
* @returns {string|null} 6位市编码,无效编码返回null
|
||||
*/
|
||||
districtAdcodeTo6DigitCityAdcode(districtAdcode) {
|
||||
// 1. 统一转换为字符串并去除空格
|
||||
const adcodeStr = String(districtAdcode).trim();
|
||||
|
||||
// 2. 验证编码有效性(6位数字)
|
||||
const adcodeReg = /^\d{6}$/;
|
||||
if (!adcodeReg.test(adcodeStr)) {
|
||||
console.warn('无效的区/县编码,必须是6位数字');
|
||||
return null;
|
||||
// console.log('平台未知')
|
||||
}
|
||||
|
||||
// 3. 截取前4位 + 拼接"00" → 6位市编码
|
||||
const cityAdcode4Digit = adcodeStr.slice(0, 4);
|
||||
const cityAdcode6Digit = cityAdcode4Digit + '00';
|
||||
|
||||
// 4. 可选验证:确保结果为6位数字
|
||||
if (!/^\d{6}$/.test(cityAdcode6Digit)) {
|
||||
console.warn('编码转换异常');
|
||||
return null;
|
||||
//一键登录密钥设置
|
||||
let sdkInfo = '';
|
||||
//设置秘钥
|
||||
if (platform == 'android') {
|
||||
//开启SDK日志打印
|
||||
aLiSDKModule.setLoggerEnable(true);
|
||||
aLiSDKModule.expandAuthPageCheckedScope(true);
|
||||
//禁用物理返回键
|
||||
//aLiSDKModule.closeAuthPageReturnBack(true);
|
||||
//开启区分界面返回及物理返回功能,自动控制后续返回事件
|
||||
aLiSDKModule.userControlAuthPageCancel();
|
||||
//是否跟随系统深色模式
|
||||
aLiSDKModule.setAuthPageUseDayLight(false);
|
||||
sdkInfo =
|
||||
'cvJWYFO9s7xgJrzD+Ok2m2kCh3x0kdRkfJzGI0oxnyUXGlNAwAzvj87Yd6y030BWposVHUT84av2adBG9SdHl5CJpL0mGi+BRtachnyADJjfdpkJC0e0Uqb45pO7h7ZZvT+sNWQs1sa4JpL0U7hYKkgCP1iVXHoA1zKfzZynON6eKyvkzL1xpoPPag4O50slww4+6XuRVplCOSNCcsLRtot4CYnfsdcMvlV34MY5qB/rV+HNb1velpx4rg5atk3iTEiSLjla69c6pOT6vpjkK1qFVpNMxrEY';
|
||||
} else if (platform == 'ios') {
|
||||
sdkInfo =
|
||||
'BONXQSabNMt1a8Cru1TjeW94aXen5rQHeAxzLGgpFzIUicDYeb9SD0l35MkKvjq7gQemE2HDp6B7adKZ8nrdUk4wgg1LIYSGDYVSc/Q1CwrJ9A3lMUeBfS1UUu3nBBg58bDvG1bl3j6tS4h6FjnYmP5+dDsyqb0YNmIhlSmia5Et7cfBMv2OT85N9WLJc/tOMQ9ZQCnuizKVlofkmDGFgjsBN/Bf2gLq6lTQyVqsgPJE5yEPd4riNg=='
|
||||
}
|
||||
aLiSDKModule.setAuthSDKInfo(sdkInfo)
|
||||
|
||||
return cityAdcode6Digit;
|
||||
|
||||
|
||||
// await uploadApp.uploadApp('onLaunch');
|
||||
// #endif
|
||||
|
||||
|
||||
console.log('App Launch')
|
||||
this.globalData.deviceId = uni.getDeviceInfo().deviceId;
|
||||
// this.globalData.deviceid = 'AC6F605124DFA87DCE40D5C062C94C3B';
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
if (uni.getStorageSync('refreshToken')) {
|
||||
let endTime = uni.getStorageSync('refresh_token_expries');
|
||||
endTime = new Date(endTime)
|
||||
// 当前系统时间
|
||||
var nowTime = new Date();
|
||||
var residueTime = (endTime.getTime() - nowTime.getTime() / 1000);
|
||||
// 4小时 14400
|
||||
if (residueTime < 4 * 60 * 60) {
|
||||
console.log('----------------------------')
|
||||
|
||||
uni.removeStorageSync('accessToken')
|
||||
uni.removeStorageSync('refreshToken')
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
if (wx.getStorageSync('refreshToken')) {
|
||||
let endTime = wx.getStorageSync('refresh_token_expries');
|
||||
endTime = new Date(endTime)
|
||||
// 当前系统时间
|
||||
var nowTime = new Date();
|
||||
var residueTime = (endTime.getTime() - nowTime.getTime() / 1000);
|
||||
// 4小时 14400
|
||||
if (residueTime < 4 * 60 * 60) {
|
||||
console.log('----------------------------')
|
||||
|
||||
wx.removeStorageSync('accessToken')
|
||||
wx.removeStorageSync('refreshToken')
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
// 更新全局定位
|
||||
updateAddress(item) {
|
||||
console.log('item', item)
|
||||
let location = item.location.split(',');
|
||||
this.globalData.latitude = location[1];
|
||||
this.globalData.longitude = location[0];
|
||||
this.globalData.address = item.name;
|
||||
this.globalData.servers_region = `${item.pname}-${item.cityname}-${item.adname}`;
|
||||
this.globalData.pcode = item.pcode;
|
||||
this.globalData.cCode = this.districtAdcodeTo6DigitCityAdcode(item.adcode);
|
||||
this.globalData.adcode = item.adcode;
|
||||
//存储用户定位
|
||||
this.globalData.addressRes.latitude = location[1];
|
||||
this.globalData.addressRes.longitude = location[0];
|
||||
this.globalData.addressRes.address.province = item.pname;
|
||||
this.globalData.addressRes.address.city = item.cityname;
|
||||
this.globalData.addressRes.address.district = item.adname;
|
||||
this.globalData.addressRes.address.street = item.address;
|
||||
this.globalData.addressRes.address.poiName = item.name;
|
||||
this.globalData.addressRes.address.streetNum = '';
|
||||
this.globalData.addressRes.address.cityCode = '';
|
||||
this.globalData.addressRes.address.pcode = item.pcode;
|
||||
this.globalData.addressRes.address.cCode = this.districtAdcodeTo6DigitCityAdcode(item.adcode);
|
||||
this.globalData.addressRes.address.adcode = item.adcode;
|
||||
this.globalData.addressRes.pcode = item.pcode;
|
||||
this.globalData.addressRes.cCode = this.districtAdcodeTo6DigitCityAdcode(item.adcode);
|
||||
this.globalData.addressRes.adcode = item.adcode;
|
||||
console.log('globalData', this.globalData)
|
||||
uni.setStorageSync('userAdrees', this.globalData)
|
||||
onShow: function() {
|
||||
uni.hideTabBar();
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
},
|
||||
methods: {
|
||||
// 验证登陆的全局方法
|
||||
verifyLogin() {
|
||||
if (!vuex.state.userInfo.token) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '您需要登陆后才能进行此操作',
|
||||
confirmColor: '#F1AC66',
|
||||
success(e) {
|
||||
if (e.confirm) {
|
||||
// uni.oprPresentLogin()
|
||||
uni.navigateTo({
|
||||
url: '/pages/blogPopup/blogPopup'
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 区/县adcode转换为6位市adcode(后两位补0)
|
||||
* @param {string|number} districtAdcode - 6位区/县编码(字符串或数字类型)
|
||||
* @returns {string|null} 6位市编码,无效编码返回null
|
||||
*/
|
||||
districtAdcodeTo6DigitCityAdcode(districtAdcode) {
|
||||
// 1. 统一转换为字符串并去除空格
|
||||
const adcodeStr = String(districtAdcode).trim();
|
||||
|
||||
// 2. 验证编码有效性(6位数字)
|
||||
const adcodeReg = /^\d{6}$/;
|
||||
if (!adcodeReg.test(adcodeStr)) {
|
||||
console.warn('无效的区/县编码,必须是6位数字');
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3. 截取前4位 + 拼接"00" → 6位市编码
|
||||
const cityAdcode4Digit = adcodeStr.slice(0, 4);
|
||||
const cityAdcode6Digit = cityAdcode4Digit + '00';
|
||||
|
||||
// 4. 可选验证:确保结果为6位数字
|
||||
if (!/^\d{6}$/.test(cityAdcode6Digit)) {
|
||||
console.warn('编码转换异常');
|
||||
return null;
|
||||
}
|
||||
|
||||
return cityAdcode6Digit;
|
||||
},
|
||||
// 更新全局定位
|
||||
updateAddress(item) {
|
||||
console.log('item', item)
|
||||
let location = item.location.split(',');
|
||||
this.globalData.latitude = location[1];
|
||||
this.globalData.longitude = location[0];
|
||||
this.globalData.address = item.name;
|
||||
this.globalData.servers_region = `${item.pname}-${item.cityname}-${item.adname}`;
|
||||
this.globalData.pcode = item.pcode;
|
||||
this.globalData.cCode = this.districtAdcodeTo6DigitCityAdcode(item.adcode);
|
||||
this.globalData.adcode = item.adcode;
|
||||
//存储用户定位
|
||||
this.globalData.addressRes.latitude = location[1];
|
||||
this.globalData.addressRes.longitude = location[0];
|
||||
this.globalData.addressRes.address.province = item.pname;
|
||||
this.globalData.addressRes.address.city = item.cityname;
|
||||
this.globalData.addressRes.address.district = item.adname;
|
||||
this.globalData.addressRes.address.street = item.address;
|
||||
this.globalData.addressRes.address.poiName = item.name;
|
||||
this.globalData.addressRes.address.streetNum = '';
|
||||
this.globalData.addressRes.address.cityCode = '';
|
||||
this.globalData.addressRes.address.pcode = item.pcode;
|
||||
this.globalData.addressRes.address.cCode = this.districtAdcodeTo6DigitCityAdcode(item.adcode);
|
||||
this.globalData.addressRes.address.adcode = item.adcode;
|
||||
this.globalData.addressRes.pcode = item.pcode;
|
||||
this.globalData.addressRes.cCode = this.districtAdcodeTo6DigitCityAdcode(item.adcode);
|
||||
this.globalData.addressRes.adcode = item.adcode;
|
||||
console.log('globalData', this.globalData)
|
||||
uni.setStorageSync('userAdrees', this.globalData)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/*每个页面公共css */
|
||||
@import '@/static/css/common.css';
|
||||
|
||||
/* App.vue全局style */
|
||||
page,
|
||||
html,
|
||||
body {
|
||||
-webkit-text-size-adjust: 100% !important;
|
||||
text-size-adjust: 100% !important;
|
||||
}
|
||||
</style>
|
||||
/*每个页面公共css */
|
||||
@import '@/static/css/common.css';
|
||||
</style>
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
# 改动记录
|
||||
|
||||
## 2026-06-12
|
||||
|
||||
### 后台长时间运行后首页登录态不同步
|
||||
|
||||
问题现象:
|
||||
|
||||
- APP 后台运行较长时间后再次进入。
|
||||
- 商家首页显示未登录或无法及时获取商家信息。
|
||||
- “我的”页面仍显示已登录。
|
||||
- 从“我的”页面切回首页后,首页才能正常获取商家信息。
|
||||
|
||||
涉及文件:
|
||||
|
||||
- `App.vue`
|
||||
- `pages/home/home.vue`
|
||||
- `utils/request.js`
|
||||
|
||||
改动内容:
|
||||
|
||||
- `App.vue`
|
||||
- 在全局 `onShow` 中新增 `uni.$emit('appShowRefresh')`。
|
||||
- APP 从后台恢复前台时主动通知页面刷新状态,避免只依赖页面级 `onShow`。
|
||||
|
||||
- `pages/home/home.vue`
|
||||
- 新增 `refreshPageState` 方法,统一处理首页登录态刷新。
|
||||
- `onShow`、下拉刷新、APP 前台恢复事件都调用同一套刷新逻辑。
|
||||
- `onLoad` 注册 `appShowRefresh` 事件。
|
||||
- `onUnload` 解除 `appShowRefresh` 事件,避免重复监听。
|
||||
- 有 token 时主动重新请求 `/sj/user/getUser`。
|
||||
- 无 token 时清空 `userInfo`、`authDetails`、`sjId`,并重置 `isUserInfoLoaded`。
|
||||
- `getUserInfo` 请求成功后显式设置 `isLogin = true` 和 `isUserInfoLoaded = true`。
|
||||
- `getUserInfo` 请求失败时,如果本地 token 已被清理,则同步首页为未登录状态。
|
||||
|
||||
- `utils/request.js`
|
||||
- `refreshToken` 兼容后端返回结构:
|
||||
- 支持 token 在 `res.access_token`。
|
||||
- 支持 token 在 `res.data.access_token`。
|
||||
- 刷新 token 成功后同步更新:
|
||||
- `accessToken`
|
||||
- `refreshToken`
|
||||
- `refresh_token_expries`
|
||||
- 如果刷新接口成功但没有返回 `access_token`,主动抛错,避免写入 `undefined` token。
|
||||
|
||||
验证情况:
|
||||
|
||||
- 已检查相关 diff,未做全文件重构。
|
||||
- `pages/home/home.vue` 原文件为 CRLF 行尾;为避免整文件行尾改造造成大面积 diff,本次保留原行尾。
|
||||
- 项目 `package.json` 未配置 build/lint 脚本,未执行完整构建校验。
|
||||
|
||||
### 订单详情顾客头像被挤压
|
||||
|
||||
问题现象:
|
||||
|
||||
- `pages/shop/SellerDetail` 页面“顾客信息”一栏中,客户头像在部分图片比例下显示被拉伸或挤压。
|
||||
|
||||
涉及文件:
|
||||
|
||||
- `pages/shop/SellerDetail.vue`
|
||||
|
||||
改动内容:
|
||||
|
||||
- 给顾客头像 `<image>` 增加 `mode="aspectFill"`,按头像容器比例裁剪填充,避免原图比例不一致时被拉伸。
|
||||
- 为 `.shop_photo` 增加 `min-width` 和 `min-height`,在 flex 布局中进一步锁定头像为固定正方形尺寸。
|
||||
|
||||
验证情况:
|
||||
|
||||
- 已执行 `pages/shop/SellerDetail.vue` 与 `CHANGE_RECORD.md` 的空白格式检查。
|
||||
|
||||
### 核销成功后工时/工位订单详情跳转错误
|
||||
|
||||
问题现象:
|
||||
|
||||
- 商家扫码核销或输入核销码核销成功后,工时订单和工位订单跳转到详情页时参数或页面类型不正确。
|
||||
- 工时订单会进入工位详情链路,工位订单会落到普通订单详情链路。
|
||||
|
||||
涉及文件:
|
||||
|
||||
- `pages/shop/verify/verify-order-detail.vue`
|
||||
|
||||
改动内容:
|
||||
|
||||
- 新增 `getOrderDetailUrl`,统一按 `order_type` 生成核销成功后的详情页地址。
|
||||
- `order_type=3` 工时订单跳转到 `/pages/shop/SellerDetail?order_id=...&identity=1`,使用手艺人工时订单详情链路。
|
||||
- `order_type=4` 工位订单跳转到 `/pages/shop/SellerDetail?order_id=...`,使用商家工位订单详情链路。
|
||||
- `order_type=6` 自营订单跳转普通订单详情并携带 `serviceType=2`。
|
||||
- 其他普通订单跳转普通订单详情,不再误携带自营参数。
|
||||
|
||||
验证情况:
|
||||
|
||||
- 已执行 `pages/shop/verify/verify-order-detail.vue` 与 `CHANGE_RECORD.md` 的空白格式检查。
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
// 引入 spark-md5 计算文件哈希
|
||||
import SparkMD5 from 'spark-md5'
|
||||
|
|
@ -41,7 +42,7 @@ export default {
|
|||
maxSize: {
|
||||
type: Number,
|
||||
default: 500
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -52,7 +53,7 @@ export default {
|
|||
fileMd5: '',
|
||||
cancelToken: null
|
||||
};
|
||||
},
|
||||
}
|
||||
methods: {
|
||||
// 选择视频文件
|
||||
async chooseVideo() {
|
||||
|
|
@ -318,7 +319,7 @@ export default {
|
|||
chunkIndex,
|
||||
fileMd5: this.fileMd5,
|
||||
chunkSize: this.chunkSize,
|
||||
totalChunks: Math.ceil(this.file.size / this.chunkSize)
|
||||
totalChunks: Math.ceil(this.file.size / this.chunkSize))
|
||||
},
|
||||
header: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
|
|
@ -410,4 +411,4 @@ button {
|
|||
color: #666;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -95,7 +95,7 @@ export default {
|
|||
color: #999;
|
||||
}
|
||||
.tab-text.active {
|
||||
color: #FF4767; /* 选中颜色 */
|
||||
color: #E8101E; /* 选中颜色 */
|
||||
}
|
||||
.tab-badge {
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
v-for="(file, index) in videoList"
|
||||
:key="file || index"
|
||||
class="preview-item"
|
||||
@click="previewVideo(file)"
|
||||
>
|
||||
<!-- <video
|
||||
:src="file"
|
||||
|
|
@ -58,11 +57,6 @@
|
|||
@click="handlePreview(index)"
|
||||
/> -->
|
||||
<image class="preview-image" :src="getVideoPoster(file)" mode="aspectFill"></image>
|
||||
<view class="video-play-mask">
|
||||
<view class="video-play-circle">
|
||||
<view class="video-play-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
<image
|
||||
v-if="deletable"
|
||||
class="delete-icon"
|
||||
|
|
@ -87,14 +81,6 @@
|
|||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="showVideoPlayer" class="video-player-mask" @click="closeVideoPlayer">
|
||||
<view class="video-player-box" @click.stop>
|
||||
<video :src="previewVideoUrl" class="video-player" controls autoplay show-fullscreen-btn></video>
|
||||
<view class="video-player-close" @click="closeVideoPlayer">
|
||||
<text class="video-player-close-text">×</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 提示文字 -->
|
||||
<!-- <text v-if="tips" class="tips-text">{{ tips }}</text> -->
|
||||
|
||||
|
|
@ -111,12 +97,12 @@ export default {
|
|||
props: {
|
||||
// 已上传文件列表
|
||||
value: {
|
||||
type: [Array, String, Object],
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 单个上传文件
|
||||
fileString: {
|
||||
type: [String, Object, Array],
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 按钮文字
|
||||
|
|
@ -187,12 +173,10 @@ export default {
|
|||
fileList: [],
|
||||
oneFile: '',
|
||||
videoList: [],
|
||||
loading: false,
|
||||
loading: false,
|
||||
dragIndex: -1,
|
||||
isDragging: false,
|
||||
suppressPreview: false,
|
||||
showVideoPlayer: false,
|
||||
previewVideoUrl: ''
|
||||
suppressPreview: false
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -206,57 +190,19 @@ export default {
|
|||
value: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (this.accept === 'video/*') {
|
||||
const videoValue = this.normalizeVideoValue(newVal)
|
||||
this.oneFile = videoValue
|
||||
this.videoList = videoValue ? [videoValue] : []
|
||||
return
|
||||
}
|
||||
this.fileList = Array.isArray(newVal) ? [...newVal] : []
|
||||
this.fileList = [...newVal]
|
||||
}
|
||||
},
|
||||
fileString: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
const videoValue = this.normalizeVideoValue(newVal)
|
||||
this.oneFile = videoValue
|
||||
this.videoList = videoValue ? [videoValue] : []
|
||||
this.oneFile = newVal
|
||||
this.videoList = newVal ? [newVal] : []
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
normalizeVideoValue(value) {
|
||||
if (!value) return ''
|
||||
if (typeof value === 'string') {
|
||||
const str = value.trim()
|
||||
if (!str) return ''
|
||||
if ((str.startsWith('{') && str.endsWith('}')) || (str.startsWith('[') && str.endsWith(']'))) {
|
||||
try {
|
||||
return this.normalizeVideoValue(JSON.parse(str))
|
||||
} catch (error) {
|
||||
return str
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) {
|
||||
const url = this.normalizeVideoValue(item)
|
||||
if (url) return url
|
||||
}
|
||||
return ''
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
const candidates = [value.url, value.path, value.filePath, value.tempFilePath, value.src, value.value]
|
||||
for (const item of candidates) {
|
||||
const url = this.normalizeVideoValue(item)
|
||||
if (url) return url
|
||||
}
|
||||
return ''
|
||||
}
|
||||
return String(value)
|
||||
},
|
||||
|
||||
// 显示权限说明弹窗
|
||||
showPermissionDialog(title, content) {
|
||||
|
|
@ -373,9 +319,8 @@ export default {
|
|||
},
|
||||
// 上传文件到OSS
|
||||
async uploadFile(file) {
|
||||
const uploadFile = await this.prepareUploadFile(file)
|
||||
// 检查文件大小
|
||||
if (uploadFile.size > this.maxSize * 1024 * 1024) {
|
||||
if (file.size > this.maxSize * 1024 * 1024) {
|
||||
uni.showToast({
|
||||
title: `文件大小不能超过${this.maxSize}MB`,
|
||||
icon: 'none'
|
||||
|
|
@ -383,7 +328,7 @@ export default {
|
|||
return Promise.reject(new Error('文件大小超出限制'))
|
||||
}
|
||||
let date = `${new Date().getTime()}_${Math.floor(Math.random() * 100000)}`
|
||||
const fileExt = this.getFileExt(uploadFile)
|
||||
const fileExt = this.getFileExt(file)
|
||||
|
||||
let artisan = this.type==1 ? 'yh' : this.type==2 ? 'syr' : this.type==3 ? 'sj' : '';
|
||||
let name = `${this.userId}_${artisan}_${date}.${fileExt}`
|
||||
|
|
@ -392,7 +337,7 @@ export default {
|
|||
// 1. 获取OSS上传凭证
|
||||
const ossConfig = await this.getOssConfig()
|
||||
// 2. 上传文件
|
||||
const fileUrl = await this.uploadToOss(uploadFile, ossConfig, name)
|
||||
const fileUrl = await this.uploadToOss(file, ossConfig, name)
|
||||
// 3. 添加到文件列表
|
||||
if(this.accept == 'image/*') {
|
||||
const newFile = [`${fileUrl}`]
|
||||
|
|
@ -434,90 +379,10 @@ export default {
|
|||
|
||||
getFileExt(file) {
|
||||
const defaultExt = this.accept === 'video/*' ? 'mp4' : 'jpg'
|
||||
const sources = this.accept === 'video/*'
|
||||
? [file && file.tempFilePath, file && file.path, file && file.url, file && file.name]
|
||||
: [file && file.path, file && file.tempFilePath, file && file.url, file && file.name]
|
||||
for (const source of sources) {
|
||||
const cleanPath = String(source || '').split('?')[0].split('#')[0]
|
||||
const ext = cleanPath.includes('.') ? cleanPath.split('.').pop().toLowerCase() : ''
|
||||
if (/^[a-z0-9]+$/.test(ext)) return ext
|
||||
}
|
||||
return defaultExt
|
||||
},
|
||||
|
||||
getFilePath(file) {
|
||||
if (!file) return ''
|
||||
return file.tempFilePath || file.path || file.url || file.name || ''
|
||||
},
|
||||
|
||||
getMimeType(file, name) {
|
||||
const ext = this.getFileExt({ tempFilePath: name, path: name, name })
|
||||
const mimeTypes = {
|
||||
jpg: 'image/jpeg',
|
||||
jpeg: 'image/jpeg',
|
||||
png: 'image/png',
|
||||
gif: 'image/gif',
|
||||
webp: 'image/webp',
|
||||
mp4: 'video/mp4',
|
||||
m4v: 'video/x-m4v',
|
||||
mov: 'video/quicktime',
|
||||
qt: 'video/quicktime',
|
||||
webm: 'video/webm',
|
||||
mpeg: 'video/mpeg',
|
||||
mpg: 'video/mpeg',
|
||||
avi: 'video/x-msvideo',
|
||||
'3gp': 'video/3gpp',
|
||||
mkv: 'video/x-matroska',
|
||||
}
|
||||
return mimeTypes[ext] || (file && file.type) || ''
|
||||
},
|
||||
|
||||
buildOssFormData(ossConfig, objectKey, mimeType) {
|
||||
const formData = {
|
||||
key: objectKey,
|
||||
policy: ossConfig.policy,
|
||||
OSSAccessKeyId: ossConfig.ossAccessKeyId,
|
||||
success_action_status: '200',
|
||||
signature: ossConfig.signature,
|
||||
}
|
||||
if (mimeType) {
|
||||
formData['Content-Type'] = mimeType
|
||||
formData['x-oss-meta-content-type'] = mimeType
|
||||
}
|
||||
return formData
|
||||
},
|
||||
|
||||
async prepareUploadFile(file) {
|
||||
if (this.accept !== 'video/*') return file
|
||||
const filePath = this.getFilePath(file)
|
||||
const fileExt = this.getFileExt(file)
|
||||
if (!filePath || fileExt === 'mp4' || typeof uni.compressVideo !== 'function') {
|
||||
return file
|
||||
}
|
||||
try {
|
||||
const res = await uni.compressVideo({
|
||||
src: filePath,
|
||||
quality: 'medium'
|
||||
})
|
||||
const tempFilePath = res.tempFilePath || res.path
|
||||
if (!tempFilePath) return file
|
||||
return {
|
||||
...file,
|
||||
tempFilePath,
|
||||
path: tempFilePath,
|
||||
size: res.size || file.size,
|
||||
name: this.replaceFileExt(file.name, 'mp4'),
|
||||
type: 'video/mp4'
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('视频压缩失败,使用原文件上传:', error)
|
||||
return file
|
||||
}
|
||||
},
|
||||
|
||||
replaceFileExt(name, ext) {
|
||||
if (!name) return ''
|
||||
return String(name).replace(/\.[^.]+$/, `.${ext}`)
|
||||
const source = file && (file.name || file.tempFilePath || file.path || file.url || '')
|
||||
const cleanPath = String(source).split('?')[0].split('#')[0]
|
||||
const ext = cleanPath.includes('.') ? cleanPath.split('.').pop().toLowerCase() : ''
|
||||
return /^[a-z0-9]+$/.test(ext) ? ext : defaultExt
|
||||
},
|
||||
|
||||
buildFileUrl(ossConfig, name) {
|
||||
|
|
@ -538,21 +403,6 @@ export default {
|
|||
},
|
||||
|
||||
chooseVideoFiles(sourceType, count) {
|
||||
if (count <= 1 && typeof uni.chooseVideo === 'function') {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.chooseVideo({
|
||||
sourceType: [sourceType],
|
||||
compressed: true,
|
||||
maxDuration: 60,
|
||||
success: (res) => resolve([{
|
||||
...res,
|
||||
tempFilePath: res.tempFilePath || res.path,
|
||||
path: res.tempFilePath || res.path,
|
||||
}]),
|
||||
fail: reject,
|
||||
});
|
||||
});
|
||||
}
|
||||
if (uni.chooseMedia) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.chooseMedia({
|
||||
|
|
@ -588,20 +438,14 @@ export default {
|
|||
return new Promise((resolve, reject) => {
|
||||
const objectKey = this.buildObjectKey(ossConfig, name)
|
||||
const fileUrl = this.buildFileUrl(ossConfig, name)
|
||||
const mimeType = this.getMimeType(file, name)
|
||||
let formData;
|
||||
// #ifdef H5
|
||||
formData = new FormData()
|
||||
// #ifdef H5
|
||||
const formData = new FormData()
|
||||
formData.append('name',name);
|
||||
formData.append('policy', ossConfig.policy);
|
||||
formData.append('OSSAccessKeyId', ossConfig.ossAccessKeyId);
|
||||
formData.append('success_action_status', '200');
|
||||
formData.append('signature', ossConfig.signature);
|
||||
formData.append('key', objectKey);
|
||||
if (mimeType) {
|
||||
formData.append('Content-Type', mimeType);
|
||||
formData.append('x-oss-meta-content-type', mimeType);
|
||||
}
|
||||
// file必须为最后一个表单域,除file以外的其他表单域无顺序要求。
|
||||
formData.append('file', file.file || file.tempFile || file);
|
||||
fetch(ossConfig.host, { method: 'POST', body: formData},).then((res) => {
|
||||
|
|
@ -615,18 +459,24 @@ export default {
|
|||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS || MP-WEIXIN
|
||||
formData = this.buildOssFormData(ossConfig, objectKey, mimeType);
|
||||
formData.name = name;
|
||||
// #ifdef APP-PLUS || MP-WEIXIN
|
||||
let formData = {};
|
||||
formData.name = name;
|
||||
formData.policy = ossConfig.policy;
|
||||
formData.OSSAccessKeyId = ossConfig.ossAccessKeyId;
|
||||
formData.success_action_status = '200';
|
||||
formData.signature = ossConfig.signature;
|
||||
formData.key = objectKey;
|
||||
formData.file = file;
|
||||
let path;
|
||||
if(this.accept == 'image/*') {
|
||||
path = this.getFilePath(file)
|
||||
path = file.path
|
||||
}else if(this.accept == 'video/*') {
|
||||
// #ifdef H5
|
||||
path = this.getFilePath(file)
|
||||
path = file.name
|
||||
// #endif
|
||||
// #ifdef APP-PLUS || MP-WEIXIN
|
||||
path = this.getFilePath(file)
|
||||
path = file.tempFilePath
|
||||
// #endif
|
||||
}
|
||||
// 使用 uni.uploadFile 上传文件(支持多平台)
|
||||
|
|
@ -634,7 +484,13 @@ export default {
|
|||
url: ossConfig.host,
|
||||
filePath: path, // 手机端文件路径
|
||||
name: 'file',
|
||||
formData,
|
||||
formData: {
|
||||
key: objectKey, // 文件名
|
||||
policy: ossConfig.policy, // 后台获取超时时间
|
||||
OSSAccessKeyId: ossConfig.ossAccessKeyId, // 后台获取临时ID
|
||||
success_action_status: 200, // 让服务端返回200,不然,默认会返回204
|
||||
signature: ossConfig.signature // 后台获取签名
|
||||
},
|
||||
success: (res) => {
|
||||
const statusCode = Number(res.statusCode)
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
|
|
@ -661,17 +517,6 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
previewVideo(url) {
|
||||
if (!url) return
|
||||
this.previewVideoUrl = url
|
||||
this.showVideoPlayer = true
|
||||
},
|
||||
|
||||
closeVideoPlayer() {
|
||||
this.showVideoPlayer = false
|
||||
this.previewVideoUrl = ''
|
||||
},
|
||||
|
||||
startDrag(index) {
|
||||
if (!this.sortable || this.accept !== 'image/*' || this.fileList.length < 2) return
|
||||
this.dragIndex = index
|
||||
|
|
@ -817,38 +662,6 @@ export default {
|
|||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.video-play-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.18);
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.video-play-circle {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.55);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.video-play-icon {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 14rpx solid transparent;
|
||||
border-bottom: 14rpx solid transparent;
|
||||
border-left: 22rpx solid #fff;
|
||||
margin-left: 6rpx;
|
||||
}
|
||||
|
||||
.delete-icon {
|
||||
position: absolute;
|
||||
top: -10rpx;
|
||||
|
|
@ -857,50 +670,4 @@ export default {
|
|||
height: 42rpx;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.video-player-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.video-player-box {
|
||||
position: relative;
|
||||
width: 690rpx;
|
||||
background-color: #000;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-player {
|
||||
width: 690rpx;
|
||||
height: 388rpx;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.video-player-close {
|
||||
position: absolute;
|
||||
top: 12rpx;
|
||||
right: 12rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.55);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.video-player-close-text {
|
||||
color: #fff;
|
||||
font-size: 42rpx;
|
||||
line-height: 52rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export default {
|
|||
// 圆环颜色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#FF4767'
|
||||
default: '#E8101E'
|
||||
},
|
||||
// 背景圆环颜色
|
||||
backgroundColor: {
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ export default {
|
|||
}
|
||||
|
||||
.time-option.active .time-text {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -413,7 +413,7 @@ export default {
|
|||
|
||||
.time-discount {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
padding: 4rpx 12rpx;
|
||||
background-color: #fff5f6;
|
||||
border-radius: 20rpx;
|
||||
|
|
@ -444,7 +444,7 @@ export default {
|
|||
color: #666;
|
||||
}
|
||||
.active {
|
||||
color: #FF4767; /* 选中态主题色 */
|
||||
color: #E8101E; /* 选中态主题色 */
|
||||
}
|
||||
|
||||
/* 服务时间按钮专属:控制下拉图标尺寸 */
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export default {
|
|||
// 已定义的激活色props(无需修改)
|
||||
activeColor: {
|
||||
type: String,
|
||||
default: "#FF4767",
|
||||
default: "#E8101E",
|
||||
},
|
||||
// 已定义的非激活色props(无需修改)
|
||||
inactiveColor: {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export default {
|
|||
// 激活状态的颜色
|
||||
activeColor: {
|
||||
type: String,
|
||||
default: "#FF4767",
|
||||
default: "#E8101E",
|
||||
},
|
||||
// 非激活状态的颜色
|
||||
inactiveColor: {
|
||||
|
|
@ -129,7 +129,7 @@ export default {
|
|||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border: 2rpx solid #FF4767;
|
||||
border: 2rpx solid #E8101E;
|
||||
border-radius: 48rpx;
|
||||
}
|
||||
|
||||
|
|
@ -143,6 +143,6 @@ export default {
|
|||
}
|
||||
|
||||
.icon-item.active .icon-text {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<view class="form-checkbox">
|
||||
<view v-for="(item, index) in options" :key="index" class="checkbox-item" @click="onToggle(item)">
|
||||
<view class="checkbox-dot" :class="{ active: isChecked(item) }"></view>
|
||||
<text class="checkbox-label">{{ getOptionLabel(item) }}</text>
|
||||
<text class="checkbox-label">{{ item }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -16,37 +16,12 @@ export default {
|
|||
maxCount: { type: Number, default: 0 }
|
||||
},
|
||||
methods: {
|
||||
getOptionValue: function (item) {
|
||||
if (item && typeof item === 'object') {
|
||||
if (item.value !== undefined) return item.value;
|
||||
if (item.id !== undefined) return item.id;
|
||||
if (item.key !== undefined) return item.key;
|
||||
if (item.code !== undefined) return item.code;
|
||||
return item.label;
|
||||
}
|
||||
return item;
|
||||
isChecked: function (val) {
|
||||
return this.value && this.value.indexOf(val) !== -1;
|
||||
},
|
||||
getOptionLabel: function (item) {
|
||||
if (item && typeof item === 'object') {
|
||||
var label = item.label || item.title || item.name || item.text;
|
||||
if (label !== undefined && label !== null) return label;
|
||||
return String(this.getOptionValue(item));
|
||||
}
|
||||
return item;
|
||||
},
|
||||
findValueIndex: function (list, value) {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i] == value) return i;
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
isChecked: function (item) {
|
||||
return this.findValueIndex(this.value || [], this.getOptionValue(item)) !== -1;
|
||||
},
|
||||
onToggle: function (item) {
|
||||
var val = this.getOptionValue(item);
|
||||
onToggle: function (val) {
|
||||
var newValue = (this.value || []).slice();
|
||||
var index = this.findValueIndex(newValue, val);
|
||||
var index = newValue.indexOf(val);
|
||||
if (index === -1) {
|
||||
if (this.maxCount > 0 && newValue.length >= this.maxCount) {
|
||||
uni.showToast({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<ali-oss-uploader v-model="currentValue" :max-count="maxCount" :max-size="maxSize" accept="image/*" :userId="computedUserId"
|
||||
:type="computedOssType" width="100%" :sortable="true" @input="onInput" @change="onChange" />
|
||||
<ali-oss-uploader v-model="currentValue" :max-count="maxCount" :max-size="maxSize" accept="image/*" :userId="userId"
|
||||
:type="ossType" width="100%" :sortable="true" @input="onInput" @change="onChange" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -9,29 +9,25 @@ import AliOssUploader from '../ali-oss-uploader/ali-oss-uploader.vue'
|
|||
export default {
|
||||
name: 'FormItemImage',
|
||||
components: { AliOssUploader },
|
||||
props: {
|
||||
value: { type: Array, default: function () { return []; } },
|
||||
maxCount: { type: Number, default: 9 },
|
||||
maxSize: { type: Number, default: 5 },
|
||||
userId: { type: [Number, String], default: null },
|
||||
ossType: { type: [Number, String], default: null }
|
||||
},
|
||||
props: {
|
||||
value: { type: Array, default: function () { return []; } },
|
||||
maxCount: { type: Number, default: 9 },
|
||||
maxSize: { type: Number, default: 5 }
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
currentValue: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
computedUserId: function () {
|
||||
if (this.userId) return this.userId;
|
||||
return this.$store && this.$store.state && this.$store.state.sjInfo
|
||||
? this.$store.state.sjInfo.id : null;
|
||||
},
|
||||
computedOssType: function () {
|
||||
if (this.ossType) return this.ossType;
|
||||
var artisanType = getApp().globalData ? getApp().globalData.artisanType : 0;
|
||||
return (artisanType || 0) + 1;
|
||||
}
|
||||
userId: function () {
|
||||
return this.$store && this.$store.state && this.$store.state.sjInfo
|
||||
? this.$store.state.sjInfo.id : null;
|
||||
},
|
||||
ossType: function () {
|
||||
var artisanType = getApp().globalData ? getApp().globalData.artisanType : 0;
|
||||
return (artisanType || 0) + 1;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<view class="form-radio">
|
||||
<view v-for="(item, index) in options" :key="index" class="radio-item" @click="onSelect(item)">
|
||||
<view class="radio-dot" :class="{ active: isActive(item) }"></view>
|
||||
<text class="radio-label">{{ getOptionLabel(item) }}</text>
|
||||
<view class="radio-dot" :class="{ active: value === item }"></view>
|
||||
<text class="radio-label">{{ item }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -15,29 +15,8 @@ export default {
|
|||
options: { type: Array, default: function () { return []; } }
|
||||
},
|
||||
methods: {
|
||||
getOptionValue: function (item) {
|
||||
if (item && typeof item === 'object') {
|
||||
if (item.value !== undefined) return item.value;
|
||||
if (item.id !== undefined) return item.id;
|
||||
if (item.key !== undefined) return item.key;
|
||||
if (item.code !== undefined) return item.code;
|
||||
return item.label;
|
||||
}
|
||||
return item;
|
||||
},
|
||||
getOptionLabel: function (item) {
|
||||
if (item && typeof item === 'object') {
|
||||
var label = item.label || item.title || item.name || item.text;
|
||||
if (label !== undefined && label !== null) return label;
|
||||
return String(this.getOptionValue(item));
|
||||
}
|
||||
return item;
|
||||
},
|
||||
isActive: function (item) {
|
||||
return this.value == this.getOptionValue(item);
|
||||
},
|
||||
onSelect: function (item) {
|
||||
this.$emit('input', this.getOptionValue(item));
|
||||
onSelect: function (val) {
|
||||
this.$emit('input', val);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<picker :range="displayOptions" @change="onChange">
|
||||
<picker :range="options" @change="onChange">
|
||||
<view class="form-select">
|
||||
<text :class="['select-text', hasValue ? '' : 'placeholder']">
|
||||
{{ hasValue ? selectedLabel : placeholder }}
|
||||
<text :class="['select-text', value ? '' : 'placeholder']">
|
||||
{{ value || placeholder }}
|
||||
</text>
|
||||
<image src="https://mrrplus.oss-cn-beijing.aliyuncs.com/wxstaic/images/arrow_right.png" class="arrow-right"
|
||||
mode="aspectFit" />
|
||||
|
|
@ -18,48 +18,12 @@ export default {
|
|||
options: { type: Array, default: function () { return []; } },
|
||||
placeholder: { type: String, default: '请选择' }
|
||||
},
|
||||
computed: {
|
||||
displayOptions: function () {
|
||||
var self = this;
|
||||
return this.options.map(function (item) {
|
||||
return self.getOptionLabel(item);
|
||||
});
|
||||
},
|
||||
hasValue: function () {
|
||||
return this.value !== undefined && this.value !== null && this.value !== '';
|
||||
},
|
||||
selectedLabel: function () {
|
||||
var self = this;
|
||||
var selected = this.options.find(function (item) {
|
||||
return self.getOptionValue(item) == self.value;
|
||||
});
|
||||
return selected !== undefined ? this.getOptionLabel(selected) : this.value;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getOptionValue: function (item) {
|
||||
if (item && typeof item === 'object') {
|
||||
if (item.value !== undefined) return item.value;
|
||||
if (item.id !== undefined) return item.id;
|
||||
if (item.key !== undefined) return item.key;
|
||||
if (item.code !== undefined) return item.code;
|
||||
return item.label;
|
||||
}
|
||||
return item;
|
||||
},
|
||||
getOptionLabel: function (item) {
|
||||
if (item && typeof item === 'object') {
|
||||
var label = item.label || item.title || item.name || item.text;
|
||||
if (label !== undefined && label !== null) return label;
|
||||
return String(this.getOptionValue(item));
|
||||
}
|
||||
return item;
|
||||
},
|
||||
onChange: function (e) {
|
||||
var index = e.detail.value;
|
||||
var selected = this.options[index];
|
||||
if (selected !== undefined) {
|
||||
this.$emit('input', this.getOptionValue(selected));
|
||||
this.$emit('input', selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,47 +20,16 @@
|
|||
<text class="price-tip-card">{{ group.field.tip }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="group.field.type === 'textarea'" class="detail-row">
|
||||
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label
|
||||
}}</text>
|
||||
<view class="detail-textarea-wrap">
|
||||
<textarea class="detail-textarea" :value="formData[group.field.key]" :placeholder="group.field.placeholder"
|
||||
placeholder-class="placeholder" maxlength="200" @input="onInput(group.field.key, $event)" />
|
||||
<text class="detail-count">{{ (formData[group.field.key] || "").length }}/200</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="group.field.type === 'select'" class="form-item">
|
||||
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label
|
||||
}}</text>
|
||||
<form-item-select :value="formData[group.field.key]" :options="group.field.options || []"
|
||||
:placeholder="group.field.placeholder" @input="onInput(group.field.key, $event)" />
|
||||
</view>
|
||||
<view v-else-if="group.field.type === 'single_select'" class="form-item" style="flex-wrap: wrap;">
|
||||
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label
|
||||
}}</text>
|
||||
<view class="select-options">
|
||||
<form-item-radio :value="formData[group.field.key]" :options="group.field.options || []"
|
||||
@input="onInput(group.field.key, $event)" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="group.field.type === 'multi_select'" class="form-item" style="flex-wrap: wrap;">
|
||||
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label
|
||||
}}</text>
|
||||
<view class="select-options">
|
||||
<form-item-checkbox :value="formData[group.field.key]" :options="group.field.options || []"
|
||||
:maxCount="group.field.maxCount || 0" @input="onInput(group.field.key, $event)" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="group.field.type === 'image_multi'" class="form-item-up upload-item">
|
||||
<view>
|
||||
<text :class="['form-label', group.field.is_required === true ? 'required' : '']">{{ group.field.label
|
||||
}}</text>
|
||||
<text class="upload-tip">(仅可上传{{ group.field.maxCount || 9 }}个图片)</text>
|
||||
</view>
|
||||
<view class="upload-content">
|
||||
<form-item-image :value="formData[group.field.key]" :maxCount="group.field.maxCount || 9"
|
||||
:userId="uploadUserId" @input="onInput(group.field.key, $event)" />
|
||||
</view>
|
||||
<view class="upload-content">
|
||||
<form-item-image :value="formData[group.field.key]" :maxCount="group.field.maxCount || 9"
|
||||
@input="onInput(group.field.key, $event)" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="group.field.type === 'video'" class="form-item-up upload-item">
|
||||
<view>
|
||||
|
|
@ -138,10 +107,10 @@
|
|||
<text :class="['form-label', field.is_required === true ? 'required' : '']">{{ field.label }}</text>
|
||||
<text class="upload-tip">(仅可上传{{ field.maxCount || 9 }}个图片)</text>
|
||||
</view>
|
||||
<view class="upload-content">
|
||||
<form-item-image :value="formData[field.key]" :maxCount="field.maxCount || 9"
|
||||
:userId="uploadUserId" @input="onInput(field.key, $event)" />
|
||||
</view>
|
||||
<view class="upload-content">
|
||||
<form-item-image :value="formData[field.key]" :maxCount="field.maxCount || 9"
|
||||
@input="onInput(field.key, $event)" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="field.type === 'video'" class="form-item-up upload-item no-bg">
|
||||
<view>
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ export default {
|
|||
padding-left: 30rpx;
|
||||
position: relative;
|
||||
&__point {
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
height: 6rpx;
|
||||
width: 6rpx;
|
||||
border-radius: 50%;
|
||||
|
|
@ -221,7 +221,7 @@ export default {
|
|||
}
|
||||
.active {
|
||||
background: #ffffff;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
}
|
||||
&__right {
|
||||
|
|
@ -295,17 +295,17 @@ export default {
|
|||
height: 82rpx;
|
||||
font-weight: 400;
|
||||
font-size: 30rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 42rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
&__sure {
|
||||
border-radius: 41rpx;
|
||||
border: 2rpx solid #FF4767;
|
||||
border: 2rpx solid #E8101E;
|
||||
}
|
||||
&__reset {
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 41rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,8 +114,8 @@ export default {
|
|||
}
|
||||
.active {
|
||||
background: rgba(252, 67, 124, 0.1);
|
||||
color: #FF4767;
|
||||
border: 1rpx solid #FF4767;
|
||||
color: #E8101E;
|
||||
border: 1rpx solid #E8101E;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -548,7 +548,7 @@
|
|||
width: 690rpx;
|
||||
height: 68rpx;
|
||||
background: #FFFFFF;
|
||||
border: 2rpx solid #FF4767;
|
||||
border: 2rpx solid #E8101E;
|
||||
background-color: #fafafa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ export default {
|
|||
border: 1rpx solid #fba9bb;
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
|
|
@ -197,7 +197,7 @@ export default {
|
|||
margin-top: 10rpx;
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export default {
|
|||
.loginBtn {
|
||||
width: 262rpx;
|
||||
height: 86rpx;
|
||||
background: #FF4767;
|
||||
background: #e8101e;
|
||||
border-radius: 43rpx;
|
||||
text-align: center;
|
||||
line-height: 86rpx;
|
||||
|
|
|
|||
|
|
@ -408,11 +408,11 @@ export default {
|
|||
|
||||
.isActive {
|
||||
background: rgba(252, 67, 124, 0.08);
|
||||
color: #FF4767 !important;
|
||||
color: #e8101e !important;
|
||||
}
|
||||
|
||||
.isActive .time-picker-content__time__list__item__text {
|
||||
color: #FF4767 !important;
|
||||
color: #e8101e !important;
|
||||
}
|
||||
|
||||
/* 选中样式前后弧度 */
|
||||
|
|
@ -433,7 +433,7 @@ border-radius: 0rpx 51rpx 51rpx 0rpx}
|
|||
.time-picker-content__time__sure__box {
|
||||
width: 648rpx;
|
||||
height: 94rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -467,8 +467,8 @@
|
|||
.isActive {
|
||||
background: rgba(252, 67, 124, 0.08);
|
||||
border-radius: 10rpx;
|
||||
border: 1rpx solid #FF4767;
|
||||
color: #FF4767;
|
||||
border: 1rpx solid #E8101E;
|
||||
color: #E8101E;
|
||||
/* 选中状态 */
|
||||
}
|
||||
|
||||
|
|
@ -493,7 +493,7 @@
|
|||
&__box {
|
||||
width: 648rpx;
|
||||
height: 94rpx;
|
||||
background: linear-gradient(140deg, #fa4e9a 0%, #FF4767 100%);
|
||||
background: linear-gradient(140deg, #fa4e9a 0%, #E8101E 100%);
|
||||
border-radius: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,30 @@
|
|||
<template>
|
||||
<view class="service-code-modal" v-if="show" :style="{ bottom: `${popBotom}px` }">
|
||||
<view class="service-code-modal" v-if="show" :style="{bottom:`${popBotom}px`}">
|
||||
<view class="modal-mask" @touchmove.stop.prevent></view>
|
||||
<view class="modal-content">
|
||||
<view class="modal-title">开始服务</view>
|
||||
<view class="modal-subtitle">请输入服务码</view>
|
||||
<view class="code-box">
|
||||
<view v-for="(item, idx) in codeLength" :key="idx"
|
||||
<view
|
||||
v-for="(item, idx) in codeLength"
|
||||
:key="idx"
|
||||
:class="['code-cell', idx === currentIndex ? 'active' : '', code[idx] ? 'filled' : '']">
|
||||
<text v-if="code[idx]">{{ code[idx] }}</text>
|
||||
</view>
|
||||
<!-- 隐藏真实输入框 -->
|
||||
<input :adjust-position="false" class="real-input" type="number" :maxlength="codeLength"
|
||||
v-model="inputValue" :focus="true" @input="onInput" @focus="onFocus"
|
||||
@keyboardheightchange="onkeyboardheightchange" @blur="onBlur" cursor-spacing="100"
|
||||
cursor-color="transparent" ref="realInput" />
|
||||
<input
|
||||
:adjust-position="false"
|
||||
class="real-input"
|
||||
type="number"
|
||||
:maxlength="codeLength"
|
||||
v-model="inputValue"
|
||||
:focus="true"
|
||||
@input="onInput"
|
||||
@focus="onFocus"
|
||||
@keyboardheightchange="onkeyboardheightchange"
|
||||
@blur="onBlur"
|
||||
cursor-spacing="100"
|
||||
ref="realInput" />
|
||||
</view>
|
||||
<button class="confirm-btn" :disabled="code.length < codeLength" @click="onConfirm">确定</button>
|
||||
<view class="close-btn" @click="close">×</view>
|
||||
|
|
@ -22,212 +33,210 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'serviceCodeInput',
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
codeLength: {
|
||||
type: Number,
|
||||
default: 6
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputValue: '',
|
||||
isFocus: true,
|
||||
keyboardHeight: 0,
|
||||
popBotom: 0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
code() {
|
||||
return this.inputValue.split('').slice(0, this.codeLength)
|
||||
},
|
||||
currentIndex() {
|
||||
return this.inputValue.length
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// show(val) {
|
||||
// if (val) {
|
||||
// this.$refs.realInput && this.$refs.realInput.focus
|
||||
// } else {
|
||||
// this.inputValue = ''
|
||||
// }
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
// uni.onKeyboardHeightChange((res)=>{
|
||||
// this.keyboardHeight = res.height;
|
||||
// })
|
||||
},
|
||||
methods: {
|
||||
onInput(e) {
|
||||
let val = e.detail.value.replace(/[^0-9]/g, '').slice(0, this.codeLength)
|
||||
this.inputValue = val
|
||||
this.$emit('input', val)
|
||||
if (val.length === this.codeLength) {
|
||||
this.$emit('finish', val)
|
||||
export default {
|
||||
name: 'serviceCodeInput',
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
codeLength: {
|
||||
type: Number,
|
||||
default: 6
|
||||
}
|
||||
},
|
||||
onFocus(e) {
|
||||
this.isFocus = true
|
||||
this.inputValue = ''
|
||||
},
|
||||
onkeyboardheightchange(e) {
|
||||
this.popBotom = e.target.height || 0
|
||||
},
|
||||
onBlur() {
|
||||
this.isFocus = false
|
||||
},
|
||||
onConfirm() {
|
||||
if (this.inputValue.length === this.codeLength) {
|
||||
this.$emit('confirm', this.inputValue);
|
||||
data() {
|
||||
return {
|
||||
inputValue: '',
|
||||
isFocus: true,
|
||||
keyboardHeight: 0,
|
||||
popBotom:0,
|
||||
}
|
||||
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
computed: {
|
||||
code() {
|
||||
return this.inputValue.split('').slice(0, this.codeLength)
|
||||
},
|
||||
currentIndex() {
|
||||
return this.inputValue.length
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// show(val) {
|
||||
// if (val) {
|
||||
// this.$refs.realInput && this.$refs.realInput.focus
|
||||
// } else {
|
||||
// this.inputValue = ''
|
||||
// }
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
// uni.onKeyboardHeightChange((res)=>{
|
||||
// this.keyboardHeight = res.height;
|
||||
// })
|
||||
},
|
||||
methods: {
|
||||
onInput(e) {
|
||||
let val = e.detail.value.replace(/[^0-9]/g, '').slice(0, this.codeLength)
|
||||
this.inputValue = val
|
||||
this.$emit('input', val)
|
||||
if (val.length === this.codeLength) {
|
||||
this.$emit('finish', val)
|
||||
}
|
||||
},
|
||||
onFocus(e) {
|
||||
this.isFocus = true
|
||||
this.inputValue = ''
|
||||
},
|
||||
onkeyboardheightchange(e){
|
||||
this.popBotom = e.target.height || 0
|
||||
},
|
||||
onBlur() {
|
||||
this.isFocus = false
|
||||
},
|
||||
onConfirm() {
|
||||
if (this.inputValue.length === this.codeLength) {
|
||||
this.$emit('confirm', this.inputValue);
|
||||
}
|
||||
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.service-code-modal {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999999;
|
||||
|
||||
.modal-mask {
|
||||
.service-code-modal {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: -1;
|
||||
}
|
||||
z-index: 999999;
|
||||
|
||||
.modal-content {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
border-radius: 32rpx 32rpx 0 0;
|
||||
padding: 56rpx 40rpx 40rpx 40rpx;
|
||||
box-shadow: 0 -8rpx 32rpx rgba(0, 0, 0, 0.08);
|
||||
min-height: 340rpx;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
animation: modalUp 0.25s;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-subtitle {
|
||||
font-size: 28rpx;
|
||||
color: #888;
|
||||
margin: 24rpx 0 40rpx 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.code-box {
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 48rpx;
|
||||
position: relative;
|
||||
|
||||
.code-cell {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border: 2rpx solid #eee;
|
||||
border-radius: 16rpx;
|
||||
margin-right: 24rpx;
|
||||
font-size: 40rpx;
|
||||
color: #ff4d8d;
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
line-height: 72rpx;
|
||||
box-sizing: border-box;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
&.active {
|
||||
border-color: #ff4d8d;
|
||||
}
|
||||
|
||||
&.filled {
|
||||
border-color: #ff4d8d;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.real-input {
|
||||
.modal-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
border-radius: 32rpx 32rpx 0 0;
|
||||
padding: 56rpx 40rpx 40rpx 40rpx;
|
||||
box-shadow: 0 -8rpx 32rpx rgba(0, 0, 0, 0.08);
|
||||
min-height: 340rpx;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
animation: modalUp 0.25s;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-subtitle {
|
||||
font-size: 28rpx;
|
||||
color: #888;
|
||||
margin: 24rpx 0 40rpx 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.code-box {
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 48rpx;
|
||||
position: relative;
|
||||
|
||||
.code-cell {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border: 2rpx solid #eee;
|
||||
border-radius: 16rpx;
|
||||
margin-right: 24rpx;
|
||||
font-size: 40rpx;
|
||||
color: #ff4d8d;
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
line-height: 72rpx;
|
||||
box-sizing: border-box;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
&.active {
|
||||
border-color: #ff4d8d;
|
||||
}
|
||||
|
||||
&.filled {
|
||||
border-color: #ff4d8d;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.real-input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
caret-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #ff4d8d;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-top: 16rpx;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
border: none;
|
||||
|
||||
&:disabled {
|
||||
background: #ffd1e3;
|
||||
height: 88rpx;
|
||||
background: #ff4d8d;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-top: 16rpx;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
border: none;
|
||||
|
||||
&:disabled {
|
||||
background: #ffd1e3;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 32rpx;
|
||||
top: 32rpx;
|
||||
font-size: 48rpx;
|
||||
color: #bbb;
|
||||
z-index: 10;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 32rpx;
|
||||
top: 32rpx;
|
||||
font-size: 48rpx;
|
||||
color: #bbb;
|
||||
z-index: 10;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
@keyframes modalUp {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
@keyframes modalUp {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -181,7 +181,7 @@
|
|||
position: absolute;
|
||||
top: 0rpx;
|
||||
left: 0rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
color: #FFFFFF;
|
||||
font-size: 24rpx;
|
||||
padding: 6rpx 14rpx;
|
||||
|
|
@ -247,7 +247,7 @@
|
|||
.price-symbol {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -256,7 +256,7 @@
|
|||
.price-value {
|
||||
font-weight: 500;
|
||||
font-size: 36rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -332,12 +332,12 @@
|
|||
|
||||
.price-symbol {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
font-size: 32rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@
|
|||
.price-text{
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -345,7 +345,7 @@
|
|||
.price-symbol {
|
||||
font-weight: 500;
|
||||
font-size: 20rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -354,7 +354,7 @@
|
|||
.price-value {
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
|
|||
|
|
@ -1,54 +1,63 @@
|
|||
<template>
|
||||
<view class="step-tab">
|
||||
<view class="step-container">
|
||||
<!-- 步骤1: 入驻协议 -->
|
||||
<view class="step-item" :class="getStepClass(0)">
|
||||
<view class="step-icon">
|
||||
<image
|
||||
v-if="mappedStep === 0"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/d62a1d01-52cb-418e-ba5b-afef513061b9.png"
|
||||
<image
|
||||
v-if="currentStep === 0"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/55a51333-318f-4ae4-8402-aca265bd499d"
|
||||
class="step-img active-circle"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view v-else-if="mappedStep > 0" class="step-done">1</view>
|
||||
<view v-else-if="currentStep > 0" class="step-done">1</view>
|
||||
<view v-else class="step-number">1</view>
|
||||
</view>
|
||||
<text class="step-text" :class="{ active: mappedStep === 0 }">入驻协议</text>
|
||||
<text class="step-text" :class="{ active: currentStep === 0 }">入驻协议</text>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 第一个连接线 -->
|
||||
<view class="line-segment line-1">
|
||||
<view class="line-progress" :class="{ active: line1Active, deactivating: line1Deactivating }"></view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 步骤2: 根据身份显示不同信息 -->
|
||||
<view class="step-item" :class="getStepClass(1)">
|
||||
<view class="step-icon">
|
||||
<image
|
||||
v-if="mappedStep === 1"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/d62a1d01-52cb-418e-ba5b-afef513061b9.png"
|
||||
<image
|
||||
v-if="currentStep === 1"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/55a51333-318f-4ae4-8402-aca265bd499d"
|
||||
class="step-img active-circle"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view v-else-if="mappedStep > 1" class="step-done">2</view>
|
||||
<view v-else-if="currentStep > 1" class="step-done">2</view>
|
||||
<view v-else class="step-number">2</view>
|
||||
</view>
|
||||
<text class="step-text" :class="{ active: mappedStep === 1 }">基本信息</text>
|
||||
<text class="step-text" :class="{ active: currentStep === 1 }">
|
||||
{{ identity === 1 ? '个人信息' : '资质信息' }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 第二个连接线 -->
|
||||
<view class="line-segment line-2">
|
||||
<view class="line-progress" :class="{ active: line2Active, deactivating: line2Deactivating }"></view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 步骤3: 根据身份显示不同信息 -->
|
||||
<view class="step-item" :class="getStepClass(2)">
|
||||
<view class="step-icon">
|
||||
<image
|
||||
v-if="mappedStep === 2"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/d62a1d01-52cb-418e-ba5b-afef513061b9.png"
|
||||
<image
|
||||
v-if="currentStep === 2"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/55a51333-318f-4ae4-8402-aca265bd499d"
|
||||
class="step-img active-circle"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view v-else-if="mappedStep > 2" class="step-done">3</view>
|
||||
<view v-else-if="currentStep > 2" class="step-done">3</view>
|
||||
<view v-else class="step-number">3</view>
|
||||
</view>
|
||||
<text class="step-text" :class="{ active: mappedStep === 2 }">资质认证</text>
|
||||
<text class="step-text" :class="{ active: currentStep === 2 }">
|
||||
{{ identity === 1 ? '资质信息' : '门店信息' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -58,23 +67,32 @@
|
|||
export default {
|
||||
name: "StepTab",
|
||||
props: {
|
||||
mappedStep: {
|
||||
// 当前步骤索引 (0, 1, 2)
|
||||
currentStep: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 身份类型:1-手艺人,2-商家
|
||||
identity: {
|
||||
type: Number,
|
||||
default: 2
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
prevStep: 0,
|
||||
line1Active: false,
|
||||
line2Active: false,
|
||||
line1Deactivating: false,
|
||||
line2Deactivating: false
|
||||
prevStep: 0, // 记录上一步骤
|
||||
line1Active: false, // 第一条线激活状态
|
||||
line2Active: false, // 第二条线激活状态
|
||||
line1Deactivating: false, // 第一条线正在取消激活
|
||||
line2Deactivating: false // 第二条线正在取消激活
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
mappedStep(newVal, oldVal) {
|
||||
// 监听currentStep变化,处理线条动画
|
||||
currentStep(newVal, oldVal) {
|
||||
this.prevStep = oldVal;
|
||||
|
||||
// 处理前进动画
|
||||
if (newVal > oldVal) {
|
||||
if (newVal >= 1) {
|
||||
this.line1Active = true;
|
||||
|
|
@ -84,34 +102,38 @@ export default {
|
|||
this.line2Active = true;
|
||||
this.line2Deactivating = false;
|
||||
}
|
||||
} else if (newVal < oldVal) {
|
||||
}
|
||||
// 处理返回动画
|
||||
else if (newVal < oldVal) {
|
||||
if (newVal < 2) {
|
||||
this.line2Deactivating = true;
|
||||
setTimeout(() => {
|
||||
this.line2Active = false;
|
||||
this.line2Deactivating = false;
|
||||
}, 300);
|
||||
}, 300); // 与动画持续时间匹配
|
||||
}
|
||||
if (newVal < 1) {
|
||||
this.line1Deactivating = true;
|
||||
setTimeout(() => {
|
||||
this.line1Active = false;
|
||||
this.line1Deactivating = false;
|
||||
}, 300);
|
||||
}, 300); // 与动画持续时间匹配
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.line1Active = this.mappedStep >= 1;
|
||||
this.line2Active = this.mappedStep >= 2;
|
||||
// 初始化线条状态
|
||||
this.line1Active = this.currentStep >= 1;
|
||||
this.line2Active = this.currentStep >= 2;
|
||||
},
|
||||
methods: {
|
||||
// 获取步骤的CSS类名
|
||||
getStepClass(stepIndex) {
|
||||
if (stepIndex === this.mappedStep) {
|
||||
if (stepIndex === this.currentStep) {
|
||||
return 'active';
|
||||
}
|
||||
else if (stepIndex < this.mappedStep) {
|
||||
else if (stepIndex < this.currentStep) {
|
||||
return 'completed';
|
||||
}
|
||||
return '';
|
||||
|
|
@ -184,7 +206,7 @@ export default {
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: inset 0 0 4rpx rgba(232, 16, 30, 0.2);
|
||||
|
|
@ -237,16 +259,35 @@ export default {
|
|||
transform-origin: left center;
|
||||
}
|
||||
|
||||
/* 激活状态的线条 - 前进动画 */
|
||||
.line-progress.active {
|
||||
width: 100%;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
/* 取消激活状态的线条 - 返回动画 */
|
||||
.line-progress.deactivating {
|
||||
width: 0%;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
transition: width 0.3s ease;
|
||||
transform-origin: right center;
|
||||
}
|
||||
</style>
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 750rpx) {
|
||||
.step-container {
|
||||
/* padding: 5rpx 40rpx; */
|
||||
}
|
||||
|
||||
.line-segment {
|
||||
/* width: 100rpx; */
|
||||
}
|
||||
|
||||
/* .line-1,
|
||||
.line-2 {
|
||||
margin-left: 15rpx;
|
||||
margin-right: 15rpx;
|
||||
} */
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,209 +1,123 @@
|
|||
<template>
|
||||
<uv-tabbar
|
||||
v-if="tabbarReady"
|
||||
:key="refreshKey"
|
||||
fixed
|
||||
:value="currentTabIndex"
|
||||
@change="onTabChange"
|
||||
activeColor="#FF4767"
|
||||
:placeholder="false"
|
||||
:safeAreaInsetBottom="false"
|
||||
:customStyle="{height:'110rpx'}"
|
||||
>
|
||||
<uv-tabbar-item
|
||||
v-for="(item, idx) in tabbarList"
|
||||
:key="idx"
|
||||
:name="idx"
|
||||
:text="item.text"
|
||||
:badge="getNum(idx)"
|
||||
:customStyle="{height:'110rpx'}"
|
||||
@click="onItemClick(idx)"
|
||||
>
|
||||
<template v-slot:active-icon>
|
||||
<image class="icon" :src="item.selectedIconPath"></image>
|
||||
</template>
|
||||
<template v-slot:inactive-icon>
|
||||
<image class="icon" :src="item.iconPath"></image>
|
||||
</template>
|
||||
</uv-tabbar-item>
|
||||
</uv-tabbar>
|
||||
<uv-tabbar fixed :value="selected" @change="change1" activeColor="#ee0a24" :placeholder="false"
|
||||
:safeAreaInsetBottom="false" :customStyle="{height:`110rpx`}">
|
||||
<uv-tabbar-item v-for="(item,index) in $store.state.tabbarList" :key="index" :badge="getNum(index)"
|
||||
:customStyle="{height:`110rpx`}">
|
||||
<template v-slot:active-icon>
|
||||
<image class="icon" :src="item.selectedIconPath"></image>
|
||||
</template>
|
||||
<template v-slot:inactive-icon>
|
||||
<image class="icon" :src="item.iconPath"></image>
|
||||
</template>
|
||||
</uv-tabbar-item>
|
||||
</uv-tabbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
import request from "@/utils/request";
|
||||
import request from "@/utils/request";
|
||||
export default {
|
||||
name: "tab-bar",
|
||||
props: {
|
||||
selected: {
|
||||
type: [Number, String]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabbarList: [{
|
||||
"iconPath": "/static/images/tabbar/new_home_gray.png",
|
||||
"text": "首页",
|
||||
"selectedIconPath": "/static/images/tabbar/new_home.png",
|
||||
"pagePath": "/pages/home/home"
|
||||
},
|
||||
{
|
||||
"iconPath": "/static/images/tabbar/new_message_gray.png",
|
||||
"text": "消息",
|
||||
"selectedIconPath": "/static/images/tabbar/new_message.png",
|
||||
"pagePath": "/pages/message/message"
|
||||
},
|
||||
{
|
||||
"iconPath": "/static/images/tabbar/new_my_gray.png",
|
||||
"text": "我的",
|
||||
"selectedIconPath": "/static/images/tabbar/new_my.png",
|
||||
"pagePath": "/pages/my/my"
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
messageNum() {
|
||||
return this.$store.state.messageNum || 0
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
if (!this.$store.state.tabbarList.length) {
|
||||
let isnNetwork = uni.getStorageSync("isnNetwork");
|
||||
if (isnNetwork) {
|
||||
await this.getButtonImg()
|
||||
} else {
|
||||
uni.getNetworkType({
|
||||
success: (res) => {
|
||||
console.log(res.networkType);
|
||||
if (res.networkType == "none") {
|
||||
|
||||
export default {
|
||||
name: "tab-bar",
|
||||
// 不再需要 props.selected,完全由 Vuex 控制高亮
|
||||
data() {
|
||||
return {
|
||||
refreshKey: 0, // 强制重建标识
|
||||
tabbarReady: false, // 组件就绪标识
|
||||
tabbarList: [ // tab 配置
|
||||
{
|
||||
iconPath: "/static/images/tabbar/new_home_gray.png",
|
||||
text: "首页",
|
||||
selectedIconPath: "/static/images/tabbar/new_home.png",
|
||||
pagePath: "/pages/home/home"
|
||||
},
|
||||
{
|
||||
iconPath: "/static/images/tabbar/new_order_gray.png",
|
||||
text: "订单",
|
||||
selectedIconPath: "/static/images/tabbar/new_order.png",
|
||||
pagePath: "/pages/order/userorder-list"
|
||||
},
|
||||
{
|
||||
iconPath: "/static/images/tabbar/new_message_gray.png",
|
||||
text: "消息",
|
||||
selectedIconPath: "/static/images/tabbar/new_message.png",
|
||||
pagePath: "/pages/message/message"
|
||||
},
|
||||
{
|
||||
iconPath: "/static/images/tabbar/new_my_gray.png",
|
||||
text: "我的",
|
||||
selectedIconPath: "/static/images/tabbar/new_my.png",
|
||||
pagePath: "/pages/my/my"
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 保留对消息数量的映射
|
||||
...mapState(['messageNum']),
|
||||
|
||||
// ========= 动态计算当前高亮索引 =========
|
||||
// 替代原先直接获取 Vuex 的方式,改为根据当前真实路由计算,解决刷新状态丢失问题
|
||||
currentTabIndex() {
|
||||
try {
|
||||
// 获取当前页面栈
|
||||
const pages = getCurrentPages();
|
||||
if (pages && pages.length > 0) {
|
||||
// 获取当前页面实例
|
||||
const currentPage = pages[pages.length - 1];
|
||||
// 拼接当前页面路径(兼容不同平台获取路由的方式)
|
||||
const currentPath = '/' + (currentPage.route || currentPage.__route__);
|
||||
|
||||
// 在 tabbarList 中查找匹配当前路径的索引
|
||||
const index = this.tabbarList.findIndex(item => item.pagePath === currentPath);
|
||||
if (index !== -1) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
// 如果由于某些原因匹配不到,降级去取 Vuex 中的值(防止其他极端情况报错)
|
||||
return this.$store.state.currentTabIndex || 0;
|
||||
} catch (e) {
|
||||
return this.$store.state.currentTabIndex || 0;
|
||||
}
|
||||
}
|
||||
// =================================================
|
||||
},
|
||||
watch: {
|
||||
// 当 tabbarList 内容变化(如异步更新图标)时,强制重建组件
|
||||
tabbarList: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.rebuildTabbar();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 初始化时延迟显示,避免闪烁
|
||||
this.tabbarReady = false;
|
||||
this.$nextTick(() => {
|
||||
this.tabbarReady = true;
|
||||
// 如果需要异步加载图标,取消下面注释
|
||||
// this.getButtonImg();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_CURRENT_TAB_INDEX']),
|
||||
this.$store.commit("setTabbarList", this.tabbarList)
|
||||
} else {
|
||||
// 页面加载逻辑
|
||||
uni.setStorageSync("isnNetwork", 1);
|
||||
this.getButtonImg()
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 设置全局选中索引(简化调用)
|
||||
setCurrentTabIndex(index) {
|
||||
this.SET_CURRENT_TAB_INDEX(index);
|
||||
},
|
||||
}
|
||||
|
||||
// 强制重建 uv-tabbar(用于异步更新图标后)
|
||||
rebuildTabbar() {
|
||||
this.tabbarReady = false;
|
||||
this.$nextTick(() => {
|
||||
this.refreshKey++;
|
||||
this.tabbarReady = true;
|
||||
});
|
||||
},
|
||||
|
||||
// 获取角标数字(只有消息 tab 且数量 > 0 才显示)
|
||||
getNum(index) {
|
||||
if (index === 2 && this.messageNum > 0) {
|
||||
return this.messageNum;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// 异步更新图标(保留你的业务逻辑)
|
||||
async getButtonImg() {
|
||||
try {
|
||||
let res = await request.post("/sj/poster/getButtonImg", {});
|
||||
if (res.code === 200) {
|
||||
this.tabbarList.forEach((item, index) => {
|
||||
if (res.data[index]?.iconPath) {
|
||||
item.iconPath = res.data[index].iconPath;
|
||||
}
|
||||
if (res.data[index]?.selectedIconPath) {
|
||||
item.selectedIconPath = res.data[index].selectedIconPath;
|
||||
}
|
||||
});
|
||||
this.$store.commit("setTabbarList", this.tabbarList);
|
||||
// 图标更新后,强制重建组件
|
||||
this.rebuildTabbar();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('getButtonImg 请求失败', err);
|
||||
}
|
||||
},
|
||||
|
||||
// uv-tabbar 的 change 事件(组件内部触发)
|
||||
onTabChange(val) {
|
||||
const idx = parseInt(val, 10);
|
||||
this.doJump(idx);
|
||||
},
|
||||
|
||||
// 手动点击 item 时触发
|
||||
onItemClick(idx) {
|
||||
this.doJump(idx);
|
||||
},
|
||||
|
||||
// 实际跳转逻辑 + 更新全局高亮
|
||||
doJump(index) {
|
||||
const idx = parseInt(index, 10);
|
||||
if (isNaN(idx) || !this.tabbarList[idx]) return;
|
||||
|
||||
// 依然更新全局高亮,确保其他可能依赖 Vuex 状态的逻辑正常运行
|
||||
this.setCurrentTabIndex(idx);
|
||||
|
||||
// 跳转页面
|
||||
const targetPage = this.tabbarList[idx].pagePath;
|
||||
uni.switchTab({
|
||||
url: targetPage,
|
||||
fail: (err) => console.error('switchTab 失败', err)
|
||||
});
|
||||
|
||||
// 保留你原有的消息更新方法
|
||||
if (typeof this.messageUpudateNum === 'function') {
|
||||
this.messageUpudateNum();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getNum(index) {
|
||||
if (index == 1) {
|
||||
return this.messageNum
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
},
|
||||
//获取头部背景图片
|
||||
async getButtonImg() {
|
||||
let res = await request.post("/sj/poster/getButtonImg", {});
|
||||
if (res.code == 200) {
|
||||
// if (res.data?.photo) {
|
||||
// this.topBgImage = res.data?.photo + '?time=666'
|
||||
// }
|
||||
this.tabbarList.forEach((item, index) => {
|
||||
if (res.data[index].iconPath) {
|
||||
item.iconPath = res.data[index].iconPath
|
||||
}
|
||||
if (res.data[index].selectedIconPath) {
|
||||
item.selectedIconPath = res.data[index].selectedIconPath
|
||||
}
|
||||
})
|
||||
}
|
||||
this.$store.commit("setTabbarList", this.tabbarList)
|
||||
},
|
||||
change1(val) {
|
||||
// 因为在pages中配置了需要跳转的页面为 tabbar页面
|
||||
// 所以不能使用navigateTo 只能使用下面这个方法跳转。
|
||||
uni.switchTab({
|
||||
url: this.tabbarList[val].pagePath
|
||||
})
|
||||
this.messageUpudateNum()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.icon {
|
||||
height: 54rpx;
|
||||
width: 54rpx;
|
||||
}
|
||||
::v-deep .uv-tabbar__content {
|
||||
z-index: 999 !important;
|
||||
}
|
||||
.icon {
|
||||
height: 98rpx;
|
||||
width: 98rpx;
|
||||
}
|
||||
::v-deep .uv-tabbar__content{
|
||||
z-index: 999!important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -383,7 +383,7 @@
|
|||
justify-content: center;
|
||||
width: 690rpx;
|
||||
height: 80rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 38rpx;
|
||||
font-weight: 400;
|
||||
font-size: 30rpx;
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ export default {
|
|||
justify-content: center;
|
||||
width: 690rpx;
|
||||
height: 80rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 38rpx;
|
||||
font-weight: 400;
|
||||
font-size: 30rpx;
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ export default {
|
|||
&__text {
|
||||
font-weight: 400;
|
||||
font-size: 18rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 25rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -371,7 +371,7 @@ export default {
|
|||
&__immediately {
|
||||
width: 236rpx;
|
||||
height: 78rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 39rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -405,7 +405,7 @@ export default {
|
|||
|
||||
&__active {
|
||||
height: 28rpx;
|
||||
background: linear-gradient(270deg, #fe78b3 0%, #FF4767 100%);
|
||||
background: linear-gradient(270deg, #fe78b3 0%, #E8101E 100%);
|
||||
border-radius: 39rpx;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.18.0.min.js"></script>
|
||||
<script>
|
||||
import request from '../../utils/request';
|
||||
export default {
|
||||
|
|
@ -234,4 +235,4 @@ import request from '../../utils/request';
|
|||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -200,13 +200,12 @@ import sparkMD5 from 'spark-md5'; // 引入MD5计算库
|
|||
const loadNext = () => {
|
||||
const start = currentChunk * chunkSize;
|
||||
const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
|
||||
let reader;
|
||||
// #ifdef H5
|
||||
reader = new FileReader();
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
reader = uni.getfilesystem;
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
const reader = new FileReader();
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
const reader = uni.getfilesystem;
|
||||
// #endif
|
||||
reader.onload = (e) => {
|
||||
spark.append(e.target.result);
|
||||
currentChunk++;
|
||||
|
|
@ -227,13 +226,12 @@ import sparkMD5 from 'spark-md5'; // 引入MD5计算库
|
|||
try {
|
||||
// 获取ArrayBuffer
|
||||
const arrayBuffer = await new Promise((resolve) => {
|
||||
let reader;
|
||||
// #ifdef H5
|
||||
reader = new FileReader();
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
reader = uni.getfilesystem;
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
const reader = new FileReader();
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
const reader = uni.getfilesystem;
|
||||
// #endif
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.readAsArrayBuffer(chunk);
|
||||
});
|
||||
|
|
@ -420,4 +418,4 @@ import sparkMD5 from 'spark-md5'; // 引入MD5计算库
|
|||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -2,21 +2,14 @@
|
|||
"name" : "美融融商家",
|
||||
"appid" : "__UNI__BBE6285",
|
||||
"description" : "同城便捷到家美业“技术外卖”服务、同城预约到店服务平台美融融为同城爱美人群提供更优质的更全面的服务。",
|
||||
"versionName" : "1.0.22",
|
||||
"versionCode" : 1022,
|
||||
"versionName" : "1.0.09",
|
||||
"versionCode" : 1009,
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"screenOrientation" : [
|
||||
//可选,字符串数组类型,应用支持的横竖屏
|
||||
"portrait-primary", //可选,字符串类型,支持竖屏
|
||||
"portrait-secondary", //可选,字符串类型,支持反向竖屏
|
||||
"landscape-primary", //可选,字符串类型,支持横屏
|
||||
"landscape-secondary" //可选,字符串类型,支持反向横屏
|
||||
],
|
||||
"compatible" : {
|
||||
"ignoreVersion" : true //true表示忽略版本检查提示框,HBuilderX1.9.0及以上版本支持
|
||||
},
|
||||
|
|
@ -41,8 +34,7 @@
|
|||
"Payment" : {},
|
||||
"VideoPlayer" : {},
|
||||
"OAuth" : {},
|
||||
"Camera" : {},
|
||||
"Barcode" : {}
|
||||
"Camera" : {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
|
|
@ -77,7 +69,6 @@
|
|||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {
|
||||
"UIRequiresFullScreen" : false, // 允许非全屏模式
|
||||
"urlschemewhitelist" : [ "iosmap" ],
|
||||
"dSYMs" : false,
|
||||
"plistcmds" : [
|
||||
|
|
|
|||
122
pages.json
122
pages.json
|
|
@ -31,20 +31,6 @@
|
|||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/home/growth-package",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/home/growth-package-result",
|
||||
"style": {
|
||||
"navigationBarTitleText": "支付结果",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/message/message",
|
||||
"style": {
|
||||
|
|
@ -103,12 +89,8 @@
|
|||
"path": "pages/order/userorder-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单",
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"app-plus": {
|
||||
"softinputNavBar": "none"
|
||||
}
|
||||
"navigationBarBackgroundColor": "#FFFFFF"
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"path": "pages/order/userorder-detail",
|
||||
|
|
@ -168,13 +150,7 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/notice/notice_list",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/notice/detail",
|
||||
"path": "pages/add/add",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
|
|
@ -245,12 +221,6 @@
|
|||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/search_common/search",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/settings/index",
|
||||
"style": {
|
||||
|
|
@ -614,30 +584,6 @@
|
|||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/shop/verify/verify-order",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/shop/verify/manual-verify",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/shop/verify/verify-fail",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/shop/verify/verify-order-detail",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/shop/photoAlbum/photoManage",
|
||||
"style": {
|
||||
|
|
@ -650,14 +596,6 @@
|
|||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/shop/photoAlbum/videoplayer",
|
||||
"style": {
|
||||
"navigationBarTitleText": "全屏视频播放",
|
||||
"pageOrientation": "auto",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/shop/photoAlbum/videoList",
|
||||
"style": {
|
||||
|
|
@ -1005,43 +943,6 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "拍摄技巧"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/myFavorite",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的收藏",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/jingxuan/selected-skills",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/jingxuan/selected-brands",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/jingxuan/brand-detail",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/jingxuan/skill-detail",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/ruzhu/successruzhu",
|
||||
"style": {
|
||||
"navigationBarTitleText": "入驻成功"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1054,7 +955,7 @@
|
|||
},
|
||||
"tabBar": {
|
||||
"color": "#999",
|
||||
"selectedColor": "#FF4767",
|
||||
"selectedColor": "#E8101E",
|
||||
"backgroundColor": "#fff",
|
||||
"list": [{
|
||||
"iconPath": "/static/images/tabbar/home_icon_dis.png",
|
||||
|
|
@ -1062,17 +963,10 @@
|
|||
"selectedIconPath": "/static/images/tabbar/home_icon_active.png",
|
||||
"pagePath": "pages/home/home"
|
||||
},
|
||||
{
|
||||
"iconPath": "/static/images/tabbar/new_order_gray.png",
|
||||
"text": "订单",
|
||||
"selectedIconPath": "/static/images/tabbar/new_order.png",
|
||||
"pagePath": "pages/order/userorder-list"
|
||||
},
|
||||
{
|
||||
"iconPath": "/static/images/tabbar/new_message_gray.png",
|
||||
"text": "消息",
|
||||
"selectedIconPath": "/static/images/tabbar/new_message.png",
|
||||
"pagePath": "pages/message/message"
|
||||
{ "iconPath": "/static/images/tabbar/new_message_gray.png",
|
||||
"text": "消息",
|
||||
"selectedIconPath": "/static/images/tabbar/new_message.png",
|
||||
"pagePath": "pages/message/message"
|
||||
},
|
||||
{
|
||||
"iconPath": "/static/images/tabbar/my_icon_dis.png",
|
||||
|
|
@ -1083,4 +977,4 @@
|
|||
]
|
||||
},
|
||||
"uniIdRouter": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
<!-- 设为默认地址 -->
|
||||
<view class="form-item switch-item">
|
||||
<text class="label">设为默认地址</text>
|
||||
<switch :checked="addressInfo.is_default == 1" @change="onSwitchChange" color="#FF4767" />
|
||||
<switch :checked="addressInfo.is_default == 1" @change="onSwitchChange" color="#E8101E" />
|
||||
</view>
|
||||
<!-- 顶部图标 -->
|
||||
<view class="biao"></view>
|
||||
|
|
@ -622,7 +622,7 @@
|
|||
.save-btn {
|
||||
width: 630rpx;
|
||||
height: 96rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-radius: 44rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@
|
|||
|
||||
/* .tag {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
background-color: rgba(252, 67, 124, 0.08);
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 6rpx;
|
||||
|
|
@ -370,7 +370,7 @@
|
|||
width: 690rpx;
|
||||
height: 78rpx;
|
||||
border-radius: 39rpx;
|
||||
border: 1rpx solid #FF4767;
|
||||
border: 1rpx solid #E8101E;
|
||||
text-align: center;
|
||||
line-height: 64rpx;
|
||||
display: flex;
|
||||
|
|
@ -383,7 +383,7 @@
|
|||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 30rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 42rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<!-- <view class="search-container">
|
||||
<text class="search-container-text" @click="goSelectCity">{{ city.name }}</text>
|
||||
<search-box v-model="searchKeyword" placeholder="请输入地址" width="571rpx" height="68rpx"
|
||||
border="1px solid #FF4767" style="padding: 0;" @confirm="onSearch" :showBack="false"></search-box>
|
||||
border="1px solid #E8101E" style="padding: 0;" @confirm="onSearch" :showBack="false"></search-box>
|
||||
</view> -->
|
||||
<view class="search-container">
|
||||
<text class="search-container-text" @click="goSelectCity">
|
||||
|
|
@ -858,7 +858,7 @@
|
|||
flex: 1;
|
||||
height: 68rpx;
|
||||
background: #FFFFFF;
|
||||
border: 2rpx solid #FF4767;
|
||||
border: 2rpx solid #E8101E;
|
||||
border-radius: 60rpx;
|
||||
position: relative;
|
||||
|
||||
|
|
@ -936,7 +936,7 @@
|
|||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 34rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
|
|
@ -1124,7 +1124,7 @@
|
|||
width: 48rpx;
|
||||
height: 26rpx;
|
||||
border-radius: 6rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
margin-right: 10rpx;
|
||||
|
||||
&__text {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
<!-- 设为默认地址 -->
|
||||
<view class="form-item switch-item">
|
||||
<text class="label">设为默认地址</text>
|
||||
<switch :checked="addressInfo.is_default == 1" @change="onSwitchChange" color="#FF4767" />
|
||||
<switch :checked="addressInfo.is_default == 1" @change="onSwitchChange" color="#E8101E" />
|
||||
</view>
|
||||
<!-- 顶部图标 -->
|
||||
<view class="biao"></view>
|
||||
|
|
@ -614,7 +614,7 @@
|
|||
.save-btn {
|
||||
width: 630rpx;
|
||||
height: 96rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-radius: 44rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
|
|||
|
|
@ -666,7 +666,7 @@
|
|||
flex: 1;
|
||||
height: 68rpx;
|
||||
background: #FFFFFF;
|
||||
border: 2rpx solid #FF4767;
|
||||
border: 2rpx solid #E8101E;
|
||||
border-radius: 60rpx;
|
||||
position: relative;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -274,7 +274,7 @@
|
|||
flex: 1;
|
||||
height: 68rpx;
|
||||
background: #FFFFFF;
|
||||
border: 2rpx solid #FF4767;
|
||||
border: 2rpx solid #E8101E;
|
||||
background-color: #fafafa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
></custom-navbar>
|
||||
<!-- <view class="search-container">
|
||||
<search-box v-model="searchKeyword" placeholder="请输入你的服务地址" width="690rpx" height="68rpx"
|
||||
border="1px solid #FF4767" style="padding: 0;" @confirm="onSearch" :showBack="false"></search-box>
|
||||
border="1px solid #E8101E" style="padding: 0;" @confirm="onSearch" :showBack="false"></search-box>
|
||||
</view>
|
||||
<scroll-view scroll-y class="hao-scroll">
|
||||
<view class="hot-citys">
|
||||
|
|
|
|||
|
|
@ -1,88 +1,822 @@
|
|||
<template>
|
||||
<view class="video-page">
|
||||
<!-- 原生视频组件:全端兼容 -->
|
||||
<video id="fullVideo" class="video-box" :src="videoUrl" controls show-fullscreen-btn enable-progress-gesture
|
||||
:autoplay="false" :loop="false" :muted="false" @play="onPlay" @pause="onPause"
|
||||
@fullscreenchange="handleFullScreenChange" @ended="onVideoEnd"></video>
|
||||
<view style="z-index: 100;">
|
||||
<!-- 视频滑动主容器 -->
|
||||
<view class="view-box" :style="viewTopLength">
|
||||
<!-- 复用的5个视频容器 - 核心复用节点,不可删减 -->
|
||||
<view class="video-box" :style="itemViewTopLength0">
|
||||
<video :src="videoInfo_0.src" :style="fillScreen" :autoplay="videoInfo_0.autoplay"
|
||||
:loop="videoInfo_0.loop" :controls="videoInfo_0.controls"
|
||||
:enable-play-gesture="videoInfo_0.enablePlayGesture" :objectFit="videoInfo_0.objectFit || objectFit"
|
||||
:show-fullscreen-btn="videoInfo_0.showFullscreenBtn"
|
||||
:enable-progress-gesture="videoInfo_0.enableProgressGesture" @timeupdate="timeupdate(0,$event)"
|
||||
@ended='ended' :show-play-btn="videoInfo_0.showPlayBtn" :show-progress="videoInfo_0.showProgress"
|
||||
initial-time="0" id='video_id_0' @play="playing(0)" :muted="videoInfo_0.isMuted"
|
||||
webkit-playsinline="true" playsinline="true">
|
||||
</video>
|
||||
<cover-view v-if="!videoInfo_0.flag" :style="stopIcon" class="cover-view-stop" />
|
||||
<cover-view v-if="cover && videoInfo_0.coverStatus" :style="fillScreen2" class="video-image">
|
||||
<image :mode="videoInfo_0.mode || mode" :src="videoInfo_0.coverUrl" :style="fillScreen"></image>
|
||||
</cover-view>
|
||||
<view class="video-action" @touchstart.stop='videotouchstart' @touchmove.stop="videotochmove"
|
||||
@touchend.stop='videotouchend' @click.stop="videoClick"></view>
|
||||
<!-- 视频文本区域 - 每个视频都有 -->
|
||||
<view class="video-texts">
|
||||
<view class="flex-row-center" style="flex: 1;">
|
||||
<text class="video-title">{{ videoInfo_0.src }}</text>
|
||||
<text class="video-score">评分 4.8</text>
|
||||
</view>
|
||||
<view class="flex-row-center-between" style="flex: 1;">
|
||||
<text class="video-text">{{videoInfo_0.name}}</text>
|
||||
<!-- 声音图标 - 绑定0号视频的状态,点击切换静音 -->
|
||||
<image class="video-sound"
|
||||
:src="videoInfo_0.isMuted ? '/static/images/icons/sound_no.png' : '/static/images/icons/sound_yes.png'"
|
||||
@click.stop="toggleMute(0)"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="video-box" :style="itemViewTopLength1">
|
||||
<video :src="videoInfo_1.src" :style="fillScreen" :autoplay="videoInfo_1.autoplay"
|
||||
:loop="videoInfo_1.loop" :controls="videoInfo_1.controls"
|
||||
:enable-play-gesture="videoInfo_1.enablePlayGesture" :objectFit="videoInfo_1.objectFit || objectFit"
|
||||
:show-fullscreen-btn="videoInfo_1.showFullscreenBtn"
|
||||
:enable-progress-gesture="videoInfo_1.enableProgressGesture" @timeupdate="timeupdate(1,$event)"
|
||||
@ended='ended' :show-play-btn="videoInfo_1.showPlayBtn" :show-progress="videoInfo_1.showProgress"
|
||||
initial-time="0" id='video_id_1' @play="playing(1)" :muted="videoInfo_1.isMuted"
|
||||
webkit-playsinline="true" playsinline="true">
|
||||
</video>
|
||||
<cover-view v-if="!videoInfo_1.flag" :style="stopIcon" class="cover-view-stop" />
|
||||
<cover-view v-if="cover && videoInfo_1.coverStatus" :style="fillScreen2" class="video-image">
|
||||
<image :mode="videoInfo_1.mode || mode" :src="videoInfo_1.coverUrl" :style="fillScreen"></image>
|
||||
</cover-view>
|
||||
<view class="video-action" @touchstart='videotouchstart' @touchmove="videotochmove"
|
||||
@touchend='videotouchend' @click="videoClick"></view>
|
||||
<!-- 视频文本区域 - 1号视频 -->
|
||||
<view class="video-texts">
|
||||
<view class="flex-row-center" style="flex: 1;">
|
||||
<text class="video-title">珍草品汇理疗馆珍馆服务流程11订单</text>
|
||||
<text class="video-score">评分 4.8</text>
|
||||
</view>
|
||||
<view class="flex-row-center-between" style="flex: 1;">
|
||||
<text class="video-text">{{videoInfo_1.name}}</text>
|
||||
<!-- 声音图标 - 绑定1号视频的状态 -->
|
||||
<image class="video-sound"
|
||||
:src="videoInfo_1.isMuted ? '/static/images/icons/sound_no.png' : '/static/images/icons/sound_yes.png'"
|
||||
@click.stop="toggleMute(1)"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="video-box" :style="itemViewTopLength2">
|
||||
<video :src="videoInfo_2.src" :style="fillScreen" :autoplay="videoInfo_2.autoplay"
|
||||
:loop="videoInfo_2.loop" :controls="videoInfo_2.controls"
|
||||
:enable-play-gesture="videoInfo_2.enablePlayGesture" :objectFit="videoInfo_2.objectFit || objectFit"
|
||||
:show-fullscreen-btn="videoInfo_2.showFullscreenBtn"
|
||||
:enable-progress-gesture="videoInfo_2.enableProgressGesture" @timeupdate="timeupdate(2,$event)"
|
||||
@ended='ended' :show-play-btn="videoInfo_2.showPlayBtn" :show-progress="videoInfo_2.showProgress"
|
||||
initial-time="0" id='video_id_2' @play="playing(2)" :muted="videoInfo_2.isMuted"
|
||||
webkit-playsinline="true" playsinline="true">
|
||||
</video>
|
||||
<cover-view v-if="!videoInfo_2.flag" :style="stopIcon" class="cover-view-stop" />
|
||||
<cover-view v-if="cover && videoInfo_2.coverStatus" :style="fillScreen2" class="video-image">
|
||||
<image :mode="videoInfo_2.mode || mode" :src="videoInfo_2.coverUrl" :style="fillScreen"></image>
|
||||
</cover-view>
|
||||
<view class="video-action" @touchstart='videotouchstart' @touchmove="videotochmove"
|
||||
@touchend='videotouchend' @click="videoClick"></view>
|
||||
<!-- 视频文本区域 - 2号视频 -->
|
||||
<view class="video-texts">
|
||||
<view class="flex-row-center" style="flex: 1;">
|
||||
<text class="video-title">珍草品汇理疗馆珍馆服务流程11订单</text>
|
||||
<text class="video-score">评分 4.8</text>
|
||||
</view>
|
||||
<view class="flex-row-center-between" style="flex: 1;">
|
||||
<text class="video-text">{{videoInfo_2.name}}</text>
|
||||
<!-- 声音图标 - 绑定2号视频的状态 -->
|
||||
<image class="video-sound"
|
||||
:src="videoInfo_2.isMuted ? '/static/images/icons/sound_no.png' : '/static/images/icons/sound_yes.png'"
|
||||
@click.stop="toggleMute(2)"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="video-box" :style="itemViewTopLength3">
|
||||
<video :src="videoInfo_3.src" :style="fillScreen" :autoplay="videoInfo_3.autoplay"
|
||||
:loop="videoInfo_3.loop" :controls="videoInfo_3.controls"
|
||||
:enable-play-gesture="videoInfo_3.enablePlayGesture" :objectFit="videoInfo_3.objectFit || objectFit"
|
||||
:show-fullscreen-btn="videoInfo_3.showFullscreenBtn"
|
||||
:enable-progress-gesture="videoInfo_3.enableProgressGesture" @timeupdate="timeupdate(3,$event)"
|
||||
@ended='ended' :show-play-btn="videoInfo_3.showPlayBtn" :show-progress="videoInfo_3.showProgress"
|
||||
initial-time="0" id='video_id_3' @play="playing(3)" :muted="videoInfo_3.isMuted"
|
||||
webkit-playsinline="true" playsinline="true">
|
||||
</video>
|
||||
<cover-view v-if="!videoInfo_3.flag" :style="stopIcon" class="cover-view-stop" />
|
||||
<cover-view v-if="cover && videoInfo_3.coverStatus" :style="fillScreen2" class="video-image">
|
||||
<image :mode="videoInfo_3.mode || mode" :src="videoInfo_3.coverUrl" :style="fillScreen"></image>
|
||||
</cover-view>
|
||||
<view class="video-action" @touchstart='videotouchstart' @touchmove="videotochmove"
|
||||
@touchend='videotouchend' @click="videoClick"></view>
|
||||
<!-- 视频文本区域 - 3号视频 -->
|
||||
<view class="video-texts">
|
||||
<view class="flex-row-center" style="flex: 1;">
|
||||
<text class="video-title">珍草品汇理疗馆珍馆服务流程11订单</text>
|
||||
<text class="video-score">评分 4.8</text>
|
||||
</view>
|
||||
<view class="flex-row-center-between" style="flex: 1;">
|
||||
<text class="video-text">{{videoInfo_3.name}}</text>
|
||||
<!-- 声音图标 - 绑定3号视频的状态 -->
|
||||
<image class="video-sound"
|
||||
:src="videoInfo_3.isMuted ? '/static/images/icons/sound_no.png' : '/static/images/icons/sound_yes.png'"
|
||||
@click.stop="toggleMute(3)"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="video-box" :style="itemViewTopLength4">
|
||||
<video :src="videoInfo_4.src" :style="fillScreen" :autoplay="videoInfo_4.autoplay"
|
||||
:loop="videoInfo_4.loop" :controls="videoInfo_4.controls"
|
||||
:enable-play-gesture="videoInfo_4.enablePlayGesture" :objectFit="videoInfo_4.objectFit || objectFit"
|
||||
:show-fullscreen-btn="videoInfo_4.showFullscreenBtn"
|
||||
:enable-progress-gesture="videoInfo_4.enableProgressGesture" @timeupdate="timeupdate(4,$event)"
|
||||
@ended='ended' :show-play-btn="videoInfo_4.showPlayBtn" :show-progress="videoInfo_4.showProgress"
|
||||
initial-time="0" id='video_id_4' @play="playing(4)" :muted="videoInfo_4.isMuted"
|
||||
webkit-playsinline="true" playsinline="true">
|
||||
</video>
|
||||
<cover-view v-if="!videoInfo_4.flag" :style="stopIcon" class="cover-view-stop" />
|
||||
<cover-view v-if="cover && videoInfo_4.coverStatus" :style="fillScreen2" class="video-image">
|
||||
<image :mode="videoInfo_4.mode || mode" :src="videoInfo_4.coverUrl" :style="fillScreen"></image>
|
||||
</cover-view>
|
||||
<view class="video-action" @touchstart='videotouchstart' @touchmove="videotochmove"
|
||||
@touchend='videotouchend' @click="videoClick"></view>
|
||||
<!-- 视频文本区域 - 4号视频 -->
|
||||
<view class="video-texts">
|
||||
<view class="flex-row-center" style="flex: 1;">
|
||||
<text class="video-title">珍草品汇理疗馆珍馆服务流程11订单</text>
|
||||
<text class="video-score">评分 4.8</text>
|
||||
</view>
|
||||
<view class="flex-row-center-between" style="flex: 1;">
|
||||
<text class="video-text">{{videoInfo_4.name}}</text>
|
||||
<!-- 声音图标 - 绑定4号视频的状态 -->
|
||||
<image class="video-sound"
|
||||
:src="videoInfo_4.isMuted ? '/static/images/icons/sound_no.png' : '/static/images/icons/sound_yes.png'"
|
||||
@click.stop="toggleMute(4)"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view @touchend='progressTouchend' class="progress-view">
|
||||
<uv-slider v-if="showSlider" v-model="progressValue" activeColor="#D8D8D8" block-size="6"
|
||||
backgroundColor="#494949;" class="progress-slider"></uv-slider>
|
||||
</view>
|
||||
|
||||
<!-- 修改:Dot指示器 - 最多显示5个 -->
|
||||
<view class="dots" :style="{top:`${0.5*winHeight}px`}" v-if="videoListLength > 1">
|
||||
<view class="dots-container">
|
||||
<view class="dot-item" v-for="(dotIndex, idx) in visibleDots" :key="idx"
|
||||
:class="{ active: dotIndex === videoIndex }" @click="jumpToVideo(dotIndex)"></view>
|
||||
</view>
|
||||
<text class="pageNumber">
|
||||
{{ videoIndex+1 }}/{{ videoListLength }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 自定义操作按钮 -->
|
||||
<view class="btn-wrap">
|
||||
<button type="primary" size="default" @click="openFullScreen">
|
||||
手动横屏全屏播放
|
||||
</button>
|
||||
<button type="warn" size="default" @click="closeFullScreen">
|
||||
退出全屏
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let VIDEO_LIST = []
|
||||
let initVideoInfo = {
|
||||
src: "",
|
||||
coverStatus: true,
|
||||
coverUrl: "",
|
||||
flag: false,
|
||||
objectFit: "",
|
||||
mode: "",
|
||||
isMuted: false, // 默认不静音
|
||||
autoplay: false,
|
||||
loop: true,
|
||||
controls: false,
|
||||
enablePlayGesture: true,
|
||||
showFullscreenBtn: false,
|
||||
enableProgressGesture: false,
|
||||
showPlayBtn: false,
|
||||
showProgress: false
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
popVideoList: {
|
||||
type: Array,
|
||||
default: [] // 默认值设为空数组JSON,避免parse报错
|
||||
},
|
||||
marginTop: {
|
||||
type: String,
|
||||
default: "88" // 默认值设为空数组JSON,避免parse报错
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 测试视频地址,替换自己的
|
||||
videoUrl: "https://www.w3school.com.cn/i/movie.mp4",
|
||||
videoContext: null
|
||||
playSetTime:null,
|
||||
showSlider: true,
|
||||
progressTime: 0,
|
||||
progressValue: 0,
|
||||
boxHeight: 0,
|
||||
objectFit: "fill",
|
||||
mode: "scaleToFill",
|
||||
winWidth: 1,
|
||||
winHeight: 1,
|
||||
videoIndex: 0,
|
||||
viewTop: 0,
|
||||
viewTopPostion: 0,
|
||||
videoList: [],
|
||||
videoListLength: 0,
|
||||
itemViewTop0: 0,
|
||||
itemViewTop1: 0,
|
||||
itemViewTop2: 0,
|
||||
itemViewTop3: 0,
|
||||
itemViewTop4: 0,
|
||||
videoInfo_0: initVideoInfo,
|
||||
videoInfo_1: initVideoInfo,
|
||||
videoInfo_2: initVideoInfo,
|
||||
videoInfo_3: initVideoInfo,
|
||||
videoInfo_4: initVideoInfo,
|
||||
stopIcon: '',
|
||||
videotouchstartTimestamp: 0,
|
||||
videotouchendTimestamp: 0,
|
||||
moveView: true,
|
||||
cover: true,
|
||||
slidingStatus: false,
|
||||
videoPlayingStatus: false,
|
||||
preloadedIndex: [],
|
||||
startPageY: 0,
|
||||
endPageY: 0,
|
||||
// 新增:控制可视dot的数组
|
||||
visibleDots: [],
|
||||
};
|
||||
},
|
||||
onReady() {
|
||||
// 初始化视频实例
|
||||
this.videoContext = uni.createVideoContext("fullVideo", this);
|
||||
watch: {
|
||||
// videoList: {
|
||||
// handler(newVal, oldVal) {
|
||||
|
||||
|
||||
// },
|
||||
// immediate: true, // 可选:组件初始化时立即执行一次(即使值未变化)
|
||||
// deep: false // 普通类型无需深度监听,默认false
|
||||
// }
|
||||
},
|
||||
created(options) {
|
||||
//#ifdef APP-PLUS
|
||||
plus.screen.lockOrientation("portrait-primary")
|
||||
//#endif
|
||||
if (this.popVideoList.length) {
|
||||
try {
|
||||
VIDEO_LIST = []
|
||||
this.popVideoList.forEach((item, index) => {
|
||||
let obj = {
|
||||
"src": "",
|
||||
"coverStatus": true,
|
||||
"coverUrl": "",
|
||||
"flag": false,
|
||||
"objectFit": "contain",
|
||||
"mode": "aspectFit",
|
||||
"isMuted": false, // 默认不静音
|
||||
"autoplay": false,
|
||||
"loop": true,
|
||||
"controls": false,
|
||||
"enablePlayGesture": true,
|
||||
"showFullscreenBtn": false,
|
||||
"enableProgressGesture": false,
|
||||
"showPlayBtn": false,
|
||||
"showProgress": false,
|
||||
"name": ""
|
||||
}
|
||||
obj.name = item.name
|
||||
obj.src = item.url
|
||||
obj.coverUrl = item.url +
|
||||
`?x-oss-process=video/snapshot,t_1000,m_fast,f_jpg,w_600,ar_auto`
|
||||
VIDEO_LIST.push(obj)
|
||||
if (index == 0) {
|
||||
initVideoInfo = obj
|
||||
}
|
||||
})
|
||||
} catch (e) {}
|
||||
this.getSystemInfo();
|
||||
this.videoList = VIDEO_LIST;
|
||||
this.videoListLength = this.videoList.length;
|
||||
this.boxHeight = this.videoListLength * this.winHeight;
|
||||
for (let i = 0; i < 5; i++) {
|
||||
if (this.videoList[i]) {
|
||||
this['videoInfo_' + i] = this.videoList[i]
|
||||
}
|
||||
}
|
||||
// 初始化可视dot范围
|
||||
this.updateVisibleDots();
|
||||
// setTimeout(() => {
|
||||
// this.playVideo(0)
|
||||
// }, 500)
|
||||
}
|
||||
},
|
||||
onUnload() {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
this.unloadVideo(i)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getVideoTop() {
|
||||
return uni.upx2px(this.marginTop)
|
||||
},
|
||||
viewTopLength() {
|
||||
return `height:${this.boxHeight}px;top:${this.viewTop}px;`
|
||||
},
|
||||
fillScreen() {
|
||||
let style = `height:${this.winHeight}px;width:${this.winWidth}px;`
|
||||
return style
|
||||
},
|
||||
fillScreen2() {
|
||||
let style = `height:auto;width:${this.winWidth}px;`
|
||||
return style
|
||||
},
|
||||
itemViewTopLength0() {
|
||||
return `height:${this.winHeight}px;top:${this.itemViewTop0}px;`
|
||||
},
|
||||
itemViewTopLength1() {
|
||||
return `height:${this.winHeight}px;top:${this.itemViewTop1}px;`
|
||||
},
|
||||
itemViewTopLength2() {
|
||||
return `height:${this.winHeight}px;top:${this.itemViewTop2}px;`
|
||||
},
|
||||
itemViewTopLength3() {
|
||||
return `height:${this.winHeight}px;top:${this.itemViewTop3}px;`
|
||||
},
|
||||
itemViewTopLength4() {
|
||||
return `height:${this.winHeight}px;top:${this.itemViewTop4}px;`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 进入横屏全屏
|
||||
openFullScreen() {
|
||||
// direction 90:横屏;-90反向横屏;0自适应
|
||||
this.videoContext.requestFullScreen({
|
||||
direction: 90
|
||||
});
|
||||
},
|
||||
// 退出全屏
|
||||
closeFullScreen() {
|
||||
this.videoContext.exitFullScreen();
|
||||
},
|
||||
// 播放监听
|
||||
onPlay() {
|
||||
console.log("视频开始播放");
|
||||
},
|
||||
// 暂停监听
|
||||
onPause() {
|
||||
console.log("视频暂停");
|
||||
},
|
||||
// 全屏状态切换监听
|
||||
handleFullScreenChange(e) {
|
||||
if (e.detail.fullScreen) {
|
||||
uni.setNavigationBarHidden(true); // 全屏隐藏顶部导航
|
||||
} else {
|
||||
uni.setNavigationBarHidden(false); // 退出恢复导航
|
||||
// 新增:切换视频静音状态
|
||||
toggleMute(videoNum) {
|
||||
// 1. 切换数据层状态
|
||||
this['videoInfo_' + videoNum].isMuted = !this['videoInfo_' + videoNum].isMuted;
|
||||
// 2. 同步视频实例静音状态(恢复并完善原有注释代码,加容错)
|
||||
const videoCtx = uni.createVideoContext("video_id_" + videoNum, this);
|
||||
if (videoCtx) {
|
||||
videoCtx.mute(this['videoInfo_' + videoNum].isMuted);
|
||||
}
|
||||
console.log("当前全屏状态:", e.detail.fullScreen);
|
||||
},
|
||||
// 视频播放结束
|
||||
onVideoEnd() {
|
||||
// 播放完毕自动退出全屏
|
||||
this.videoContext.exitFullScreen();
|
||||
// 修改:点击dot跳转 - 传真实的视频索引
|
||||
jumpToVideo(targetIndex) {
|
||||
if (targetIndex === this.videoIndex || this.slidingStatus) return;
|
||||
this.stopVideo(this.videoIndex % 5, true);
|
||||
const diff = targetIndex - this.videoIndex;
|
||||
this.videoIndex = targetIndex;
|
||||
this.viewTopPostion = -this.videoIndex * this.winHeight;
|
||||
this.viewTop = this.viewTopPostion;
|
||||
if (this.videoListLength > 5) {
|
||||
this.sortItemView(diff > 0 ? -1 : 1);
|
||||
}
|
||||
// 更新可视dot范围
|
||||
this.updateVisibleDots();
|
||||
setTimeout(() => {
|
||||
this.playVideo(this.videoIndex % 5);
|
||||
}, 400);
|
||||
},
|
||||
// 核心:更新可视dot范围 - 最多显示5个
|
||||
updateVisibleDots() {
|
||||
const maxShow = 5;
|
||||
const total = this.videoListLength;
|
||||
// 视频总数 ≤ 5,显示全部
|
||||
if (total <= maxShow) {
|
||||
this.visibleDots = Array.from({
|
||||
length: total
|
||||
}, (_, i) => i);
|
||||
return;
|
||||
}
|
||||
// 视频总数 > 5,显示包含当前索引的5个dot
|
||||
// 计算起始索引,避免越界
|
||||
let start = Math.max(0, Math.min(this.videoIndex - 2, total - maxShow));
|
||||
// 生成5个连续的索引
|
||||
this.visibleDots = Array.from({
|
||||
length: maxShow
|
||||
}, (_, i) => start + i);
|
||||
},
|
||||
progressTouchend() {
|
||||
let s = Math.round(this.progressValue / 100 * this.time)
|
||||
let i = this.videoIndex % 5
|
||||
uni.createVideoContext("video_id_" + i, this).seek(s)
|
||||
uni.createVideoContext("video_id_" + i, this).play()
|
||||
},
|
||||
sliderchanging(e) {
|
||||
console.log(3333, e)
|
||||
},
|
||||
getSystemInfo() {
|
||||
var _this = this;
|
||||
uni.getSystemInfo({
|
||||
success: function(res) {
|
||||
_this.winWidth = res.windowWidth;
|
||||
_this.winHeight = res.windowHeight;
|
||||
let p = uni.upx2px(150)
|
||||
_this.stopIcon = `left:${(res.windowWidth - p)/2}px;top:${(res.windowHeight - p)/2}px;`
|
||||
_this.itemViewTop1 = res.windowHeight
|
||||
_this.itemViewTop2 = res.windowHeight * 2
|
||||
_this.itemViewTop3 = res.windowHeight * 3
|
||||
_this.itemViewTop4 = res.windowHeight * 4
|
||||
},
|
||||
})
|
||||
},
|
||||
unloadVideo(index) {
|
||||
if (index < 0 || index >= this.videoListLength) return;
|
||||
const nodeNum = index % 5;
|
||||
const videoCtx = uni.createVideoContext("video_id_" + nodeNum, this);
|
||||
videoCtx.stop();
|
||||
this.preloadedIndex = this.preloadedIndex.filter(item => item !== index);
|
||||
},
|
||||
playVideo(num) {
|
||||
clearTimeout(this.playSetTime)
|
||||
uni.$uv.debounce(() => {
|
||||
this.videoPlayingStatus = true
|
||||
this["videoInfo_" + num].flag = true
|
||||
let VideoContext = uni.createVideoContext("video_id_" + num, this)
|
||||
this.playSetTime = setTimeout(() => {
|
||||
VideoContext.play()
|
||||
}, 400)
|
||||
}, 30)
|
||||
},
|
||||
stopVideo(num, control = false) {
|
||||
const videoCtx = uni.createVideoContext("video_id_" + num, this);
|
||||
if (!control) {
|
||||
this['videoInfo_' + num].coverStatus = true;
|
||||
videoCtx.stop()
|
||||
} else {
|
||||
videoCtx.pause()
|
||||
}
|
||||
this["videoInfo_" + num].flag = false
|
||||
},
|
||||
nowPlayVideo() {
|
||||
clearTimeout(this.playSetTime)
|
||||
uni.$uv.debounce(() => {
|
||||
this.videoPlayingStatus = true
|
||||
this["videoInfo_" + this.videoIndex].flag = true
|
||||
let VideoContext = uni.createVideoContext("video_id_" + this.videoIndex, this)
|
||||
this.playSetTime = setTimeout(() => {
|
||||
VideoContext.play()
|
||||
}, 400)
|
||||
}, 30)
|
||||
},
|
||||
nowStopVideo() {
|
||||
const videoCtx = uni.createVideoContext("video_id_" + this.videoIndex, this);
|
||||
videoCtx.pause()
|
||||
this["videoInfo_" + this.videoIndex].flag = false
|
||||
},
|
||||
videoClick() {
|
||||
let num = this.videoIndex % 5
|
||||
if (this["videoInfo_" + num].flag) {
|
||||
this.stopVideo(num, true)
|
||||
} else {
|
||||
this.playVideo(num, true)
|
||||
}
|
||||
},
|
||||
videotouchstart(e) {
|
||||
this.videotouchendTimestamp = this.videotouchstartTimestamp
|
||||
this.videotouchstartTimestamp = e.timestamp
|
||||
if ((this.videotouchstartTimestamp - this.videotouchendTimestamp) < 500) return
|
||||
if (this.slidingStatus) return
|
||||
this.startPageY = e.changedTouches[0].screenY;
|
||||
},
|
||||
videotochmove(e) {
|
||||
if ((this.videotouchstartTimestamp - this.videotouchendTimestamp) < 500) return
|
||||
if (this.slidingStatus) return
|
||||
this.endPageY = e.changedTouches[0].screenY;
|
||||
let sliding = this.endPageY - this.startPageY
|
||||
if (sliding > 20 || sliding < -20) {
|
||||
this.moveView = false
|
||||
} else {
|
||||
this.moveView = true
|
||||
}
|
||||
if (this.videoIndex == 0 && sliding > 50) {
|
||||
this.viewTop = 50
|
||||
} else if (this.videoIndex == this.videoListLength - 1 && sliding < 0) {
|
||||
this.viewTop = this.viewTopPostion
|
||||
} else {
|
||||
this.viewTop = this.viewTopPostion + sliding
|
||||
}
|
||||
},
|
||||
videotouchend(e) {
|
||||
if ((this.videotouchstartTimestamp - this.videotouchendTimestamp) < 500) return
|
||||
if (this.slidingStatus) return
|
||||
this.moveView = true
|
||||
this.endPageY = e.changedTouches[0].screenY;
|
||||
let sliding = this.endPageY - this.startPageY
|
||||
if ((sliding >= -40 && sliding < 0) || (sliding <= 40 && sliding > 0)) {
|
||||
this.slidingStatus = true
|
||||
this.videoSlidingReset(sliding)
|
||||
return
|
||||
}
|
||||
if (sliding < -30) {
|
||||
this.slidingStatus = true
|
||||
if (this.videoIndex == this.videoListLength - 1) {
|
||||
this.videoSlidingReset(sliding)
|
||||
uni.showToast({
|
||||
title: "已经到底了",
|
||||
icon: "none"
|
||||
})
|
||||
return
|
||||
}
|
||||
this.moveView = false
|
||||
this.videoSlidingToTop(sliding)
|
||||
return
|
||||
}
|
||||
if (sliding > 30) {
|
||||
this.slidingStatus = true
|
||||
if (this.videoIndex == 0) {
|
||||
this.videoSlidingReset(sliding)
|
||||
return
|
||||
}
|
||||
this.moveView = false
|
||||
this.videoSlidingToBottom(sliding)
|
||||
}
|
||||
},
|
||||
videoSlidingReset(sliding) {
|
||||
this.viewTop = this.viewTopPostion
|
||||
this.slidingStatus = false
|
||||
},
|
||||
videoSlidingToTop(sliding) {
|
||||
this.stopVideo(this.videoIndex % 5, true)
|
||||
this.videoIndex++
|
||||
if (this.videoListLength > 5) {
|
||||
this.sortItemView(sliding)
|
||||
}
|
||||
this.viewTopPostion = this.viewTopPostion - this.winHeight
|
||||
setTimeout(() => {
|
||||
this.playVideo(this.videoIndex % 5)
|
||||
}, 5)
|
||||
let timer = setInterval(() => {
|
||||
this.viewTop = this.viewTop - 35
|
||||
if (this.viewTop < (this.viewTopPostion + 10)) {
|
||||
this.viewTop = this.viewTopPostion
|
||||
clearInterval(timer)
|
||||
this.slidingStatus = false
|
||||
this.slidingCallback()
|
||||
}
|
||||
}, 3)
|
||||
},
|
||||
videoSlidingToBottom(sliding) {
|
||||
this.stopVideo(this.videoIndex % 5, true)
|
||||
this.videoIndex--
|
||||
if (this.videoListLength > 5) {
|
||||
this.sortItemView(sliding)
|
||||
}
|
||||
this.viewTopPostion = this.viewTopPostion + this.winHeight
|
||||
setTimeout(() => {
|
||||
this.playVideo(this.videoIndex % 5)
|
||||
}, 5)
|
||||
let timer = setInterval(() => {
|
||||
this.viewTop = this.viewTop + 35
|
||||
if (this.viewTop > (this.viewTopPostion - 10)) {
|
||||
this.viewTop = this.viewTopPostion
|
||||
clearInterval(timer)
|
||||
this.slidingStatus = false
|
||||
this.slidingCallback()
|
||||
}
|
||||
}, 3)
|
||||
},
|
||||
// 修改:滑动结束后更新可视dot
|
||||
slidingCallback() {
|
||||
this.progressValue = 0
|
||||
this.updateVisibleDots();
|
||||
},
|
||||
//滑动组件排序
|
||||
sortItemView(silding) {
|
||||
// 向上滑动
|
||||
if (silding < 0) {
|
||||
if (this.videoIndex > 2 && this.videoIndex < this.videoListLength - 2) {
|
||||
let i = (this.videoIndex - 3) % 5
|
||||
this["itemViewTop" + i] = this["itemViewTop" + i] + this.winHeight * 5
|
||||
this['videoInfo_' + i] = this.videoList[this.videoIndex + 2]
|
||||
}
|
||||
return
|
||||
}
|
||||
// 向下滑动
|
||||
if (silding > 0) {
|
||||
if (this.videoIndex > 1 && this.videoIndex < this.videoListLength - 3) {
|
||||
let i = (this.videoIndex + 3) % 5
|
||||
this["itemViewTop" + i] = this["itemViewTop" + i] - this.winHeight * 5
|
||||
this['videoInfo_' + i] = this.videoList[this.videoIndex - 2]
|
||||
}
|
||||
}
|
||||
},
|
||||
playing(i) {
|
||||
setTimeout(() => {
|
||||
this['videoInfo_' + i].coverStatus = false
|
||||
this.moveView = true
|
||||
this.slidingStatus = false
|
||||
}, 600)
|
||||
},
|
||||
timeupdate(i, e) {
|
||||
if (this.videoPlayingStatus) {
|
||||
this.slidingStatus = false
|
||||
this.videoPlayingStatus = false
|
||||
setTimeout(() => {
|
||||
this['videoInfo_' + i].coverStatus = false
|
||||
this.moveView = true
|
||||
}, 200)
|
||||
}
|
||||
this["videoInfo_" + i].flag = true
|
||||
if (e.detail.duration >= this.progressTime) {
|
||||
if (this.videoIndex%5 == i) {
|
||||
this.time = e.detail.duration
|
||||
this.progress = e.detail.currentTime
|
||||
this.progressValue = (e.detail.currentTime / e.detail.duration) * 100
|
||||
}
|
||||
|
||||
this.showProgress = true
|
||||
} else {
|
||||
this.showProgress = false
|
||||
}
|
||||
},
|
||||
ended() {
|
||||
let num = this.videoIndex % 5
|
||||
this["videoInfo_" + num].flag = false
|
||||
this.progressValue = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.video-page {
|
||||
padding: 15rpx;
|
||||
<style scoped lang="less">
|
||||
.view-box {
|
||||
// position: fixed;
|
||||
// left: 0;
|
||||
// right: 0;
|
||||
background-color: #000;
|
||||
// z-index: 900;
|
||||
}
|
||||
|
||||
.video-box {
|
||||
width: 100%;
|
||||
height: 420rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.btn-wrap {
|
||||
margin-top: 30rpx;
|
||||
.video-image {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 2001;
|
||||
}
|
||||
|
||||
.video-action {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 2008;
|
||||
}
|
||||
|
||||
.video-texts {
|
||||
position: absolute;
|
||||
left: 30rpx;
|
||||
right: 30rpx;
|
||||
bottom: 120rpx;
|
||||
z-index: 2009; // 确保在视频上方显示
|
||||
|
||||
.video-title {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
lines: 1;
|
||||
max-width: 240rpx;
|
||||
}
|
||||
|
||||
.video-score {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.video-text {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.video-sound {
|
||||
width: 44rpx;
|
||||
height: 42rpx;
|
||||
cursor: pointer; // 点击指针,提示可点击
|
||||
}
|
||||
}
|
||||
|
||||
.cover-view-stop {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
width: 150rpx;
|
||||
height: 200rpx;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.progress-view {
|
||||
z-index: 9999;
|
||||
position: fixed;
|
||||
left: 30rpx;
|
||||
right: 30rpx;
|
||||
bottom: 80rpx;
|
||||
|
||||
.progress-slider {}
|
||||
}
|
||||
|
||||
// 修改:Dot指示器样式 - 最多显示5个 + 过渡动画
|
||||
.dots {
|
||||
position: fixed;
|
||||
left: 20rpx;
|
||||
top: 0;
|
||||
transform: translateY(-50%);
|
||||
z-index: 9999;
|
||||
flex-direction: row;
|
||||
|
||||
.dots-container {
|
||||
// 限制最多显示5个,超出隐藏
|
||||
width: fit-content;
|
||||
overflow: hidden;
|
||||
margin: auto 0;
|
||||
|
||||
.dot-item {
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 50%;
|
||||
// 核心:过渡动画,切换更丝滑
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
cursor: pointer;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
&.active {
|
||||
width: 10rpx;
|
||||
height: 30rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pageNumber {
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
line-height: 36rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
margin-left: 6rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-row-center-between {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-row-start-between {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-row-center-center {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flex-row-center {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex-row-start {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.flex-row-end-between {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
<template>
|
||||
<view class="video-page">
|
||||
<!-- 原生视频组件:全端兼容 -->
|
||||
<video id="fullVideo" class="video-box" :src="videoUrl" controls show-fullscreen-btn enable-progress-gesture
|
||||
:autoplay="true" :loop="false" :muted="false" @play="onPlay" @pause="onPause" object-fit="cover" :direction="90"
|
||||
@fullscreenchange="handleFullScreenChange" @ended="onVideoEnd" @fullscreenclick="tapback"></video>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
videoUrl: "",
|
||||
videoContext: null
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
console.log(options, '页面参数');
|
||||
// 接收视频地址
|
||||
if (options.url) {
|
||||
this.videoUrl = options.url;
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
// #ifdef APP-PLUS
|
||||
//plus.screen.unlockOrientation(); //解除屏幕方向的锁定,但是不一定是竖屏;
|
||||
|
||||
// #endif
|
||||
// 初始化视频实例(唯一正确位置)
|
||||
this.videoContext = uni.createVideoContext("fullVideo", this);
|
||||
// 页面渲染完成后 安全触发自动全屏
|
||||
//this.autoFullScreen();
|
||||
},
|
||||
methods: {
|
||||
tapback(e) {
|
||||
console.log('点击全屏按钮');
|
||||
// if (e.target.fullScreen) {
|
||||
// plus.screen.lockOrientation('landscape'); //锁死屏幕方向为竖屏
|
||||
// }else{
|
||||
// plus.screen.lockOrientation('portrait'); //锁死屏幕方向为竖屏
|
||||
// }
|
||||
},
|
||||
// 自动全屏(核心:修复iOS方向错乱)
|
||||
autoFullScreen() {
|
||||
if (!this.videoContext) return;
|
||||
|
||||
// 区分平台设置方向:iOS用0自适应,安卓用90横屏
|
||||
const direction = uni.getSystemInfoSync().platform === 'ios' ? 0 : 90;
|
||||
|
||||
// 延迟执行,避免视频未加载完成导致全屏失败
|
||||
setTimeout(() => {
|
||||
this.videoContext.requestFullScreen({
|
||||
direction: direction
|
||||
});
|
||||
}, 300)
|
||||
},
|
||||
// 手动横屏全屏
|
||||
openFullScreen() {
|
||||
if (!this.videoContext) return;
|
||||
const direction = uni.getSystemInfoSync().platform === 'ios' ? 0 : 90;
|
||||
this.videoContext.requestFullScreen({
|
||||
direction
|
||||
});
|
||||
},
|
||||
// 退出全屏
|
||||
closeFullScreen() {
|
||||
if (!this.videoContext) return;
|
||||
this.videoContext.exitFullScreen();
|
||||
},
|
||||
// 播放监听
|
||||
onPlay() {
|
||||
console.log("视频开始播放");
|
||||
},
|
||||
// 暂停监听
|
||||
onPause() {
|
||||
console.log("视频暂停");
|
||||
},
|
||||
// 全屏状态切换
|
||||
handleFullScreenChange(e) {
|
||||
// 全屏隐藏导航栏,退出显示
|
||||
// uni.setNavigationBarHidden(!!e.detail.fullScreen);
|
||||
console.log("全屏状态:", e.detail.fullScreen);
|
||||
},
|
||||
// 视频播放完毕
|
||||
onVideoEnd() {
|
||||
this.closeFullScreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.video-page {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.video-box {
|
||||
width: 100%;
|
||||
/* 自适应高度,避免拉伸 */
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,59 +1,52 @@
|
|||
<template>
|
||||
<view class="container">
|
||||
<view class="positonFixed">
|
||||
<view class="header-top flex-row-center" :style="{ height: `${100 + statusBarHeight}rpx`,paddingTop:`${statusBarHeight}rpx`}">
|
||||
<view class="header-top flex-row-center" :class="{videoTop:current==0}"
|
||||
:style="{ height: `${88+statusBarHeight}rpx`,paddingTop: `${statusBarHeight}rpx`}">
|
||||
<view class="left-area" @click="goBack">
|
||||
<image src="/static/images/back.png" mode="aspectFit" class="back-icon"></image>
|
||||
<image src="/static/images/whiteBack.png" mode="aspectFit" class="back-icon"></image>
|
||||
</view>
|
||||
<view class="flex-row-center-center" style="flex: 1;margin-right: 18rpx;height:66rpx;">
|
||||
<view class="flex-row-center-center" style="flex: 1;margin-right: 18rpx;height:66rpx;">
|
||||
<uv-tabs :list="list" @click="tabsClick" itemStyle="height:66rpx;" :activeStyle="activeStyle"
|
||||
:inactiveStyle="inactiveStyle" :current="current" :lineColor="`rgba(232, 16, 30, 1)`"></uv-tabs>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<scroll-view scroll-x style="height: 100rpx;background-color: #fff;" v-if="current==1">
|
||||
<scroll-view scroll-x style="height: 100rpx;" v-if="current==1">
|
||||
<view class="container-tabs flex-row-center">
|
||||
<view class="container-tab flex-row-center-center" @click="clickTab(item)"
|
||||
:class="{active:cardListIndex==item.id}" v-for="(item,index) in cardList[user_type]"
|
||||
:key="index">
|
||||
:class="{active:cardListIndex==item.id}" v-for="(item,index) in cardList[1]" :key="index">
|
||||
<text class="container-tab-text">{{ item.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
<view :style="swiperStyle3"></view>
|
||||
|
||||
<view class="container-content" :style="swiperStyle2">
|
||||
<swiper class="swiper" circular :style="swiperStyle" :current="current" @change="swiperChange"
|
||||
:disable-touch="current==0">
|
||||
<swiper class="swiper" circular :style="swiperStyle" :current="current" @change="swiperChange" :disable-touch="current==0">
|
||||
<swiper-item>
|
||||
<scroll-view scroll-y :style="{height:`${viewportHeight - 100 - statusBarHeight}rpx`}">
|
||||
<view class="swiper-items3">
|
||||
<view class="swiper-item3" :class="{item2Left:index%2 == 0}"
|
||||
v-for="(item,index) in videoList" :key="index" @click="tovideo(item)">
|
||||
<image class="swiper-item3-video" mode="aspectFill" :src="item.img"></image>
|
||||
<image
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/c6c039fc-99fd-492e-ae9a-ed43260c94ef.png"
|
||||
mode="widthFix"
|
||||
style="width: 80rpx;position: absolute;top: 50%;left: 50%;transform: translate3d(-50%, -50%, 0);">
|
||||
</image>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<videoSlide ref="ideoSlideRrf" :popVideoList="videoList" :marginTop="`${88 + this.statusBarHeight}`" v-show="current==0" v-if="videoList.length"></videoSlide>
|
||||
</swiper-item>
|
||||
<swiper-item>
|
||||
<scroll-view scroll-y :style="{height:`${viewportHeight - 100 - statusBarHeight - 100}rpx`}">
|
||||
<scroll-view scroll-y :style="{height:`${viewportHeight-88-this.statusBarHeight-100}rpx`}">
|
||||
<view class="swiper-items2">
|
||||
<view class="swiper-item2" :class="{item2Left:index%2 == 0}"
|
||||
v-for="(item,index) in imagObj[cardListIndex]" :key="index" @click="toimg(item)">
|
||||
v-for="(item,index) in imagObj[cardListIndex]" :key="index">
|
||||
<image class="swiper-item2-img" mode="aspectFill" :src="item.url"></image>
|
||||
<view class="swiper-item2-title">
|
||||
<text class="swiper-item2-title-text">{{ item.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
</scroll-view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
|
@ -75,23 +68,6 @@
|
|||
title: "主图",
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
title: "作品",
|
||||
id: 3
|
||||
},
|
||||
{
|
||||
title: "其他",
|
||||
id: 4
|
||||
}
|
||||
],
|
||||
2: [{
|
||||
title: "全部",
|
||||
id: 0
|
||||
},
|
||||
{
|
||||
title: "主图",
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
title: "环境",
|
||||
id: 2
|
||||
|
|
@ -118,7 +94,7 @@
|
|||
inactiveStyle: {
|
||||
fontWeight: 500,
|
||||
fontSize: "32rpx",
|
||||
color: "#333333",
|
||||
color: "#666666",
|
||||
},
|
||||
current: 1,
|
||||
statusBarHeight: 0,
|
||||
|
|
@ -132,7 +108,6 @@
|
|||
};
|
||||
},
|
||||
async onLoad(options) {
|
||||
|
||||
// 获取状态栏高度
|
||||
const systemInfo = await uni.getSystemInfoSync()
|
||||
this.systemInfo = systemInfo
|
||||
|
|
@ -145,12 +120,6 @@
|
|||
this.getVideoList()
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
// // #ifdef APP-PLUS
|
||||
// plus.screen.unlockOrientation(); //解除屏幕方向的锁定,但是不一定是竖屏;
|
||||
// plus.screen.lockOrientation('portrait'); //锁死屏幕方向为竖屏
|
||||
// // #endif
|
||||
},
|
||||
computed: {
|
||||
// 计算swiper的样式
|
||||
swiperStyle() {
|
||||
|
|
@ -159,82 +128,68 @@
|
|||
// 注意:100vh 是视口高度,需要先转数值计算,再拼接单位
|
||||
|
||||
let viewportHeight = this.pxToRpx(this.systemInfo.windowHeight || window?.innerHeight || document
|
||||
?.documentElement?.clientHeight || 0, screenWidth);
|
||||
let height = viewportHeight - 100 - this.statusBarHeight;
|
||||
?.documentElement?.clientHeight|| 0, screenWidth ) ;
|
||||
let height = viewportHeight - 88 - this.statusBarHeight;
|
||||
return {
|
||||
height: `${height}rpx`
|
||||
};
|
||||
}
|
||||
return {
|
||||
height: `${this.viewportHeight - 100 - this.statusBarHeight}rpx`
|
||||
height: `${this.viewportHeight}rpx`
|
||||
};
|
||||
},
|
||||
swiperStyle2() {
|
||||
if (this.current == 1) {
|
||||
return {
|
||||
height: `${this.viewportHeight-100-this.statusBarHeight-100}rpx`
|
||||
marginTop: `${88 + this.statusBarHeight + 100}rpx`,
|
||||
height: `${this.viewportHeight-88-this.statusBarHeight-100}rpx`
|
||||
};
|
||||
}
|
||||
return {
|
||||
height: `${this.viewportHeight - 100 - this.statusBarHeight}rpx`
|
||||
};
|
||||
},
|
||||
swiperStyle3() {
|
||||
if (this.current == 1) {
|
||||
return {
|
||||
width: `750rpx`,
|
||||
height: `${200 + this.statusBarHeight}rpx`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
width: `750rpx`,
|
||||
height: `${100 + this.statusBarHeight}rpx`,
|
||||
height: `${this.viewportHeight}rpx`
|
||||
};
|
||||
},
|
||||
viewportHeight() {
|
||||
let screenWidth = this.systemInfo.screenWidth;
|
||||
// 注意:100vh 是视口高度,需要先转数值计算,再拼接单位
|
||||
let viewportHeight = this.pxToRpx(this.systemInfo.windowHeight || window?.innerHeight || document
|
||||
?.documentElement?.clientHeight || 0, screenWidth);
|
||||
?.documentElement?.clientHeight|| 0, screenWidth) ;
|
||||
return viewportHeight
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack(-1)
|
||||
},
|
||||
toimg(item) {
|
||||
console.log(item, 'item');
|
||||
uni.previewImage({
|
||||
urls: [item.url], // 外面加 [] 变成数组
|
||||
current: 0 // 可选,默认第一张
|
||||
})
|
||||
},
|
||||
tovideo(item) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/album/components/videoplayer?url=' + item.url
|
||||
})
|
||||
},
|
||||
clickTab(item) {
|
||||
this.cardListIndex = item.id
|
||||
},
|
||||
tabsClick(e) {
|
||||
console.log('12312312312');
|
||||
this.$nextTick(() => {
|
||||
|
||||
this.current = e.index
|
||||
if(this.current==1){
|
||||
this.activeStyle.color = "#333333"
|
||||
this.inactiveStyle.color = "#666666"
|
||||
this.$refs.ideoSlideRrf.nowStopVideo()
|
||||
}
|
||||
if(this.current==0){
|
||||
this.activeStyle.color = "#fff"
|
||||
this.inactiveStyle.color = "#ccc"
|
||||
this.$refs.ideoSlideRrf.nowPlayVideo()
|
||||
}
|
||||
})
|
||||
|
||||
this.current = e.index
|
||||
this.activeStyle.color = "#333333"
|
||||
this.inactiveStyle.color = "#666666"
|
||||
},
|
||||
swiperChange(e) {
|
||||
this.$nextTick(() => {
|
||||
this.current = e.detail.current
|
||||
if (this.current == 1) {
|
||||
if(this.current==1){
|
||||
this.activeStyle.color = "#333333"
|
||||
this.inactiveStyle.color = "#666666"
|
||||
this.$refs.ideoSlideRrf.nowStopVideo()
|
||||
}
|
||||
if (this.current == 0) {
|
||||
this.activeStyle.color = "#333333"
|
||||
this.inactiveStyle.color = "#666666"
|
||||
if(this.current==0){
|
||||
this.activeStyle.color = "#fff"
|
||||
this.inactiveStyle.color = "#ccc"
|
||||
this.$refs.ideoSlideRrf.nowPlayVideo()
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -253,17 +208,12 @@
|
|||
type: 1
|
||||
}).then(res => {
|
||||
if (res.code == 200) {
|
||||
if (res.data.list.length != 0) {
|
||||
this.imagObj = res.data.list[1]
|
||||
let all = []
|
||||
for (let key in res.data.list[1]) {
|
||||
all = [...all, ...res.data.list[1][key]]
|
||||
}
|
||||
this.imagObj[0] = all
|
||||
} else {
|
||||
this.imagObj[0] = []
|
||||
this.imagObj = res.data.list[1]
|
||||
let all = []
|
||||
for (let key in res.data.list[1]) {
|
||||
all = [...all, ...res.data.list[1][key]]
|
||||
}
|
||||
|
||||
this.imagObj[0] = all
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
@ -274,17 +224,8 @@
|
|||
type: 2
|
||||
}).then(res => {
|
||||
if (res.code == 200) {
|
||||
if (res.data.list.length != 0) {
|
||||
console.log(res.data, 'res.data');
|
||||
for (let key in res.data.list[2]) {
|
||||
this.videoList = [...this.videoList, ...res.data.list[2][key]]
|
||||
this.videoList.forEach((item) => {
|
||||
item.img = item.url +
|
||||
'?x-oss-process=video/snapshot,t_1000,m_fast,f_jpg,w_600,ar_auto'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
this.videoList = []
|
||||
for (let key in res.data.list[2]) {
|
||||
this.videoList = [...this.videoList, ...res.data.list[2][key]]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -308,7 +249,7 @@
|
|||
z-index: 9999;
|
||||
background: #f5f5f5;
|
||||
padding: 0 24rpx;
|
||||
|
||||
|
||||
.left-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -325,12 +266,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.videoTop {
|
||||
.videoTop{
|
||||
background: transparent;
|
||||
|
||||
::v-deep .uv-tabs__wrapper__nav__line {
|
||||
background: #fff !important;
|
||||
::v-deep .uv-tabs__wrapper__nav__line{
|
||||
background: #fff!important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,7 +296,7 @@
|
|||
.container-tab-text {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 40rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -367,7 +306,6 @@
|
|||
|
||||
.container-content {
|
||||
z-index: 1000;
|
||||
|
||||
.swiper {
|
||||
background: #fff;
|
||||
|
||||
|
|
@ -411,47 +349,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.swiper-items3 {
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
padding-bottom: 20rpx;
|
||||
|
||||
.swiper-item3 {
|
||||
width: 370rpx;
|
||||
height: 370rpx;
|
||||
margin-top: 10rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-radius: 20rpx;
|
||||
|
||||
.swiper-item3-video {
|
||||
width: 370rpx;
|
||||
height: 370rpx;
|
||||
}
|
||||
|
||||
.swiper-item3-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 33rpx;
|
||||
padding: 0 8rpx;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 0rpx 0rpx 10rpx 0rpx;
|
||||
width: fit-content;
|
||||
|
||||
.swiper-item3-title-text {
|
||||
font-weight: 400;
|
||||
font-size: 18rpx;
|
||||
color: #FFFFFF;
|
||||
line-height: 33rpx;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item2Left {
|
||||
margin-right: 9rpx;
|
||||
}
|
||||
|
|
@ -501,4 +398,6 @@
|
|||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
? "门店下单购买后,您需到上门至门店进行服务,门店端展示价格为"
|
||||
: ""
|
||||
}}
|
||||
<text style="color: #FF4767" v-if="showShopPrice">{{
|
||||
<text style="color: #e8101e" v-if="showShopPrice">{{
|
||||
shopPrice
|
||||
}}</text>
|
||||
{{ showShopPrice ? "元。" : "" }}
|
||||
|
|
@ -364,6 +364,19 @@
|
|||
>
|
||||
</view>
|
||||
|
||||
<!-- 新增上门提醒弹窗-->
|
||||
<transition name="fade">
|
||||
<view class="popup-mask2" v-if="showReminderPopup" @click="closeReminderPopup(false)">
|
||||
<view class="popup-content2" @click.stop>
|
||||
<view class="popup-title">提示</view>
|
||||
<view class="popup-message">此服务是需要上门服务的哦~</view>
|
||||
<view class="popup-buttons">
|
||||
<view class="popup-btn popup-btn-notshow" @click="closeReminderPopup(true)">不再提示</view>
|
||||
<view class="popup-btn popup-btn-know" @click="closeReminderPopup(false)">我已知晓</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</transition>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -389,6 +402,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
showReminderPopup: false,
|
||||
artisanType: getApp().globalData.artisanType,
|
||||
nowQer: "xc",
|
||||
progress: 0,
|
||||
|
|
@ -460,6 +474,11 @@ export default {
|
|||
this.serviceTypes = this.serviceTypes.concat(res.data);
|
||||
});
|
||||
}
|
||||
// 判断是否显示上门提醒弹窗
|
||||
const notShow = uni.getStorageSync('addServiceReminderNotShow');
|
||||
if (!notShow) {
|
||||
this.showReminderPopup = true;
|
||||
}
|
||||
this.getUserInfo();
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -556,6 +575,14 @@ export default {
|
|||
return true;
|
||||
},
|
||||
|
||||
|
||||
closeReminderPopup(notShowAgain) {
|
||||
console.log('关闭弹窗,不再提示:', notShowAgain);
|
||||
if (notShowAgain) {
|
||||
uni.setStorageSync('addServiceReminderNotShow', true);
|
||||
}
|
||||
this.showReminderPopup = false;
|
||||
},
|
||||
goImgAndText() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/shop/add-img-text?list=${this.formData.graphic_details}`,
|
||||
|
|
@ -1207,13 +1234,13 @@ export default {
|
|||
|
||||
.btn-draft {
|
||||
background-color: #ffffff;
|
||||
color: #FF4767;
|
||||
border: 2rpx solid #FF4767;
|
||||
color: #e8101e;
|
||||
border: 2rpx solid #e8101e;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: #FF4767;
|
||||
background-color: #e8101e;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
|
|
@ -1485,13 +1512,13 @@ export default {
|
|||
}
|
||||
|
||||
.popup-btn-know {
|
||||
background-color: #FF4767;
|
||||
background-color: #e8101e;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.popup-btn-notshow {
|
||||
background-color: #ffffff;
|
||||
color: #FF4767;
|
||||
border: 1rpx #FF4767 solid;
|
||||
color: #e8101e;
|
||||
border: 1rpx #e8101e solid;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1204,7 +1204,7 @@ export default {
|
|||
}
|
||||
|
||||
.change-info-btn, .view-change-btn, .resubmit-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
/* 双按钮行样式 */
|
||||
|
|
@ -1225,7 +1225,7 @@ export default {
|
|||
}
|
||||
|
||||
.submit-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #F52540 0%, #E8101E 100%, #E8101E 100%);
|
||||
border-radius: 43rpx;
|
||||
padding: 0 15rpx;
|
||||
}
|
||||
|
|
@ -1257,7 +1257,7 @@ export default {
|
|||
.title-bar {
|
||||
width: 6rpx;
|
||||
height: 30rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
margin-right: 7rpx;
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
|
|
@ -1405,7 +1405,7 @@ export default {
|
|||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #fff;
|
||||
border-top: 4rpx solid #FF4767;
|
||||
border-top: 4rpx solid #E8101E;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 16rpx;
|
||||
|
|
@ -1470,8 +1470,8 @@ export default {
|
|||
}
|
||||
|
||||
.radio.checked {
|
||||
background-color: #FF4767;
|
||||
border-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-color: #E8101E;
|
||||
}
|
||||
|
||||
.radio-icon-image {
|
||||
|
|
@ -1640,7 +1640,7 @@ export default {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
.popup-btn .btn-text {
|
||||
|
|
@ -1659,7 +1659,7 @@ export default {
|
|||
}
|
||||
|
||||
.confirm-text {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -1771,13 +1771,13 @@ export default {
|
|||
}
|
||||
|
||||
.tip-btn.cancel {
|
||||
border: #FF4767 2rpx solid;
|
||||
border: #E8101E 2rpx solid;
|
||||
background-color: transparent;
|
||||
color: #FF4767;
|
||||
color: #e8101e;
|
||||
}
|
||||
|
||||
.tip-btn.confirm {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ export default {
|
|||
timeRange: '7days',
|
||||
count: 0,
|
||||
chartOpts: {
|
||||
color: ["#FF4767"],
|
||||
color: ["#E8101E"],
|
||||
padding: [15, 15, 0, 15],
|
||||
enableScroll: false,
|
||||
legend: false,
|
||||
|
|
@ -657,7 +657,7 @@ page {
|
|||
}
|
||||
|
||||
.time-filter .active {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
|
|
@ -676,7 +676,7 @@ page {
|
|||
width: 214rpx;
|
||||
height: 56rpx;
|
||||
background-color: #FFFFFF;
|
||||
border: 1rpx solid #FF4767;
|
||||
border: 1rpx solid #E8101E;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
@ -687,7 +687,7 @@ page {
|
|||
|
||||
.type-name {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.type-count {
|
||||
|
|
@ -708,7 +708,7 @@ page {
|
|||
background-color: #F53F3F;
|
||||
}
|
||||
.order-type-item.active {
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
}
|
||||
.order-type-item.active .type-name {
|
||||
color: #FFFFFF;
|
||||
|
|
@ -800,7 +800,7 @@ page {
|
|||
}
|
||||
.action-btn.verify .action-text {
|
||||
font-size: 28rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.nothings-box {
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ page {
|
|||
flex-flow: row nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: 1rpx solid #FF4767;
|
||||
border: 1rpx solid #E8101E;
|
||||
background-color: #FFF1F1;
|
||||
border-radius: 22rpx;
|
||||
box-sizing: border-box;
|
||||
|
|
@ -267,7 +267,7 @@ page {
|
|||
}
|
||||
.verified-text {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
.verified-text.no {
|
||||
color: #666666;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1544,7 +1544,7 @@ export default {
|
|||
|
||||
.tag {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
margin-left: 14rpx;
|
||||
}
|
||||
.textarea {
|
||||
|
|
@ -1655,7 +1655,7 @@ export default {
|
|||
.save-btn {
|
||||
width: 702rpx;
|
||||
height: 64rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -1762,8 +1762,8 @@ export default {
|
|||
}
|
||||
|
||||
.checkbox.checked {
|
||||
background-color: #FF4767;
|
||||
border-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-color: #E8101E;
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
|
|
@ -1796,7 +1796,7 @@ export default {
|
|||
}
|
||||
|
||||
.popup-btn.confirm {
|
||||
background: linear-gradient(90deg, #FF4767 0%, #FF618F 100%);
|
||||
background: linear-gradient(90deg, #E8101E 0%, #FF618F 100%);
|
||||
}
|
||||
|
||||
.popup-btn .btn-text {
|
||||
|
|
@ -1834,7 +1834,7 @@ export default {
|
|||
}
|
||||
|
||||
.region-tab.active {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -1846,7 +1846,7 @@ export default {
|
|||
transform: translateX(-50%);
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
|
||||
|
|
@ -1907,7 +1907,7 @@ export default {
|
|||
|
||||
.confirm-text {
|
||||
font-size: 32rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -1949,7 +1949,7 @@ export default {
|
|||
}
|
||||
|
||||
.time-block.active .time-value {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.time-separator {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
<view class="radio-item" @click="editable && setHealthCardValidType('permanent')">
|
||||
<view class="radio" :class="{ checked: displayData.health_card_expiry_type === 1 }">
|
||||
<image v-if="displayData.health_card_expiry_type === 1"
|
||||
src="/static/images/agree_y.png"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/cb185ec8-9d30-4e53-b5dc-14b546013a60"
|
||||
class="radio-icon-image"
|
||||
mode="aspectFit"></image>
|
||||
</view>
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
<view class="radio-item" @click="editable && setHealthCardValidType('date')">
|
||||
<view class="radio" :class="{ checked: displayData.health_card_expiry_type === 2 }">
|
||||
<image v-if="displayData.health_card_expiry_type === 2"
|
||||
src="/static/images/agree_y.png"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/cb185ec8-9d30-4e53-b5dc-14b546013a60"
|
||||
class="radio-icon-image"
|
||||
mode="aspectFit"></image>
|
||||
</view>
|
||||
|
|
@ -1292,7 +1292,7 @@ export default {
|
|||
}
|
||||
|
||||
.change-info-btn, .view-change-btn, .resubmit-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
/* 双按钮行样式 */
|
||||
|
|
@ -1313,7 +1313,7 @@ export default {
|
|||
}
|
||||
|
||||
.submit-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #F52540 0%, #E8101E 100%, #E8101E 100%);
|
||||
border-radius: 43rpx;
|
||||
padding: 0 15rpx;
|
||||
}
|
||||
|
|
@ -1345,7 +1345,7 @@ export default {
|
|||
.title-bar {
|
||||
width: 6rpx;
|
||||
height: 30rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
margin-right: 7rpx;
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
|
|
@ -1472,8 +1472,8 @@ export default {
|
|||
}
|
||||
|
||||
.radio.checked {
|
||||
background-color: #FF4767;
|
||||
border-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-color: #E8101E;
|
||||
}
|
||||
|
||||
.radio-icon-image {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@
|
|||
@click="toggleDistrictSelect(index)"
|
||||
>
|
||||
<view class="checkbox" :class="{ checked: district.checked }">
|
||||
<image v-if="district.checked" class="check-icon" src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/6948baf3-aad9-4d87-9483-9db0e462a3f7.png" mode="aspectFit"></image>
|
||||
<image v-if="district.checked" class="check-icon" src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/66325904-4603-48fd-b03b-90c684af96e9" mode="aspectFit"></image>
|
||||
</view>
|
||||
<text class="checkbox-label">{{district.area}}</text>
|
||||
</view>
|
||||
|
|
@ -752,7 +752,7 @@ export default {
|
|||
.title-bar {
|
||||
width: 6rpx;
|
||||
height: 30rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
margin-right: 10rpx;
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
|
|
@ -854,7 +854,7 @@ export default {
|
|||
|
||||
.limit-text {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
/* 区域选择器样式 */
|
||||
|
|
@ -942,7 +942,7 @@ export default {
|
|||
}
|
||||
|
||||
.region-tab.active {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -954,7 +954,7 @@ export default {
|
|||
transform: translateX(-50%);
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
|
||||
|
|
@ -994,8 +994,8 @@ export default {
|
|||
}
|
||||
|
||||
.checkbox.checked {
|
||||
background-color: #FF4767;
|
||||
border-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-color: #E8101E;
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
|
|
@ -1035,7 +1035,7 @@ export default {
|
|||
}
|
||||
|
||||
.popup-btn.confirm {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
.popup-btn .btn-text {
|
||||
|
|
@ -1075,11 +1075,11 @@ export default {
|
|||
}
|
||||
|
||||
.change-info-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
.view-change-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
/* 双按钮行样式 */
|
||||
|
|
@ -1100,7 +1100,7 @@ export default {
|
|||
}
|
||||
|
||||
.submit-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #F52540 0%, #E8101E 100%, #E8101E 100%);
|
||||
border-radius: 43rpx;
|
||||
padding: 0 15rpx;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,50 +270,14 @@ export default {
|
|||
});
|
||||
},
|
||||
viewEdit(item) {
|
||||
let url = `/pages/shop/add-service?id=${item.id}&state=${item.state}`;
|
||||
if (item.first_class_id) {
|
||||
url += `&first_class_id=${item.first_class_id}`;
|
||||
}
|
||||
if (item.second_class_id) {
|
||||
url += `&second_class_id=${item.second_class_id}`;
|
||||
}
|
||||
uni.navigateTo({ url });
|
||||
uni.navigateTo({
|
||||
url: `/pages/shop/add-service?id=${item.id}&state=${item.state}&first_class_id=${item.first_class_id}`,
|
||||
});
|
||||
|
||||
},
|
||||
async getCurrentSjId() {
|
||||
const sjInfo = this.$store && this.$store.state && this.$store.state.sjInfo;
|
||||
if (sjInfo && sjInfo.id) {
|
||||
return sjInfo.id;
|
||||
}
|
||||
|
||||
const storageSjId = uni.getStorageSync("sjId");
|
||||
if (storageSjId) {
|
||||
return storageSjId;
|
||||
}
|
||||
|
||||
const res = await request.post("/sj/user/getUser");
|
||||
if (res && res.data && res.data.id) {
|
||||
if (this.$store && this.$store.commit) {
|
||||
this.$store.commit("setSjInfo", res.data);
|
||||
}
|
||||
uni.setStorageSync("sjId", res.data.id);
|
||||
return res.data.id;
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
async addService() {
|
||||
try {
|
||||
const sjId = await this.getCurrentSjId();
|
||||
if (!sjId) {
|
||||
uni.showToast({
|
||||
title: "未获取到商家信息",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await request.post("/sj/firstclass", { id: sjId });
|
||||
addService() {
|
||||
const userId = uni.getStorageSync('userId') || '';
|
||||
request.post("/sj/firstclass", { id: userId }).then((res) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
this.firstClassList = res.data;
|
||||
this.selectedFirstIndex = 0;
|
||||
|
|
@ -327,13 +291,7 @@ export default {
|
|||
icon: "none",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取商家服务分类失败:", error);
|
||||
uni.showToast({
|
||||
title: "获取分类失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
loadSecondClass(firstId) {
|
||||
request.post("/user/secondclass", {
|
||||
|
|
@ -1021,4 +979,4 @@ export default {
|
|||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
<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/6948baf3-aad9-4d87-9483-9db0e462a3f7.png"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/66325904-4603-48fd-b03b-90c684af96e9"
|
||||
mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
<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/6948baf3-aad9-4d87-9483-9db0e462a3f7.png"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/66325904-4603-48fd-b03b-90c684af96e9"
|
||||
mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
|
|
@ -721,7 +721,7 @@ export default {
|
|||
.title-bar {
|
||||
width: 6rpx;
|
||||
height: 30rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
margin-right: 10rpx;
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
|
|
@ -790,8 +790,8 @@ export default {
|
|||
}
|
||||
|
||||
.checkbox.checked {
|
||||
background-color: #FF4767;
|
||||
border-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-color: #E8101E;
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
|
|
@ -827,12 +827,12 @@ export default {
|
|||
|
||||
.change-info-btn {
|
||||
margin-top: 20rpx;
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
.view-change-btn {
|
||||
margin-top: 20rpx;
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
/* 双按钮行样式 */
|
||||
|
|
@ -853,7 +853,7 @@ export default {
|
|||
}
|
||||
|
||||
.submit-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #F52540 0%, #E8101E 100%, #E8101E 100%);
|
||||
border-radius: 43rpx;
|
||||
padding: 0 15rpx;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ export default {
|
|||
.title-bar {
|
||||
width: 6rpx;
|
||||
height: 30rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
margin-right: 10rpx;
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
|
|
@ -410,7 +410,7 @@ export default {
|
|||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 40rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -476,7 +476,7 @@ export default {
|
|||
|
||||
.confirm-text {
|
||||
font-size: 32rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -526,7 +526,7 @@ export default {
|
|||
}
|
||||
|
||||
.time-block.active .time-value-picker {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.time-separator {
|
||||
|
|
@ -572,7 +572,7 @@ export default {
|
|||
border: none;
|
||||
width: 290rpx;
|
||||
height: 86rpx;
|
||||
background: linear-gradient( 180deg, #F52540 0%, #FF4767 100%, #FF4767 100%);
|
||||
background: linear-gradient( 180deg, #F52540 0%, #E8101E 100%, #E8101E 100%);
|
||||
border-radius: 43rpx;
|
||||
}
|
||||
|
||||
|
|
@ -592,7 +592,7 @@ export default {
|
|||
}
|
||||
|
||||
.btn-confirm-large {
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -100,13 +100,13 @@
|
|||
<view class="radio-group">
|
||||
<view class="radio-item" @click="editable && setIdCardValidType(1)">
|
||||
<view class="radio" :class="{ checked: displayData.idcard_expiry_type === 1 }">
|
||||
<image v-if="displayData.idcard_expiry_type === 1" src="/static/images/agree_y.png" class="radio-icon-image" mode="aspectFit"></image>
|
||||
<image v-if="displayData.idcard_expiry_type === 1" src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/cb185ec8-9d30-4e53-b5dc-14b546013a60" class="radio-icon-image" mode="aspectFit"></image>
|
||||
</view>
|
||||
<text class="radio-label">长久有效</text>
|
||||
</view>
|
||||
<view class="radio-item" @click="editable && setIdCardValidType(2)">
|
||||
<view class="radio" :class="{ checked: displayData.idcard_expiry_type === 2 }">
|
||||
<image v-if="displayData.idcard_expiry_type === 2" src="/static/images/agree_y.png" class="radio-icon-image" mode="aspectFit"></image>
|
||||
<image v-if="displayData.idcard_expiry_type === 2" src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/cb185ec8-9d30-4e53-b5dc-14b546013a60" class="radio-icon-image" mode="aspectFit"></image>
|
||||
</view>
|
||||
<text class="radio-label">指定日期有效</text>
|
||||
</view>
|
||||
|
|
@ -1813,7 +1813,7 @@ export default {
|
|||
}
|
||||
|
||||
.change-info-btn, .view-change-btn, .resubmit-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
/* 双按钮行样式 */
|
||||
|
|
@ -1834,7 +1834,7 @@ export default {
|
|||
}
|
||||
|
||||
.submit-btn {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #F52540 0%, #E8101E 100%, #E8101E 100%);
|
||||
border-radius: 43rpx;
|
||||
padding: 0 15rpx;
|
||||
}
|
||||
|
|
@ -1866,7 +1866,7 @@ export default {
|
|||
.title-bar {
|
||||
width: 6rpx;
|
||||
height: 30rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
margin-right: 7rpx;
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
|
|
@ -2029,7 +2029,7 @@ export default {
|
|||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #fff;
|
||||
border-top: 4rpx solid #FF4767;
|
||||
border-top: 4rpx solid #E8101E;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 16rpx;
|
||||
|
|
@ -2115,8 +2115,8 @@ export default {
|
|||
}
|
||||
|
||||
.radio.checked {
|
||||
background-color: #FF4767;
|
||||
border-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-color: #E8101E;
|
||||
}
|
||||
|
||||
.radio-icon-image {
|
||||
|
|
@ -2291,7 +2291,7 @@ export default {
|
|||
|
||||
.confirm-text {
|
||||
font-size: 32rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -2321,7 +2321,7 @@ export default {
|
|||
}
|
||||
|
||||
.popup-btn.confirm {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
}
|
||||
|
||||
.popup-btn .btn-text {
|
||||
|
|
@ -2431,13 +2431,13 @@ export default {
|
|||
}
|
||||
|
||||
.tip-btn.cancel {
|
||||
border: #FF4767 2rpx solid;
|
||||
border: #E8101E 2rpx solid;
|
||||
background-color: transparent;
|
||||
color: #FF4767;
|
||||
color: #e8101e;
|
||||
}
|
||||
|
||||
.tip-btn.confirm {
|
||||
background: linear-gradient(180deg, #ff8e9d 0%, #FF4767 100%);
|
||||
background: linear-gradient(180deg, #f52540 0%, #e8101e 100%);
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ export default {
|
|||
|
||||
.add-icon {
|
||||
font-size: 32rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
|
|
@ -367,7 +367,7 @@ export default {
|
|||
}
|
||||
|
||||
.confirm-btn {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
|||
|
|
@ -934,7 +934,7 @@
|
|||
.get-code-btn {
|
||||
font-weight: 400;
|
||||
font-size: 30rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 42rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
|
|
@ -959,7 +959,7 @@
|
|||
.input-error {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #e8101e;
|
||||
margin-left: 30rpx;
|
||||
margin-top: -20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ import request from '../../utils/request';
|
|||
.state {
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
.state-text {
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export default {
|
|||
color: #91908F;
|
||||
}
|
||||
.btn-box {
|
||||
background: linear-gradient( 180deg, #F52540 0%, #FF4767 100%);
|
||||
background: linear-gradient( 180deg, #F52540 0%, #E8101E 100%);
|
||||
height: 88rpx;
|
||||
border-radius: 43rpx;
|
||||
font-weight: 500;
|
||||
|
|
|
|||
|
|
@ -285,14 +285,13 @@ export default {
|
|||
sourceType: ['album', 'camera'],
|
||||
compressed: false
|
||||
})
|
||||
let selectedFile;
|
||||
// #ifdef H5
|
||||
selectedFile = res.tempFile;
|
||||
// #endif
|
||||
// #ifdef APP-PLUS || MP-WEIXIN
|
||||
selectedFile = res;
|
||||
// #endif
|
||||
await this.uploadFile(selectedFile)
|
||||
// #ifdef H5
|
||||
const file = res.tempFile;
|
||||
// #endif
|
||||
// #ifdef APP-PLUS || MP-WEIXIN
|
||||
const file = res;
|
||||
// #endif
|
||||
await this.uploadFile(file)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('上传出错:', error)
|
||||
|
|
@ -370,9 +369,8 @@ export default {
|
|||
// 上传到OSS
|
||||
uploadToOss(file, ossConfig, name) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let formData;
|
||||
// #ifdef H5
|
||||
formData = new FormData()
|
||||
// #ifdef H5
|
||||
const formData = new FormData()
|
||||
formData.append('name',name);
|
||||
formData.append('policy', ossConfig.policy);
|
||||
formData.append('OSSAccessKeyId', ossConfig.ossAccessKeyId);
|
||||
|
|
@ -388,15 +386,15 @@ export default {
|
|||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS || MP-WEIXIN
|
||||
formData = {};
|
||||
formData.name = name;
|
||||
formData.policy = ossConfig.policy;
|
||||
formData.OSSAccessKeyId = ossConfig.ossAccessKeyId;
|
||||
formData.success_action_status = '200';
|
||||
formData.signature = ossConfig.signature;
|
||||
formData.key = ossConfig.dir + name;
|
||||
formData.file = file;
|
||||
// #ifdef APP-PLUS || MP-WEIXIN
|
||||
let formData = {};
|
||||
formData.name = name;
|
||||
formData.policy = ossConfig.policy;
|
||||
formData.OSSAccessKeyId = ossConfig.ossAccessKeyId;
|
||||
formData.success_action_status = '200';
|
||||
formData.signature = ossConfig.signature;
|
||||
formData.key = ossConfig.dir + name;
|
||||
formData.file = file;
|
||||
let path;
|
||||
if(this.accept == 'image/*') {
|
||||
path = file.path
|
||||
|
|
@ -542,4 +540,4 @@ export default {
|
|||
font-size: 32rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -226,7 +226,7 @@
|
|||
.score {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 37rpx;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@
|
|||
.score {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 37rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@
|
|||
.score {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 37rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@
|
|||
}
|
||||
|
||||
.active {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,239 +0,0 @@
|
|||
<template>
|
||||
<view class="brand-card-comp" @click="onClick">
|
||||
<image class="brand-bg" :src="item.bgSrc" mode="aspectFill"></image>
|
||||
<image class="mask-bg"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/9bca353c-fa74-407e-a69e-6f5e9aa43955.png"
|
||||
mode="widthFix"></image>
|
||||
|
||||
<view class="card-content">
|
||||
<view class="avatar-wrapper" style="border-color: #F7E5D7;">
|
||||
<image class="avatar-img" :src="item.avatar || 'https://dummyimage.com/100x100/ccc/fff.png&text=logo'">
|
||||
</image>
|
||||
</view>
|
||||
|
||||
<text class="brand-name">{{ item.name }}</text>
|
||||
|
||||
<view class="tags-container">
|
||||
<view class="tag-item" v-for="(tag, idx) in displayTags" :key="idx" :style="getTagStyle(tag)">
|
||||
<!-- <image class="tag-icon" v-if="tag.icon" :src="tag.icon"></image> -->
|
||||
<text class="tag-text">{{ tag.text }} </text>
|
||||
<text class="tag-text1">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 预定义的标签库(固定内容)
|
||||
const TAG_LIBRARY = {
|
||||
franchise: { // 品牌加盟
|
||||
text: '品牌加盟',
|
||||
color: '#8D4C1B ',
|
||||
borderColor: '#D6CAC0 ',
|
||||
icon: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/60816ae2-92ee-4473-9eca-562e1200dbca.png'
|
||||
},
|
||||
recruit: { // 学员招募
|
||||
text: '学员招募',
|
||||
color: '#E5505F',
|
||||
borderColor: '#EFCFD2 ',
|
||||
icon: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/fd0699b9-9f3c-4b1e-8693-d0c9ec7eabc3.png'
|
||||
},
|
||||
more: { // 更多详情
|
||||
text: '更多详情',
|
||||
color: '#333333',
|
||||
borderColor: '#ECECEC',
|
||||
icon: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/cec453ce-f3fc-4881-8f2c-9ec5c61e759c.png'
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'brand-card',
|
||||
props: {
|
||||
// 基础信息
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
// 新方式:传入标签 key 数组,例如 ['franchise', 'recruit']
|
||||
tagKeys: {
|
||||
type: Array,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 最终要显示的标签列表(优先使用 tagKeys,否则兼容旧数据 item.tags)
|
||||
displayTags() {
|
||||
if (this.tagKeys && this.tagKeys.length) {
|
||||
return this.tagKeys.map(key => TAG_LIBRARY[key]).filter(v => v)
|
||||
}
|
||||
// 兼容旧数据:如果 item.tags 存在且为数组,则直接使用(但建议逐步迁移)
|
||||
if (this.item.tags && Array.isArray(this.item.tags)) {
|
||||
return this.item.tags
|
||||
}
|
||||
return []
|
||||
},
|
||||
tagsLength() {
|
||||
return this.displayTags.length
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 点击品牌卡片跳转详情页
|
||||
onClick() {
|
||||
// 1. 保留 emit,方便外层如果有特殊需求可以监听到
|
||||
this.$emit('click', this.item);
|
||||
|
||||
// 2. 检查登录状态
|
||||
if (!uni.getStorageSync("accessToken")) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/blogPopup/blogPopup'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 直接在此处处理跳转逻辑
|
||||
if (this.item && this.item.id) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/jingxuan/brand-detail?id=${this.item.id}`
|
||||
});
|
||||
}
|
||||
},
|
||||
getTagStyle(tag) {
|
||||
const len = this.tagsLength
|
||||
let sizeStyle = {}
|
||||
if (len === 1) {
|
||||
sizeStyle = {
|
||||
width: '288rpx',
|
||||
height: '42rpx',
|
||||
padding: '0 12rpx',
|
||||
boxSizing: 'border-box'
|
||||
}
|
||||
} else if (len === 2) {
|
||||
sizeStyle = {
|
||||
width: '142rpx',
|
||||
height: '42rpx',
|
||||
padding: '0 12rpx',
|
||||
boxSizing: 'border-box'
|
||||
}
|
||||
}
|
||||
return {
|
||||
...sizeStyle,
|
||||
color: tag.color,
|
||||
borderColor: tag.borderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.brand-card-comp {
|
||||
width: 328rpx;
|
||||
height: 339rpx;
|
||||
position: relative;
|
||||
border-radius: 21rpx;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.brand-bg {
|
||||
width: 100%;
|
||||
height: 184rpx;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.mask-bg {
|
||||
width: 100%;
|
||||
height: 251rpx;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
margin-top: -38rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
line-height: 34rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.tags-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tag-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 21rpx;
|
||||
border: 1rpx solid;
|
||||
background-color: transparent;
|
||||
padding: 7rpx 12rpx;
|
||||
}
|
||||
|
||||
.tag-icon {
|
||||
width: 26rpx;
|
||||
height: 24rpx;
|
||||
margin-right: 6rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tag-text {
|
||||
font-size: 24rpx;
|
||||
line-height: 28rpx;
|
||||
white-space: nowrap;
|
||||
margin-top: 4rpx;
|
||||
padding-right: 2rpx;
|
||||
}
|
||||
|
||||
.tag-text1 {
|
||||
font-size: 40rpx;
|
||||
line-height: 28rpx;
|
||||
white-space: nowrap;
|
||||
margin-top: 4rpx;
|
||||
padding-right: 2rpx;
|
||||
margin-bottom: 6rpx;
|
||||
font-weight: 200;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -156,7 +156,6 @@
|
|||
weChatRefund: "/sj/workSeatOrder/weChatRefund",
|
||||
aliRefund: "/sj/workSeatOrder/aliRefund",
|
||||
startOrder: "/sj/workSeatOrder/start",
|
||||
sureOrder:"/sj/workSeatOrder/sure",
|
||||
endOrder: "/sj/workSeatOrder/end",
|
||||
ordernum: "/sj/workSeatOrder/orderNum",
|
||||
list: "/sj/workSeatOrder/list",
|
||||
|
|
@ -210,7 +209,7 @@
|
|||
secondTabs() {
|
||||
if (this.activeFirstId == 1 || this.activeFirstId == 2) {
|
||||
return [{
|
||||
title: `待开始(${this.numInfo.noservernum})`,
|
||||
title: `待服务(${this.numInfo.noservernum})`,
|
||||
id: 3
|
||||
},
|
||||
{
|
||||
|
|
@ -406,7 +405,6 @@
|
|||
return;
|
||||
}
|
||||
this.clickType = true;
|
||||
console.log(111,this.activeFirstId,this.urls)
|
||||
request
|
||||
.post(this.urls[this.activeFirstId].sureOrder, {
|
||||
id: order.id,
|
||||
|
|
@ -416,7 +414,7 @@
|
|||
.then((res) => {
|
||||
if (res.state != 1 || res.code != 200) {
|
||||
uni.showToast({
|
||||
title: "开始服务",
|
||||
title: res.msg,
|
||||
icon: "none",
|
||||
});
|
||||
} else {
|
||||
|
|
@ -461,7 +459,7 @@
|
|||
console.log(res);
|
||||
if (res.state == 1 || res.code == 200) {
|
||||
uni.showToast({
|
||||
title: "开始服务",
|
||||
title: res.msg,
|
||||
icon: "none",
|
||||
});
|
||||
this.searchList();
|
||||
|
|
@ -515,27 +513,27 @@
|
|||
if (this.idType == 1) {
|
||||
if (this.activeFirstId == 1) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/shop/userorder-detail?order_id=${order.id}&order_kind=${order.order_kind}&haveButton=${this.haveButton}`,
|
||||
url: `/pages/shop/userorder-detail?order_id=${order.id}&order_kind=${order.order_kind}`,
|
||||
});
|
||||
}
|
||||
if (this.activeFirstId == 2) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/shop/userorder-detail?order_id=${order.id}&serviceType=2&haveButton=${this.haveButton}`,
|
||||
url: `/pages/shop/userorder-detail?order_id=${order.id}&serviceType=2`,
|
||||
});
|
||||
}
|
||||
if (this.activeFirstId == 3) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/shop/SellerDetail?order_id=${order.id}&haveButton=${this.haveButton}`,
|
||||
url: `/pages/shop/SellerDetail?order_id=${order.id}`,
|
||||
});
|
||||
}
|
||||
if (this.activeFirstId == 4) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/shop/userorder-detail?order_id=${order.id}&order_kind=${order.order_kind}&haveButton=${this.haveButton}`,
|
||||
url: `/pages/shop/userorder-detail?order_id=${order.id}&order_kind=${order.order_kind}`,
|
||||
});
|
||||
}
|
||||
if (this.activeFirstId == 5) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/shop/userorder-detail?order_id=${order.id}&order_kind=${order.order_kind}&serviceType=2&haveButton=${this.haveButton}`,
|
||||
url: `/pages/shop/userorder-detail?order_id=${order.id}&order_kind=${order.order_kind}&serviceType=2`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -578,7 +576,7 @@
|
|||
|
||||
// 选中状态样式
|
||||
&.active {
|
||||
color: #FF4767; // 选中文字颜色
|
||||
color: #e8101e; // 选中文字颜色
|
||||
font-weight: 600; // 选中时加粗(可选,根据图片效果)
|
||||
|
||||
// 横条效果:通过伪元素实现
|
||||
|
|
@ -592,8 +590,8 @@
|
|||
bottom: -6rpx; // 距离文字底部的距离(可调整)
|
||||
height: 6rpx; // 横条高度
|
||||
background: linear-gradient(306deg,
|
||||
#FF4767 0%,
|
||||
#FF4767 100%); // 横条颜色(与文字颜色一致)
|
||||
#e8101e 0%,
|
||||
#e8101e 100%); // 横条颜色(与文字颜色一致)
|
||||
border-radius: 3rpx; // 横条圆角(可选,更柔和)
|
||||
}
|
||||
}
|
||||
|
|
@ -628,7 +626,7 @@
|
|||
|
||||
// 选中状态样式
|
||||
&.active {
|
||||
color: #FF4767; // 选中颜色
|
||||
color: #e8101e; // 选中颜色
|
||||
background: rgba(252, 67, 124, 0.1); // 可选:选中时背景色变化
|
||||
font-weight: 600; // 可选:选中时加粗
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,101 +0,0 @@
|
|||
<template>
|
||||
<view class="notice-item" @tap="handleClick">
|
||||
<view class="item-main">
|
||||
<text class="item-title line-2">{{ item.title }}</text>
|
||||
<view class="item-time">
|
||||
<text class="time-text">发布时间:{{ formattedTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "NoticeCard",
|
||||
props: {
|
||||
// 接收外部传入的公告对象数据
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 利用计算属性自动处理时间格式化
|
||||
formattedTime() {
|
||||
const timeStr = this.item.create_time;
|
||||
if (!timeStr) return '--:--:--';
|
||||
|
||||
let formatted = timeStr;
|
||||
if (timeStr.includes('.') && !timeStr.includes('-')) {
|
||||
formatted = timeStr.replace(/\./g, '-');
|
||||
if (formatted.match(/\d{4}-\d{2}-\d{2}\d{2}:\d{2}:\d{2}/)) {
|
||||
formatted = formatted.replace(/(\d{4}-\d{2}-\d{2})(\d{2}:\d{2}:\d{2})/, '$1 $2');
|
||||
}
|
||||
}
|
||||
if (formatted.includes('-') && formatted.includes(':')) {
|
||||
return formatted;
|
||||
}
|
||||
return timeStr;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
// 触发组件的 click 事件,把当前项的数据抛出去
|
||||
this.$emit('click', this.item);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notice-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
.item-main {
|
||||
flex: 1;
|
||||
min-width: 0; // 防止文字溢出
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #101010;
|
||||
line-height: 42rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-time {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.time-icon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.time-text {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
line-height: 30rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 多行省略
|
||||
.line-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -171,7 +171,6 @@
|
|||
},
|
||||
emitStart() {
|
||||
this.$emit("start");
|
||||
|
||||
},
|
||||
emitDone() {
|
||||
this.$emit("done");
|
||||
|
|
@ -182,8 +181,8 @@
|
|||
|
||||
<style scoped lang="less">
|
||||
.order-card {
|
||||
padding: 24rpx 20rpx 24rpx 20rpx;
|
||||
margin: 0;
|
||||
padding: 20rpx 30rpx 20rpx 30rpx;
|
||||
margin: 0rpx 30rpx 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
/* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */
|
||||
|
|
@ -206,7 +205,7 @@
|
|||
.stateText {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
position: absolute;
|
||||
|
|
@ -256,7 +255,7 @@
|
|||
.service-price {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 34rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -293,7 +292,7 @@
|
|||
letter-spacing: 2px;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
background: linear-gradient(166deg, #FC5E72 0%, #FF4767 100%);
|
||||
background: linear-gradient(166deg, #FC5E72 0%, #E8101E 100%);
|
||||
border-radius: 6rpx;
|
||||
padding: 4rpx 4rpx 4rpx 8rpx;
|
||||
margin-right: 13rpx;
|
||||
|
|
@ -389,8 +388,8 @@
|
|||
|
||||
/* 接单按钮 */
|
||||
.accept-btn {
|
||||
border: 2rpx solid #FF4767;
|
||||
color: #FF4767;
|
||||
border: 2rpx solid #E8101E;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.order-address {
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@
|
|||
|
||||
.tab-text {
|
||||
font-weight: 500;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
&::after{
|
||||
content: '';
|
||||
// 绝对定位在元素底部
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
transform: translateX(-50%);
|
||||
bottom: -6rpx; // 距离文字底部的距离(可调整)
|
||||
height: 6rpx; // 横条高度
|
||||
background: linear-gradient( 306deg, #FF4767 0%, #F25988 100%); // 横条颜色(与文字颜色一致)
|
||||
background: linear-gradient( 306deg, #E8101E 0%, #F25988 100%); // 横条颜色(与文字颜色一致)
|
||||
border-radius: 3rpx; // 横条圆角(可选,更柔和)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,196 +0,0 @@
|
|||
<template>
|
||||
<view class="skill-item" @click="handleClick">
|
||||
<view class="cover-box">
|
||||
<image class="cover" :src="item.coverSrc" mode="aspectFill"></image>
|
||||
<image v-if="item.video" class="play-icon"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/5c1ddfef-a200-424a-a9dc-03d9395568f6.png"></image>
|
||||
</view>
|
||||
<view class="skill-info">
|
||||
<view class="skill-title line-2">{{ item.title }}</view>
|
||||
<view class="skill-type" :class="typeClass">
|
||||
<image class="type-icon" :src="item.typeIcon || defaultTypeIcon"></image>
|
||||
<text class="type-text">{{ item.type || '平台课程' }}</text>
|
||||
</view>
|
||||
<view class="skill-stats">
|
||||
<image class="view-icon"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/2409b64a-56bb-4d9e-a4cc-5b3444fcf097.png">
|
||||
</image>
|
||||
{{ formatViews(item.views) }}观看 · {{ item.time }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SkillItem',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({
|
||||
id: null,
|
||||
title: '',
|
||||
coverSrc: '',
|
||||
type: '平台课程',
|
||||
views: 0,
|
||||
time: '',
|
||||
typeIcon: ''
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultTypeIcon: 'https://dummyimage.com/30x30/ccc/fff.png&text=I' // 用于占位
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
typeClass() {
|
||||
const typeMap = {
|
||||
'平台课程': 'platform-course',
|
||||
'脸缘品牌': 'brand-course',
|
||||
'品牌课程': 'brand-course'
|
||||
}
|
||||
return typeMap[this.item.type] || 'platform-course'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatViews(views) {
|
||||
if (!views) return '0'
|
||||
if (views >= 10000) {
|
||||
return (views / 10000).toFixed(1) + 'w'
|
||||
}
|
||||
return views.toString()
|
||||
},
|
||||
handleClick() {
|
||||
// 1. 保留 emit,方便外层如果有特殊需求可以监听到
|
||||
this.$emit('click', this.item);
|
||||
|
||||
// 2. 检查登录状态
|
||||
if (!uni.getStorageSync("accessToken")) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/blogPopup/blogPopup'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 直接在此处处理跳转逻辑
|
||||
if (this.item && this.item.id) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/jingxuan/skill-detail?id=${this.item.id}`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.skill-item {
|
||||
display: flex;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.cover-box {
|
||||
position: relative;
|
||||
width: 224rpx;
|
||||
height: 126rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 24rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
.cover {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.play-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 39rpx;
|
||||
height: 39rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.skill-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.skill-title {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.skill-type {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 22rpx;
|
||||
margin-top: 10rpx;
|
||||
|
||||
.type-icon {
|
||||
border: 1rpx solid #D6CAC0;
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
margin-right: 8rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.type-text {
|
||||
border-radius: 7rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
line-height: 33rpx;
|
||||
padding: 2rpx 10rpx;
|
||||
}
|
||||
|
||||
&.platform-course .type-text {
|
||||
background: #f9d3d760;
|
||||
color: #E55463;
|
||||
}
|
||||
|
||||
&.brand-course .type-text {
|
||||
background: #f9d3d760;
|
||||
color: #E55463;
|
||||
}
|
||||
}
|
||||
|
||||
.skill-stats {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.view-icon {
|
||||
width: 26rpx;
|
||||
height: 22rpx;
|
||||
margin-right: 8rpx;
|
||||
margin-top: -2rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<view class="stateText" :class="{
|
||||
stateText2: dataItem.state > 4 && dataItem.state !== 7, // 排除已取消
|
||||
stateText3: dataItem.state === 7 // 已取消状态单独处理
|
||||
}" v-if="showState">
|
||||
}" v-if="showState">
|
||||
{{ stateText }}
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -18,8 +18,8 @@
|
|||
<view class="topInfo">
|
||||
<view class="price_title">
|
||||
<view class="service-type white-space-nowrap">{{
|
||||
dataItem.title
|
||||
}}</view>
|
||||
dataItem.title
|
||||
}}</view>
|
||||
|
||||
</view>
|
||||
<view class="service-address">下单时间:{{ dataItem.add_time }}</view>
|
||||
|
|
@ -45,260 +45,299 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "OrderCard",
|
||||
props: {
|
||||
dataItem: {
|
||||
type: Object,
|
||||
export default {
|
||||
name: "OrderCard",
|
||||
props: {
|
||||
dataItem: {
|
||||
type: Object,
|
||||
},
|
||||
typeId: {
|
||||
type: Number,
|
||||
},
|
||||
showState: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
}
|
||||
},
|
||||
typeId: {
|
||||
type: Number,
|
||||
computed: {
|
||||
photo() {
|
||||
return this.dataItem.photo? JSON.parse(this.dataItem.photo):"";
|
||||
},
|
||||
useTime() {
|
||||
const start = this.dataItem.reserve_start_time;
|
||||
const endTime = this.dataItem.reserve_end_time;
|
||||
|
||||
function formatTimeRange(startTimeStr, endTimeStr) {
|
||||
if (!startTimeStr || !endTimeStr) return "未设置";
|
||||
|
||||
// 解析开始时间为Date对象
|
||||
const startTime = new Date(startTimeStr.replace(/-/g, '/'));
|
||||
const endTime = new Date(endTimeStr.replace(/-/g, '/'));
|
||||
|
||||
if (isNaN(startTime.getTime()) || isNaN(endTime.getTime())) {
|
||||
console.error("无效的时间格式");
|
||||
return "时间格式错误";
|
||||
}
|
||||
|
||||
// 格式化年份:YYYY年
|
||||
const formatYear = (date) => {
|
||||
return date.getFullYear() + '年';
|
||||
};
|
||||
|
||||
// 格式化月份和日期:MM月DD
|
||||
const formatMonthDay = (date) => {
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
return `${month}月${day}`;
|
||||
};
|
||||
|
||||
// 格式化时间部分:HH:MM
|
||||
const formatTimePart = (date) => {
|
||||
const hours = String(date.getHours()).padStart(2, "0");
|
||||
const minutes = String(date.getMinutes()).padStart(2, "0");
|
||||
return `${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
// 判断是否同一天
|
||||
const isSameDay = startTime.getFullYear() === endTime.getFullYear() &&
|
||||
startTime.getMonth() === endTime.getMonth() &&
|
||||
startTime.getDate() === endTime.getDate();
|
||||
|
||||
if (isSameDay) {
|
||||
// 同一天:2025年05月29 12:30-13:30
|
||||
return `${formatYear(startTime)}${formatMonthDay(startTime)} ${formatTimePart(startTime)}-${formatTimePart(endTime)}`;
|
||||
} else {
|
||||
// 跨天:2025年05月29 12:30-2025年05月30 13:30
|
||||
return `${formatYear(startTime)}${formatMonthDay(startTime)} ${formatTimePart(startTime)}-${formatYear(endTime)}${formatMonthDay(endTime)} ${formatTimePart(endTime)}`;
|
||||
}
|
||||
}
|
||||
return formatTimeRange(start, endTime);
|
||||
},
|
||||
stateText() {
|
||||
const textList = [
|
||||
"",
|
||||
"待支付",
|
||||
"待接单",
|
||||
"待开始",
|
||||
"进行中",
|
||||
"已完成",
|
||||
"已评价",
|
||||
"已取消",
|
||||
];
|
||||
return textList[this.dataItem.state];
|
||||
},
|
||||
},
|
||||
showState: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
photo() {
|
||||
return this.dataItem.photo ? JSON.parse(this.dataItem.photo) : "";
|
||||
methods: {
|
||||
// 触发取消事件
|
||||
emitCancel() {
|
||||
this.$emit("cancel", this.dataItem);
|
||||
},
|
||||
// 触发接单事件
|
||||
emitAccept() {
|
||||
this.$emit("accept", this.dataItem);
|
||||
},
|
||||
emitStart() {
|
||||
this.$emit("start", this.dataItem);
|
||||
},
|
||||
emitDone() {
|
||||
this.$emit("done", this.dataItem);
|
||||
},
|
||||
goDetail() {
|
||||
this.$emit("goDetail", this.dataItem);
|
||||
},
|
||||
emitGoPay() {
|
||||
this.$emit("goPay", this.dataItem);
|
||||
},
|
||||
emitRefund() {
|
||||
this.$emit("goRefund", this.dataItem);
|
||||
}
|
||||
},
|
||||
useTime() {
|
||||
const start = this.dataItem.reserve_start_time;
|
||||
const end = this.dataItem.reserve_end_time;
|
||||
if (!start || !end) return "未设置";
|
||||
const startDate = new Date(start.replace(/-/g, '/'));
|
||||
const endDate = new Date(end.replace(/-/g, '/'));
|
||||
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) return "时间格式错误";
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
const fmt = (d) => `${pad(d.getMonth() + 1)}.${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
return `${fmt(startDate)}-${fmt(endDate)}`;
|
||||
},
|
||||
stateText() {
|
||||
const textList = [
|
||||
"",
|
||||
"待支付",
|
||||
"待接单",
|
||||
"待开始",
|
||||
"进行中",
|
||||
"已完成",
|
||||
"已评价",
|
||||
"已取消",
|
||||
];
|
||||
return textList[this.dataItem.state];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 触发取消事件
|
||||
emitCancel() {
|
||||
this.$emit("cancel", this.dataItem);
|
||||
},
|
||||
// 触发接单事件
|
||||
emitAccept() {
|
||||
this.$emit("accept", this.dataItem);
|
||||
},
|
||||
emitStart() {
|
||||
this.$emit("start", this.dataItem);
|
||||
},
|
||||
emitDone() {
|
||||
this.$emit("done", this.dataItem);
|
||||
},
|
||||
goDetail() {
|
||||
this.$emit("goDetail", this.dataItem);
|
||||
},
|
||||
emitGoPay() {
|
||||
this.$emit("goPay", this.dataItem);
|
||||
},
|
||||
emitRefund() {
|
||||
this.$emit("goRefund", this.dataItem);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.order-card {
|
||||
position: relative; // 必须加,确保父容器有定位
|
||||
padding: 24rpx 20rpx 0rpx;
|
||||
margin: 0rpx 30rpx 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
/* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */
|
||||
}
|
||||
.order-card {
|
||||
position: relative; // 必须加,确保父容器有定位
|
||||
padding: 24rpx 20rpx 0rpx;
|
||||
margin: 0rpx 30rpx 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
/* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */
|
||||
}
|
||||
|
||||
.orderNumBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.stateText {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #FF4767;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background-image: url("/static/images/icons/tabBj.png");
|
||||
background-size: 100% auto;
|
||||
background-position: center top;
|
||||
background-repeat: no-repeat;
|
||||
width: 128rpx;
|
||||
height: 49rpx;
|
||||
.orderNumBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
justify-content: space-between;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.stateText2 {
|
||||
background-image: url("/static/images/icons/tabBj2.png");
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.stateText3 {
|
||||
background-image: url("/static/images/icons/tabBj2.png");
|
||||
color: #999999 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 订单编号 */
|
||||
.order-id {
|
||||
width: 530rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/* 服务信息容器 */
|
||||
.service-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 24rpx;
|
||||
border-bottom: 1px solid #f6f5f5;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 服务图片 */
|
||||
.service-img {
|
||||
width: 172rpx;
|
||||
height: 168rpx;
|
||||
border-radius: 24rpx;
|
||||
margin-right: 30rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 服务信息 */
|
||||
.service-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 168rpx;
|
||||
|
||||
.topInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.price_title {
|
||||
.stateText {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #E8101E;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background-image: url("/static/images/icons/tabBj.png");
|
||||
background-size: 100% auto;
|
||||
background-position: center top;
|
||||
background-repeat: no-repeat;
|
||||
width: 128rpx;
|
||||
height: 49rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.stateText2 {
|
||||
background-image: url("/static/images/icons/tabBj2.png");
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.stateText3 {
|
||||
background-image: url("/static/images/icons/tabBj2.png");
|
||||
color: #999999 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 订单编号 */
|
||||
.order-id {
|
||||
width: 530rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/* 服务信息容器 */
|
||||
.service-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 24rpx;
|
||||
border-bottom: 1px solid #f6f5f5;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 服务图片 */
|
||||
.service-img {
|
||||
width: 172rpx;
|
||||
height: 168rpx;
|
||||
border-radius: 24rpx;
|
||||
margin-right: 30rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 服务信息 */
|
||||
.service-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 168rpx;
|
||||
|
||||
.topInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.price_title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.service-type {
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
line-height: 34rpx;
|
||||
max-width: 300rpx;
|
||||
}
|
||||
|
||||
|
||||
.service-type {
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
line-height: 34rpx;
|
||||
max-width: 300rpx;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.service-price {
|
||||
font-family: DINPro, DINPro;
|
||||
font-weight: 500;
|
||||
font-size: 36rpx;
|
||||
color: #E8101E;
|
||||
line-height: 34rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.service-price {
|
||||
font-family: DINPro, DINPro;
|
||||
font-weight: 500;
|
||||
font-size: 36rpx;
|
||||
color: #FF4767;
|
||||
line-height: 34rpx;
|
||||
.service_subTitle {
|
||||
font-size: 26rpx;
|
||||
line-height: 26rpx;
|
||||
color: #666666;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.service-address {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.service_subTitle {
|
||||
font-size: 26rpx;
|
||||
line-height: 26rpx;
|
||||
color: #666666;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
/* 时间信息 */
|
||||
.time-info {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
line-height: 34rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
padding-bottom: 20rpx;
|
||||
margin-top: 28rpx;
|
||||
}
|
||||
|
||||
/* 按钮组 */
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 30rpx;
|
||||
padding-bottom: 30rpx;
|
||||
}
|
||||
|
||||
/* 通用按钮样式 */
|
||||
.btn {
|
||||
white-space: nowrap;
|
||||
width: 100rpx;
|
||||
height: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 20px;
|
||||
border-radius: 64rpx;
|
||||
// box-sizing: border-box;
|
||||
//height: 64rpx;
|
||||
//border-radius: 32rpx;
|
||||
border: 2rpx solid #979797;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
line-height: 64rpx;
|
||||
// padding: 0 28rpx;
|
||||
|
||||
.service-address {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
/* 时间信息 */
|
||||
.time-info {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
line-height: 34rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
padding-bottom: 20rpx;
|
||||
margin-top: 28rpx;
|
||||
}
|
||||
/* 取消按钮 */
|
||||
.cancel-btn {
|
||||
border: 2rpx solid #979797;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/* 按钮组 */
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 30rpx;
|
||||
padding-bottom: 30rpx;
|
||||
}
|
||||
|
||||
/* 通用按钮样式 */
|
||||
.btn {
|
||||
white-space: nowrap;
|
||||
width: 100rpx;
|
||||
height: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 20px;
|
||||
border-radius: 64rpx;
|
||||
// box-sizing: border-box;
|
||||
//height: 64rpx;
|
||||
//border-radius: 32rpx;
|
||||
border: 2rpx solid #979797;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
line-height: 64rpx;
|
||||
// padding: 0 28rpx;
|
||||
|
||||
}
|
||||
|
||||
/* 取消按钮 */
|
||||
.cancel-btn {
|
||||
border: 2rpx solid #979797;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/* 接单按钮 */
|
||||
.accept-btn {
|
||||
border: 2rpx solid #FF4767;
|
||||
color: #FF4767;
|
||||
}
|
||||
/* 接单按钮 */
|
||||
.accept-btn {
|
||||
border: 2rpx solid #E8101E;
|
||||
color: #E8101E;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
<template>
|
||||
<view class="growth-package-result-page">
|
||||
<custom-navbar
|
||||
title="支付结果"
|
||||
:showBack="true"
|
||||
backgroundColor="#F7F7F7"
|
||||
borderBottom="none"
|
||||
></custom-navbar>
|
||||
|
||||
<view class="result-main">
|
||||
<view class="result-icon" :class="isFail ? 'is-fail' : 'is-success'">
|
||||
<block v-if="isFail">
|
||||
<view class="fail-line"></view>
|
||||
<view class="fail-dot"></view>
|
||||
</block>
|
||||
<view v-else class="success-check"></view>
|
||||
</view>
|
||||
<view class="result-title">{{ resultInfo.title }}</view>
|
||||
<view class="result-desc">{{ resultInfo.desc }}</view>
|
||||
<view class="primary-btn" @tap="handlePrimaryTap">{{ isFail ? "重新支付" : "返回首页" }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CustomNavbar from "@/components/custom-navbar/custom-navbar.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CustomNavbar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
status: "success",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isFail() {
|
||||
return this.status === "fail";
|
||||
},
|
||||
resultInfo() {
|
||||
if (this.isFail) {
|
||||
return {
|
||||
title: "报名失败",
|
||||
desc: "最后一步出了点问题 请重新支付",
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: "报名成功",
|
||||
desc: "您已完成支付 感谢你对美融融的支持",
|
||||
};
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
this.status = options.status === "fail" ? "fail" : "success";
|
||||
},
|
||||
methods: {
|
||||
handlePrimaryTap() {
|
||||
if (this.isFail) {
|
||||
uni.redirectTo({
|
||||
url: "/pages/home/growth-package",
|
||||
});
|
||||
return;
|
||||
}
|
||||
uni.switchTab({
|
||||
url: "/pages/home/home",
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.growth-package-result-page {
|
||||
min-height: 100vh;
|
||||
background: #ffffff;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.result-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 246rpx 40rpx 0;
|
||||
}
|
||||
|
||||
.result-icon {
|
||||
width: 104rpx;
|
||||
height: 104rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.result-icon.is-success {
|
||||
background: #12c76b;
|
||||
}
|
||||
|
||||
.result-icon.is-fail {
|
||||
background: #ff4652;
|
||||
}
|
||||
|
||||
.success-check {
|
||||
width: 44rpx;
|
||||
height: 24rpx;
|
||||
border-left: 8rpx solid #ffffff;
|
||||
border-bottom: 8rpx solid #ffffff;
|
||||
transform: rotate(-45deg);
|
||||
margin-top: -8rpx;
|
||||
}
|
||||
|
||||
.fail-line {
|
||||
width: 8rpx;
|
||||
height: 46rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.fail-dot {
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
margin-left: -8rpx;
|
||||
margin-top: 58rpx;
|
||||
border-radius: 50%;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.result-title {
|
||||
margin-top: 34rpx;
|
||||
font-weight: 600;
|
||||
font-size: 40rpx;
|
||||
color: #333333;
|
||||
line-height: 56rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.result-desc {
|
||||
margin-top: 8rpx;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #b9b9b9;
|
||||
line-height: 38rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.primary-btn {
|
||||
width: 350rpx;
|
||||
height: 80rpx;
|
||||
margin-top: 144rpx;
|
||||
border: 1rpx solid #ff4b67;
|
||||
border-radius: 40rpx;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 400;
|
||||
font-size: 30rpx;
|
||||
color: #ff4767;
|
||||
line-height: 42rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,348 +0,0 @@
|
|||
<template>
|
||||
<view class="growth-package-page">
|
||||
<image class="content-image" src="@/static/images/home/growth-package/intro.png" mode="widthFix"></image>
|
||||
<view class="deal-carousel">
|
||||
<swiper class="deal-swiper" autoplay circular :interval="3000" previous-margin="40rpx"
|
||||
next-margin="40rpx" :current="dealCurrentIndex" @change="handleDealChange">
|
||||
<swiper-item v-for="(item, index) in dealSlides" :key="item">
|
||||
<view class="deal-slide" :class="getDealSlideClass(index)">
|
||||
<image class="deal-slide-image" :src="item" mode="aspectFit"></image>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="deal-indicator">
|
||||
<view class="indicator-track" v-for="(item, index) in dealSlides" :key="item"
|
||||
:class="{ active: index === dealCurrentIndex }"></view>
|
||||
</view>
|
||||
</view>
|
||||
<image class="content-image" src="@/static/images/home/growth-package/plan.png" mode="widthFix"></image>
|
||||
|
||||
<view class="fixed-action" @tap="handlePayTap">
|
||||
<image class="action-image" :src="actionImage" mode="widthFix"></image>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from "@/utils/request";
|
||||
|
||||
export default {
|
||||
name: "GrowthPackage",
|
||||
data() {
|
||||
return {
|
||||
dealCurrentIndex: 0,
|
||||
isPaying: false,
|
||||
isJoined: false,
|
||||
dealSlides: [
|
||||
"/static/images/home/growth-package/deal-1.png",
|
||||
"/static/images/home/growth-package/deal-2.png",
|
||||
"/static/images/home/growth-package/deal-3.png",
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
actionImage() {
|
||||
return this.isJoined
|
||||
? "/static/images/home/growth-package/action-success.png"
|
||||
: "/static/images/home/growth-package/action.png";
|
||||
},
|
||||
},
|
||||
onShow() {
|
||||
this.getGrowthPackageStatus();
|
||||
},
|
||||
methods: {
|
||||
async getGrowthPackageStatus() {
|
||||
if (!uni.getStorageSync("accessToken")) {
|
||||
this.isJoined = false;
|
||||
return;
|
||||
}
|
||||
if (this.isPaying) return;
|
||||
uni.showLoading({
|
||||
title: "查询报名状态...",
|
||||
mask: true,
|
||||
});
|
||||
try {
|
||||
const res = await request.post(
|
||||
"/sj/growthPackage/status",
|
||||
{},
|
||||
{
|
||||
hideLoading: true,
|
||||
}
|
||||
);
|
||||
this.isJoined = !!(res && res.code === 200 && res.data && Number(res.data.is_joined) === 1);
|
||||
} catch (error) {
|
||||
console.log("growthPackageStatus error", error);
|
||||
} finally {
|
||||
uni.hideLoading();
|
||||
}
|
||||
},
|
||||
handleDealChange(event) {
|
||||
this.dealCurrentIndex = event.detail.current;
|
||||
},
|
||||
getDealSlideClass(index) {
|
||||
const length = this.dealSlides.length;
|
||||
const prevIndex = (this.dealCurrentIndex + length - 1) % length;
|
||||
const nextIndex = (this.dealCurrentIndex + 1) % length;
|
||||
if (index === this.dealCurrentIndex) {
|
||||
return "is-active";
|
||||
}
|
||||
if (index === prevIndex) {
|
||||
return "is-prev";
|
||||
}
|
||||
if (index === nextIndex) {
|
||||
return "is-next";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
handlePayTap() {
|
||||
if (this.isPaying) return;
|
||||
if (this.isJoined) return;
|
||||
if (!uni.getStorageSync("accessToken")) {
|
||||
uni.navigateTo({
|
||||
url: "/pages/blogPopup/blogPopup",
|
||||
});
|
||||
return;
|
||||
}
|
||||
uni.showActionSheet({
|
||||
itemList: ["微信支付", "支付宝支付"],
|
||||
success: (res) => {
|
||||
const payKind = res.tapIndex === 0 ? 2 : 3;
|
||||
this.createGrowthPackagePay(payKind);
|
||||
},
|
||||
});
|
||||
},
|
||||
async createGrowthPackagePay(payKind) {
|
||||
this.isPaying = true;
|
||||
uni.showLoading({
|
||||
title: "支付中...",
|
||||
mask: true,
|
||||
});
|
||||
try {
|
||||
const payRes = await request.post(
|
||||
"/sj/growthPackage/pay",
|
||||
{
|
||||
pay_kind: payKind,
|
||||
},
|
||||
{
|
||||
hideLoading: true,
|
||||
}
|
||||
);
|
||||
if (!payRes || payRes.code !== 200) {
|
||||
uni.hideLoading();
|
||||
this.isPaying = false;
|
||||
if (payRes && payRes.data && (payRes.data.id || payRes.data.number)) {
|
||||
this.goToPayResult("fail", payRes.data);
|
||||
return;
|
||||
}
|
||||
uni.showToast({
|
||||
title: (payRes && payRes.msg) || "支付请求失败",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const orderInfo = payRes.data || {};
|
||||
if (Number(orderInfo.is_joined) === 1) {
|
||||
uni.hideLoading();
|
||||
this.isPaying = false;
|
||||
this.isJoined = true;
|
||||
this.goToPayResult("success", orderInfo.order || {});
|
||||
return;
|
||||
}
|
||||
const paymentParams = orderInfo.pay_params || orderInfo.orderInfo;
|
||||
if (!paymentParams) {
|
||||
uni.hideLoading();
|
||||
this.isPaying = false;
|
||||
if (orderInfo.id || orderInfo.number) {
|
||||
this.goToPayResult("fail", orderInfo);
|
||||
return;
|
||||
}
|
||||
uni.showToast({
|
||||
title: "支付参数缺失",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
uni.hideLoading();
|
||||
this.requestGrowthPackagePayment(payKind, paymentParams, orderInfo);
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: "支付请求失败",
|
||||
icon: "none",
|
||||
});
|
||||
this.isPaying = false;
|
||||
console.log("growthPackagePay error", error);
|
||||
}
|
||||
},
|
||||
requestGrowthPackagePayment(payKind, paymentParams, orderInfo) {
|
||||
const provider = payKind === 2 ? "wxpay" : "alipay";
|
||||
let payOrderInfo = paymentParams;
|
||||
if (payKind === 2 && paymentParams && typeof paymentParams === "object") {
|
||||
payOrderInfo = {
|
||||
...paymentParams,
|
||||
};
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
if (systemInfo.platform === "ios" && payOrderInfo.appid) {
|
||||
payOrderInfo.appId = payOrderInfo.appid;
|
||||
delete payOrderInfo.appid;
|
||||
}
|
||||
}
|
||||
uni.requestPayment({
|
||||
provider,
|
||||
orderInfo: payOrderInfo,
|
||||
success: () => {
|
||||
this.queryGrowthPackagePay(orderInfo);
|
||||
},
|
||||
fail: (err) => {
|
||||
this.isPaying = false;
|
||||
console.log("growthPackage requestPayment fail", err);
|
||||
this.goToPayResult("fail", orderInfo);
|
||||
},
|
||||
});
|
||||
},
|
||||
async queryGrowthPackagePay(orderInfo) {
|
||||
try {
|
||||
const queryRes = await request.post(
|
||||
"/sj/growthPackage/queryPay",
|
||||
{
|
||||
id: orderInfo.id,
|
||||
number: orderInfo.number,
|
||||
},
|
||||
{
|
||||
hideLoading: true,
|
||||
}
|
||||
);
|
||||
const order = queryRes && queryRes.data && queryRes.data.order;
|
||||
if (queryRes && queryRes.code === 200 && order && Number(order.state) === 2) {
|
||||
this.isJoined = true;
|
||||
this.goToPayResult("success", order);
|
||||
return;
|
||||
}
|
||||
this.goToPayResult("fail", orderInfo);
|
||||
} catch (error) {
|
||||
console.log("growthPackageQueryPay error", error);
|
||||
this.goToPayResult("fail", orderInfo);
|
||||
} finally {
|
||||
this.isPaying = false;
|
||||
}
|
||||
},
|
||||
goToPayResult(status, orderInfo = {}) {
|
||||
const params = [`status=${status}`];
|
||||
if (orderInfo.number) {
|
||||
params.push(`number=${encodeURIComponent(orderInfo.number)}`);
|
||||
}
|
||||
if (orderInfo.pay_money || orderInfo.order_money) {
|
||||
params.push(`money=${encodeURIComponent(orderInfo.pay_money || orderInfo.order_money)}`);
|
||||
}
|
||||
uni.redirectTo({
|
||||
url: `/pages/home/growth-package-result?${params.join("&")}`,
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background: #150903;
|
||||
}
|
||||
|
||||
.growth-package-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: 259rpx;
|
||||
background: #150903;
|
||||
|
||||
.content-image {
|
||||
display: block;
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.deal-carousel {
|
||||
position: relative;
|
||||
width: 750rpx;
|
||||
height: 1342rpx;
|
||||
background: #000000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.deal-swiper {
|
||||
width: 750rpx;
|
||||
height: 1280rpx;
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.deal-slide {
|
||||
position: relative;
|
||||
width: 670rpx;
|
||||
height: 1280rpx;
|
||||
background: #000000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.deal-slide-image {
|
||||
display: block;
|
||||
width: 670rpx;
|
||||
height: 1280rpx;
|
||||
}
|
||||
|
||||
.deal-slide.is-prev,
|
||||
.deal-slide.is-next {
|
||||
height: 1169rpx;
|
||||
margin-top: 56rpx;
|
||||
}
|
||||
|
||||
.deal-slide.is-prev .deal-slide-image,
|
||||
.deal-slide.is-next .deal-slide-image {
|
||||
position: absolute;
|
||||
top: -56rpx;
|
||||
}
|
||||
|
||||
.deal-slide.is-prev .deal-slide-image {
|
||||
right: 10rpx;
|
||||
border-top-right-radius: 20rpx;
|
||||
border-bottom-right-radius: 20rpx;
|
||||
}
|
||||
|
||||
.deal-slide.is-next .deal-slide-image {
|
||||
left: 10rpx;
|
||||
border-top-left-radius: 20rpx;
|
||||
border-bottom-left-radius: 20rpx;
|
||||
}
|
||||
|
||||
.deal-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 62rpx;
|
||||
column-gap: 8rpx;
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.indicator-track {
|
||||
width: 146rpx;
|
||||
height: 8rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(255, 255, 255, 0.42);
|
||||
}
|
||||
|
||||
.indicator-track.active {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.fixed-action {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 20;
|
||||
width: 750rpx;
|
||||
height: 259rpx;
|
||||
background: #150903;
|
||||
}
|
||||
|
||||
.action-image {
|
||||
display: block;
|
||||
width: 750rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
2089
pages/home/home.vue
2089
pages/home/home.vue
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,544 +0,0 @@
|
|||
<template>
|
||||
<view>
|
||||
<custom-navbar title="精选品牌"
|
||||
:leftImg="'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/60ae3383-6ff6-4f42-818b-d9b09a9bd0e0.png'"
|
||||
:showUser="true"
|
||||
backgroundColor="url('https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/ce2e62e1-c26a-45c8-a49d-7ed00b2ce02c.png') center 20%/cover no-repeat"
|
||||
titleColor="#333" borderBottom="none" :show-headle="true"
|
||||
headleSrc="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/51ebca5d-95c5-4fb8-8aa3-560a79100d25.png"
|
||||
@onHeadleClick="goToSearch" class="nav-img-size">
|
||||
</custom-navbar>
|
||||
|
||||
<serviecFirstTab :tabs="tabs" :activeId="activeId" activeColor="#FF4767" @tab-click="tabClick" bgColor="#fff">
|
||||
</serviecFirstTab>
|
||||
|
||||
<CommonList ref="brandListRef" :apiUrl="'/sj/brand/list'" :initialQuery="{}"
|
||||
:listScrollHeight="`calc(100vh - ${statusBarHeight * 2 + 250}rpx)`" @data-loaded="handleDataLoaded">
|
||||
|
||||
<template #headerScroll>
|
||||
<view class="icon-tabs">
|
||||
<view v-for="item in iconTabs" :key="item.id" class="icon-tab"
|
||||
:class="{ active: currentSecondClass == item.id }" @click="selectSecondClass(item.id)">
|
||||
<image :src="item.photo" class="icon-img" mode="aspectFill"></image>
|
||||
<text class="icon-text">{{ item.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sort-bar">
|
||||
<view class="sort-item" @tap="toggleSort('time')">
|
||||
<text class="sort-text" :class="{ active: orderType === 1 || orderType === 2 }">发布时间</text>
|
||||
<view class="arrows">
|
||||
<image class="arrow-icon" :src="orderType === 2 ? iconPinkUp : iconGreyUp"></image>
|
||||
<image class="arrow-icon" :src="orderType === 1 ? iconPinkDown : iconGreyDown"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sort-item" @tap="toggleSort('view')">
|
||||
<text class="sort-text" :class="{ active: orderType === 3 || orderType === 4 }">浏览量</text>
|
||||
<view class="arrows">
|
||||
<image class="arrow-icon" :src="orderType === 4 ? iconPinkUp : iconGreyUp"></image>
|
||||
<image class="arrow-icon" :src="orderType === 3 ? iconPinkDown : iconGreyDown"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template #listData="{ list }">
|
||||
<view class="zhanwei">
|
||||
<view class="brand-grid">
|
||||
<brand-card class="brand-card-wrap" v-for="(brand, idx) in enrichedBrandList(list)" :key="brand.id || idx"
|
||||
:item="brand" :tagKeys="brand._tagKeys" @click="handleBrandClick(brand)" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template #empty>
|
||||
<noData></noData>
|
||||
</template>
|
||||
</CommonList>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from "../../utils/request";
|
||||
import serviecFirstTab from "@/components/common/service-first-tab.vue";
|
||||
import CommonList from "@/components/common/CommonList.vue";
|
||||
import brandCard from "@/pages/home/components/brand-card.vue";
|
||||
import noData from "@/components/noData/noData.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
serviecFirstTab,
|
||||
CommonList,
|
||||
brandCard,
|
||||
noData
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statusBarHeight: 0,
|
||||
navHeight: 0,
|
||||
|
||||
// 当前选中的一级/二级分类ID(页面顶部点击用)
|
||||
activeId: "",
|
||||
currentSecondClass: "",
|
||||
tabs: [],
|
||||
iconTabs: [],
|
||||
|
||||
selectedSecondIds: [], // 抽屉里选中的分类ID
|
||||
|
||||
// 额外筛选参数
|
||||
orderType: 0,
|
||||
|
||||
// 排序图标资源
|
||||
iconGreyUp: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e00ab2ac-bccf-42d8-820c-65727327e279.png',
|
||||
iconGreyDown: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/dfffb601-6877-4608-a3eb-88695b05c6c2.png',
|
||||
iconPinkUp: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/5bc84dff-e120-4d4b-a33e-25d68e065654.png',
|
||||
iconPinkDown: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/ff2c2c9d-694a-4adf-b737-66b07f4a63ae.png',
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
this.statusBarHeight = systemInfo.statusBarHeight;
|
||||
this.navHeight = this.statusBarHeight + 44;
|
||||
|
||||
if (options.id) {
|
||||
this.activeId = options.id;
|
||||
}
|
||||
this.getFirstClass();
|
||||
|
||||
// 初始化时一并获取抽屉内的级联字典数据
|
||||
this.loadFilterCategories();
|
||||
},
|
||||
methods: {
|
||||
// 跳转搜索页
|
||||
goToSearch() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/search_common/search?type=brand' // 告诉搜索页,我要搜品牌
|
||||
});
|
||||
},
|
||||
|
||||
// 加载一级分类并自动组装其对应的二级分类,兼容 state === 1
|
||||
async loadFilterCategories() {
|
||||
try {
|
||||
const syrId = uni.getStorageSync('syrId') || 1;
|
||||
const res = await request.post('/sj/firstclass', { id: syrId })
|
||||
if ((res.code === 200 || res.state === 1) && res.data) {
|
||||
const firstClasses = res.data;
|
||||
|
||||
// 并发请求所有的二级分类
|
||||
const promises = firstClasses.map(async (first) => {
|
||||
try {
|
||||
const subRes = await request.post('/sj/secondclass', { id: first.id })
|
||||
return {
|
||||
id: first.id,
|
||||
title: first.title,
|
||||
children: ((subRes.code === 200 || subRes.state === 1) && subRes.data) ? subRes.data : []
|
||||
}
|
||||
} catch (e) {
|
||||
return { id: first.id, title: first.title, children: [] }
|
||||
}
|
||||
});
|
||||
|
||||
const filterData = await Promise.all(promises);
|
||||
// 过滤掉没有子分类的项,避免面板出现光秃秃的标题
|
||||
this.brandFilterData = filterData.filter(group => group.children.length > 0);
|
||||
} else {
|
||||
this.brandFilterData = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取分类字典失败', error)
|
||||
}
|
||||
},
|
||||
|
||||
// ============ 排序逻辑 ============
|
||||
toggleSort(type) {
|
||||
if (type === 'time') {
|
||||
if (this.orderType === 1) {
|
||||
this.orderType = 2;
|
||||
} else if (this.orderType === 2) {
|
||||
this.orderType = 0;
|
||||
} else {
|
||||
this.orderType = 1;
|
||||
}
|
||||
} else if (type === 'view') {
|
||||
if (this.orderType === 3) {
|
||||
this.orderType = 4;
|
||||
} else if (this.orderType === 4) {
|
||||
this.orderType = 0;
|
||||
} else {
|
||||
this.orderType = 3;
|
||||
}
|
||||
}
|
||||
this.refreshBrandList();
|
||||
},
|
||||
|
||||
// ============ 页面内分类逻辑 ============
|
||||
getFirstClass() {
|
||||
request.post("/sj/firstclass").then((res) => {
|
||||
this.tabs = res.data || [];
|
||||
if (this.tabs.length && !this.activeId) {
|
||||
this.activeId = this.tabs[0].id;
|
||||
}
|
||||
this.getSecondClassList();
|
||||
this.refreshBrandList();
|
||||
});
|
||||
},
|
||||
|
||||
getSecondClassList() {
|
||||
if (!this.activeId) return;
|
||||
request.post('/sj/secondclass', { id: this.activeId }).then((res) => {
|
||||
this.iconTabs = res.data || [];
|
||||
});
|
||||
},
|
||||
|
||||
selectSecondClass(id) {
|
||||
if (this.currentSecondClass === id) {
|
||||
this.currentSecondClass = "";
|
||||
} else {
|
||||
this.currentSecondClass = id;
|
||||
}
|
||||
// 页面上点击了圆形图标,则清空抽屉里的选择
|
||||
this.selectedSecondIds = [];
|
||||
this.refreshBrandList();
|
||||
},
|
||||
|
||||
tabClick(id) {
|
||||
if (this.activeId === id) return;
|
||||
this.activeId = id;
|
||||
this.currentSecondClass = "";
|
||||
this.selectedSecondIds = [];
|
||||
this.getSecondClassList();
|
||||
this.refreshBrandList();
|
||||
},
|
||||
|
||||
// ============ 刷新列表核心 ============
|
||||
refreshBrandList() {
|
||||
// 如果抽屉里选了分类,优先传抽屉的参数;否则传圆形图标选中的分类
|
||||
const targetSecondClass = this.selectedSecondIds.length > 0
|
||||
? this.selectedSecondIds.join(',')
|
||||
: this.currentSecondClass;
|
||||
|
||||
const params = {
|
||||
first_class: this.activeId || undefined,
|
||||
second_class: targetSecondClass || undefined,
|
||||
// 如果 orderType 是 0,则设为 undefined,使其不传给后端
|
||||
order_type: this.orderType === 0 ? undefined : this.orderType
|
||||
};
|
||||
|
||||
Object.keys(params).forEach(key => {
|
||||
if (params[key] === undefined) delete params[key];
|
||||
});
|
||||
|
||||
if (this.$refs.brandListRef) {
|
||||
// CommonList 会合并旧 queryData,清空筛选时需要同步移除旧字段。
|
||||
['first_class', 'second_class', 'order_type'].forEach(key => {
|
||||
if (!Object.prototype.hasOwnProperty.call(params, key) && this.$refs.brandListRef.queryData) {
|
||||
this.$delete(this.$refs.brandListRef.queryData, key);
|
||||
}
|
||||
});
|
||||
this.$refs.brandListRef.manualRefresh(params);
|
||||
}
|
||||
},
|
||||
|
||||
enrichedBrandList(list) {
|
||||
if (!list || !list.length) return [];
|
||||
return list.map(brand => {
|
||||
const tagKeys = [];
|
||||
if (brand.franchise_state === 1) tagKeys.push('franchise');
|
||||
if (brand.student_state === 1) tagKeys.push('recruit');
|
||||
if (tagKeys.length === 0) tagKeys.push('more');
|
||||
|
||||
return {
|
||||
...brand,
|
||||
name: brand.name,
|
||||
bgSrc: brand.cover_img || 'https://dummyimage.com/300x200/ccc/fff.png',
|
||||
avatar: brand.logo_img || 'https://dummyimage.com/100x100/ccc/fff.png',
|
||||
_tagKeys: tagKeys
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
handleBrandClick(brand) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/brand/detail?id=${brand.id}`
|
||||
});
|
||||
},
|
||||
|
||||
handleDataLoaded(data) {
|
||||
console.log("品牌列表加载完成", data);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 保证右侧搜索图标大小合适
|
||||
::v-deep .icon-headle {
|
||||
width: 32rpx !important;
|
||||
height: 32rpx !important;
|
||||
}
|
||||
|
||||
// 一级类目 Tab 样式微调
|
||||
.service-first-tab {
|
||||
border-bottom: none;
|
||||
padding-bottom: 27rpx;
|
||||
position: relative;
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
::v-deep .service-first-tab {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* ================= 抽屉下拉样式 ================= */
|
||||
.filter-panel {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
|
||||
&.show {
|
||||
pointer-events: auto;
|
||||
|
||||
.filter-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.filter-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border-radius: 0 0 30rpx 30rpx;
|
||||
padding: 140rpx 30rpx 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.05);
|
||||
transform: translateY(-100%);
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.filter-scroll {
|
||||
max-height: 50vh;
|
||||
}
|
||||
|
||||
.filter-group {
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.group-title {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.pill-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx 10rpx;
|
||||
/* 控制行间距和列间距 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 通用胶囊按钮 (一行四个) */
|
||||
.pill-item {
|
||||
width: calc(25% - 8rpx);
|
||||
/* 精确计算一行四个 */
|
||||
height: 58rpx;
|
||||
background: #F5F5F5;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
/* 字号略小以防溢出 */
|
||||
color: #333333;
|
||||
line-height: 37rpx;
|
||||
|
||||
/* flex 居中文字 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: 12rpx;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
|
||||
&.active {
|
||||
background: #FFF0F2;
|
||||
color: #FF4767;
|
||||
border: 1rpx solid #FFB0BD;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 40rpx;
|
||||
|
||||
.reset-btn,
|
||||
.confirm-btn {
|
||||
width: 47%;
|
||||
text-align: center;
|
||||
padding: 22rpx 0;
|
||||
border-radius: 40rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background: #F5F5F5;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background: #FF4767;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================= 其他页面样式 ================= */
|
||||
// 二级类目图标行
|
||||
.icon-tabs {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
column-gap: 36rpx;
|
||||
row-gap: 30rpx;
|
||||
background: transparent;
|
||||
padding: 0 0 0 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.icon-tab {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.icon-img {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid transparent;
|
||||
}
|
||||
|
||||
.icon-text {
|
||||
margin-top: 10rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.icon-tab.active .icon-text {
|
||||
color: #FF4767;
|
||||
line-height: 33rpx;
|
||||
}
|
||||
|
||||
.icon-tab.active .icon-img {
|
||||
border: 2rpx solid #FF4767;
|
||||
}
|
||||
|
||||
// 排序栏样式
|
||||
.sort-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 30rpx;
|
||||
margin-bottom: 24rpx;
|
||||
gap: 100rpx;
|
||||
|
||||
.sort-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.sort-text {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
line-height: 37rpx;
|
||||
margin-right: 6rpx;
|
||||
|
||||
&.active {
|
||||
color: #FF4767;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.arrows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.arrow-icon {
|
||||
width: 13rpx;
|
||||
height: 8rpx;
|
||||
margin: 2rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 品牌卡片网格
|
||||
.zhanwei {
|
||||
background-color: #f5f5f5;
|
||||
padding: 20rpx 0 0 0;
|
||||
border-radius: 20rpx 20rpx 0rpx 0rpx;
|
||||
}
|
||||
|
||||
.brand-grid {
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 24rpx;
|
||||
row-gap: 24rpx;
|
||||
border-radius: 20rpx 20rpx 0rpx 0rpx;
|
||||
|
||||
.brand-card-wrap {
|
||||
width: 48.5%;
|
||||
}
|
||||
}
|
||||
|
||||
.common-list {
|
||||
::v-deep .list-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::v-deep .list-scroll {
|
||||
margin-top: 0rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.service-list {
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
}
|
||||
|
||||
.nav-img-size::v-deep .icon-headle {
|
||||
width: 36rpx !important;
|
||||
height: 36rpx !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,579 +0,0 @@
|
|||
<template>
|
||||
<view class="skill-market-page">
|
||||
|
||||
<custom-navbar title="技能集市" :showBack="true" backgroundColor="#FFFFFF" :show-headle="true" borderBottom="none"
|
||||
headleSrc="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/51ebca5d-95c5-4fb8-8aa3-560a79100d25.png"
|
||||
@onHeadleClick="goToSearch" class="nav-img-size">
|
||||
</custom-navbar>
|
||||
<view class="sticky-header-container" :style="{ top: navHeight + 'px' }">
|
||||
|
||||
<view class="official-author-block" v-if="authorInfo.show">
|
||||
<view class="author-left">
|
||||
<image class="author-avatar" :src="authorInfo.avatar" mode="aspectFill"></image>
|
||||
<view class="author-info">
|
||||
<text class="author-name">{{ authorInfo.name }}</text>
|
||||
<text class="author-desc">发布了{{ authorInfo.videoCount }}条技能</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="view-more-btn" v-if="!authorInfo.isOfficial" @click="goToBrandDetail">
|
||||
<text>查看更多</text>
|
||||
<view class="arrow-right"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sort-bar-wrap">
|
||||
<view class="sort-bar">
|
||||
<view class="left-sorts">
|
||||
<view class="sort-item" @tap="toggleSort('time')">
|
||||
<text class="sort-text" :class="{ active: orderType === 1 || orderType === 2 }">发布时间</text>
|
||||
<view class="arrows">
|
||||
<image class="arrow-icon" :src="orderType === 2 ? iconPinkUp : iconGreyUp"></image>
|
||||
<image class="arrow-icon" :src="orderType === 1 ? iconPinkDown : iconGreyDown"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sort-item" @tap="toggleSort('view')">
|
||||
<text class="sort-text" :class="{ active: orderType === 3 || orderType === 4 }">浏览量</text>
|
||||
<view class="arrows">
|
||||
<image class="arrow-icon" :src="orderType === 4 ? iconPinkUp : iconGreyUp"></image>
|
||||
<image class="arrow-icon" :src="orderType === 3 ? iconPinkDown : iconGreyDown"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="right-filter" @tap="toggleFilterPanel" v-if="!authorInfo.show">
|
||||
<text class="filter-text">筛选</text>
|
||||
<image class="filter-icon" :src="filterIcon" :class="{ 'rotate': filterVisible }"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="filter-panel" :class="{ 'show': filterVisible }" catchtouchmove="true">
|
||||
<view class="filter-mask" @tap="closeFilterPanel"></view>
|
||||
<view class="filter-container">
|
||||
<text class="group-title">课程类型</text>
|
||||
<view class="course-filter">
|
||||
<view class="course-type-item" :class="{ active: linkType === '' }" @tap="selectAndApply('')">全部</view>
|
||||
<view class="course-type-item" :class="{ active: linkType === 1 }" @tap="selectAndApply(1)">平台课程</view>
|
||||
<view class="course-type-item" :class="{ active: linkType === 2 }" @tap="selectAndApply(2)">品牌课程</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="list-container">
|
||||
<view v-if="skillList.length > 0">
|
||||
<skill-card v-for="(item, index) in skillList" :key="item.id || index" :item="item"
|
||||
@click="goToDetail(item)"></skill-card>
|
||||
</view>
|
||||
|
||||
<view v-else>
|
||||
<noData></noData>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view style="height: 60rpx;"></view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from "@/utils/request"
|
||||
import SkillCard from "@/pages/home/components/skill-card.vue"
|
||||
import noData from "@/components/noData/noData.vue";
|
||||
|
||||
const USE_REAL_API = true
|
||||
|
||||
export default {
|
||||
components: { SkillCard, noData },
|
||||
data() {
|
||||
return {
|
||||
navHeight: 0,
|
||||
|
||||
orderType: 0,
|
||||
linkType: '',
|
||||
|
||||
// 【新增】:统一管理作者/官方/品牌信息
|
||||
authorInfo: {
|
||||
show: false, // 控制是否显示作者头部
|
||||
isOfficial: false, // 区分是官方还是普通品牌
|
||||
brandId: null, // 品牌ID
|
||||
name: '', // 作者/品牌名称
|
||||
avatar: '', // 头像
|
||||
videoCount: 0 // 视频数量
|
||||
},
|
||||
|
||||
filterVisible: false,
|
||||
|
||||
skillList: [],
|
||||
page: 1,
|
||||
limit: 10,
|
||||
isFinished: false,
|
||||
|
||||
iconGreyUp: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e00ab2ac-bccf-42d8-820c-65727327e279.png',
|
||||
iconGreyDown: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/dfffb601-6877-4608-a3eb-88695b05c6c2.png',
|
||||
iconPinkUp: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/5bc84dff-e120-4d4b-a33e-25d68e065654.png',
|
||||
iconPinkDown: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/ff2c2c9d-694a-4adf-b737-66b07f4a63ae.png',
|
||||
|
||||
mockDatabase: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filterIcon() {
|
||||
return this.filterVisible
|
||||
? 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e00ab2ac-bccf-42d8-820c-65727327e279.png'
|
||||
: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/bfe7a104-bef8-4432-9487-42f05e3e9035.png'
|
||||
}
|
||||
},
|
||||
// 接收页面跳转传过来的作者参数
|
||||
onLoad(options) {
|
||||
if (options && options.showAuthor === '1') {
|
||||
this.authorInfo.show = true;
|
||||
this.authorInfo.isOfficial = options.isOfficial === '1';
|
||||
this.authorInfo.brandId = options.linkId || null;
|
||||
|
||||
// 用 decodeURIComponent 把转义的字符解析回正常的中文和链接
|
||||
this.authorInfo.name = options.authorName ? decodeURIComponent(options.authorName) : '未知作者';
|
||||
this.authorInfo.avatar = options.authorAvatar ? decodeURIComponent(options.authorAvatar) : 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/bbe832bf-aae6-4579-b3cc-246d252488c3';
|
||||
this.authorInfo.videoCount = options.videoCount || 0;
|
||||
|
||||
// 强制设置筛选类型
|
||||
this.linkType = this.authorInfo.isOfficial ? 1 : 2;
|
||||
} else if (options && options.linkType !== undefined) {
|
||||
this.linkType = Number(options.linkType);
|
||||
}
|
||||
|
||||
const sysInfo = uni.getSystemInfoSync()
|
||||
const sbh = sysInfo.statusBarHeight || 0
|
||||
this.navHeight = sbh
|
||||
|
||||
this.initMockData()
|
||||
this.fetchData(true)
|
||||
},
|
||||
onReachBottom() {
|
||||
if (!this.isFinished) {
|
||||
this.fetchData(false)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToSearch() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/search_common/search?type=skill'
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到品牌详情页面
|
||||
goToBrandDetail() {
|
||||
if (this.authorInfo.brandId) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/jingxuan/brand-detail?id=${this.authorInfo.brandId}`
|
||||
});
|
||||
} else {
|
||||
uni.showToast({ title: '缺少品牌信息', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
toggleSort(type) {
|
||||
if (type === 'time') {
|
||||
if (this.orderType === 1) this.orderType = 2
|
||||
else if (this.orderType === 2) this.orderType = 0
|
||||
else this.orderType = 1
|
||||
} else if (type === 'view') {
|
||||
if (this.orderType === 3) this.orderType = 4
|
||||
else if (this.orderType === 4) this.orderType = 0
|
||||
else this.orderType = 3
|
||||
}
|
||||
this.fetchData(true)
|
||||
},
|
||||
|
||||
toggleFilterPanel() {
|
||||
this.filterVisible = !this.filterVisible
|
||||
},
|
||||
closeFilterPanel() {
|
||||
this.filterVisible = false
|
||||
},
|
||||
|
||||
selectAndApply(typeVal) {
|
||||
this.linkType = typeVal;
|
||||
// 当通过本地筛选器切换时,关闭“专属展示区”,确保纯净筛选
|
||||
this.authorInfo.show = false;
|
||||
this.closeFilterPanel();
|
||||
this.fetchData(true);
|
||||
},
|
||||
|
||||
async fetchData(isReset = false) {
|
||||
if (isReset) {
|
||||
this.page = 1
|
||||
this.isFinished = false
|
||||
this.skillList = []
|
||||
}
|
||||
|
||||
if (USE_REAL_API) {
|
||||
uni.showLoading({ title: '加载中...' })
|
||||
try {
|
||||
const params = {
|
||||
page: this.page,
|
||||
limit: this.limit
|
||||
}
|
||||
if (this.orderType !== 0) params.order_type = this.orderType;
|
||||
if (this.linkType !== '') params.link_type = this.linkType;
|
||||
|
||||
// 【核心接口预留】:如果当前在看某个品牌的专属页,需要传link_id给后端过滤
|
||||
if (this.authorInfo.show && !this.authorInfo.isOfficial && this.authorInfo.brandId) {
|
||||
params.link_id = this.authorInfo.brandId;
|
||||
}
|
||||
|
||||
const res = await request.post('/sj/skill/list', params)
|
||||
if ((res.code === 200 || res.state === 1) && res.data && res.data.list) {
|
||||
const list = res.data.list.map(item => this.formatApiData(item))
|
||||
if (list.length < this.limit) this.isFinished = true
|
||||
this.skillList = isReset ? list : this.skillList.concat(list)
|
||||
this.page++
|
||||
} else {
|
||||
this.isFinished = true
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
} else {
|
||||
uni.showLoading({ title: '模拟加载中...' })
|
||||
setTimeout(() => {
|
||||
let list = [...this.mockDatabase]
|
||||
|
||||
if (this.linkType !== '') {
|
||||
list = list.filter(item => item.link_type === this.linkType)
|
||||
}
|
||||
|
||||
// 模拟品牌过滤
|
||||
if (this.authorInfo.show && !this.authorInfo.isOfficial && this.authorInfo.brandId) {
|
||||
list = list.filter(item => item.brand_id == this.authorInfo.brandId)
|
||||
}
|
||||
|
||||
if (this.orderType !== 0) {
|
||||
list.sort((a, b) => {
|
||||
if (this.orderType === 1) return b.timestamp - a.timestamp
|
||||
if (this.orderType === 2) return a.timestamp - b.timestamp
|
||||
if (this.orderType === 3) return b.views - a.views
|
||||
if (this.orderType === 4) return a.views - b.views
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
const start = (this.page - 1) * this.limit
|
||||
const end = start + this.limit
|
||||
const pageData = list.slice(start, end)
|
||||
|
||||
if (pageData.length < this.limit) this.isFinished = true
|
||||
this.skillList = isReset ? pageData : this.skillList.concat(pageData)
|
||||
this.page++
|
||||
uni.hideLoading()
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
|
||||
formatApiData(item) {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
coverSrc: item.cover_img || 'https://dummyimage.com/300x200/ccc/fff.png',
|
||||
type: item.link_name || (item.link_type === 1 ? '平台课程' : '品牌课程'),
|
||||
link_type: item.link_type,
|
||||
views: item.browse_num || 0,
|
||||
time: item.create_time ? this.formatTimeAgo(item.create_time) : '',
|
||||
typeIcon: item.link_logo || ''
|
||||
}
|
||||
},
|
||||
|
||||
formatTimeAgo(timeStr) {
|
||||
const now = new Date()
|
||||
const time = new Date(timeStr.replace(/-/g, '/'))
|
||||
const diff = Math.floor((now - time) / 1000)
|
||||
if (diff < 3600) return Math.floor(diff / 60) + '分钟前'
|
||||
if (diff < 86400) return Math.floor(diff / 3600) + '小时前'
|
||||
if (diff < 604800) return Math.floor(diff / 86400) + '天前'
|
||||
return timeStr.split(' ')[0]
|
||||
},
|
||||
|
||||
goToDetail(item) {
|
||||
if (item.id) {
|
||||
uni.navigateTo({ url: `/pages/skill/detail?id=${item.id}` })
|
||||
} else {
|
||||
uni.showToast({ title: '详情页开发中', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
initMockData() {
|
||||
this.mockDatabase = [
|
||||
{ id: 1, title: '穿戴甲的操作视频扫码验券操作教程', coverSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg', type: '平台课程', link_type: 1, views: 836000, time: '7小时前', timestamp: Date.now() - 7 * 3600000 },
|
||||
{ id: 2, title: '脸部按摩操作步骤详情', coverSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg', type: '品牌课程', link_type: 2, brand_id: 101, views: 8334, time: '1天前', timestamp: Date.now() - 24 * 3600000 },
|
||||
{ id: 3, title: '全身SPA的操作视频操作教程', coverSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg', type: '平台课程', link_type: 1, views: 2344, time: '3天前', timestamp: Date.now() - 3 * 24 * 3600000 },
|
||||
{ id: 4, title: '高级面部护理手法详解最新版', coverSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg', type: '平台课程', link_type: 1, views: 836, time: '4月26日', timestamp: Date.now() - 30 * 24 * 3600000 },
|
||||
{ id: 5, title: '光疗美甲进阶全方位解析', coverSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg', type: '品牌课程', link_type: 2, brand_id: 101, views: 12000, time: '2小时前', timestamp: Date.now() - 2 * 3600000 }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.skill-market-page {
|
||||
min-height: 100vh;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 统一吸顶容器 */
|
||||
.sticky-header-container {
|
||||
position: sticky;
|
||||
background: #fff;
|
||||
z-index: 101;
|
||||
/* 确保整体吸顶时下方有稍微一点阴影或边框分割更好看,可根据 UI 需求开启 */
|
||||
// border-bottom: 1rpx solid #F5F5F5;
|
||||
}
|
||||
|
||||
/* 官方/品牌 作者展示块样式 */
|
||||
.official-author-block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 30rpx;
|
||||
background: #fff;
|
||||
border-bottom: 10rpx solid #F5F5F5;
|
||||
|
||||
.author-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.author-avatar {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.author-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.author-name {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.author-desc {
|
||||
font-weight: 400;
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
line-height: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.view-more-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
border: 2rpx solid #FF4767;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 45rpx;
|
||||
|
||||
.arrow-right {
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
border-top: 2rpx solid #FF4767;
|
||||
border-right: 2rpx solid #FF4767;
|
||||
transform: rotate(45deg);
|
||||
margin-left: 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sort-bar-wrap {
|
||||
/* 移除单独的 sticky,由外层 container 统一控制 */
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sort-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 30rpx;
|
||||
|
||||
.left-sorts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 100rpx;
|
||||
|
||||
.sort-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.sort-text {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
margin-right: 6rpx;
|
||||
font-weight: 400;
|
||||
|
||||
&.active {
|
||||
color: #FF4767;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.arrows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.arrow-icon {
|
||||
width: 14rpx;
|
||||
height: 8rpx;
|
||||
margin: 2rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.filter-text {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.filter-icon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&.rotate {
|
||||
transform: rotate(180deg);
|
||||
width: 18rpx;
|
||||
height: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-container {
|
||||
padding: 0 24rpx 30rpx;
|
||||
}
|
||||
|
||||
.filter-panel {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100vh;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
|
||||
&.show {
|
||||
pointer-events: auto;
|
||||
|
||||
.filter-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.filter-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border-radius: 0 0 24rpx 24rpx;
|
||||
padding: 30rpx 30rpx 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transform: translateY(-100%);
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.group-title {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 24rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.course-filter {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
|
||||
.course-type-item {
|
||||
background: #F5F5F5;
|
||||
color: #333333;
|
||||
font-size: 26rpx;
|
||||
padding: 12rpx 36rpx;
|
||||
border-radius: 12rpx;
|
||||
border: 1rpx solid transparent;
|
||||
transition: all 0.2s;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.active {
|
||||
background: #FFF0F2;
|
||||
color: #FF4767;
|
||||
border-color: #FFB0BD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 120rpx 0;
|
||||
|
||||
.empty-icon {
|
||||
width: 346rpx;
|
||||
height: 373rpx;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .icon-headle {
|
||||
width: 32rpx !important;
|
||||
height: 32rpx !important;
|
||||
}
|
||||
|
||||
::v-deep .back-icon {
|
||||
width: 28rpx !important;
|
||||
height: 36rpx !important;
|
||||
}
|
||||
|
||||
.nav-img-size::v-deep .icon-headle {
|
||||
width: 36rpx !important;
|
||||
height: 36rpx !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,768 +0,0 @@
|
|||
<template>
|
||||
<view class="skill-detail-page">
|
||||
|
||||
<custom-navbar title="技能集市" backgroundColor="#ffffff" titleColor="#333" borderBottom="none">
|
||||
</custom-navbar>
|
||||
|
||||
<!-- <view class="mock-switch" @click="toggleMockData">
|
||||
<text>{{ useMockData ? '关闭模拟数据' : '开启模拟数据' }}</text>
|
||||
</view> -->
|
||||
|
||||
<view class="video-section" v-if="article.videoSrc">
|
||||
<view class="video-wrapper">
|
||||
|
||||
<video v-if="!tipShow" id="customVideo" class="main-video" :src="article.videoSrc" :poster="article.poster"
|
||||
:controls="showNativeControls" :show-center-play-btn="false" :muted="isMuted" object-fit="cover"
|
||||
@timeupdate="onTimeUpdate" @loadedmetadata="onLoadedMetaData" @ended="onEnded" @play="onPlay" @pause="onPause"
|
||||
@fullscreenchange="onFullScreenChange">
|
||||
<cover-image v-if="!isPlaying && !showNativeControls" class="center-play-icon"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/bb720bb0-4ada-49f6-9ce5-38abfd613d5d.png"
|
||||
@click.stop="togglePlay"></cover-image>
|
||||
|
||||
<cover-view class="custom-control-bar" v-if="!showNativeControls">
|
||||
<cover-image class="bar-bg"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/ce7f28f8-470d-4f5b-9c7e-ff2bf8635226.png"></cover-image>
|
||||
|
||||
<cover-view class="bar-content">
|
||||
<cover-image v-if="isPlaying" class="ctrl-icon" :src="iconPause" @click.stop="togglePlay"></cover-image>
|
||||
<cover-image v-if="!isPlaying" class="ctrl-icon" :src="iconPlay" @click.stop="togglePlay"></cover-image>
|
||||
|
||||
<cover-view class="time-text">{{ formatTime(currentTime) }}</cover-view>
|
||||
|
||||
<cover-view class="slider-track">
|
||||
<cover-view class="slider-bg"></cover-view>
|
||||
<cover-view class="slider-active" :style="activeStyle"></cover-view>
|
||||
<cover-view class="slider-thumb" v-if="currentTime > 0" :style="thumbStyle"></cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="time-text">{{ formatTime(duration) }}</cover-view>
|
||||
|
||||
<cover-image v-if="!isMuted" class="ctrl-icon mute-icon" :src="iconSoundOn"
|
||||
@click.stop="toggleMute"></cover-image>
|
||||
<cover-image v-if="isMuted" class="ctrl-icon mute-icon" :src="iconMute"
|
||||
@click.stop="toggleMute"></cover-image>
|
||||
|
||||
<cover-image class="ctrl-icon fullscreen-icon" :src="iconFullscreen"
|
||||
@click.stop="toggleFullScreen"></cover-image>
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
</video>
|
||||
|
||||
<image v-else class="main-video fallback-poster" :src="article.poster || article.videoSrc" mode="aspectFill">
|
||||
</image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="article-header" v-if="article.title">
|
||||
<view class="title">{{ article.title }}</view>
|
||||
<view class="meta-row">
|
||||
<view class="author-info" @click="goToAuthorMarket">
|
||||
<image class="avatar" :src="article.authorAvatar" mode="aspectFill"></image>
|
||||
<text class="author-name">{{ article.authorName }}</text>
|
||||
<text class="date">{{ article.date }}</text>
|
||||
</view>
|
||||
|
||||
<view class="favorite-btn" @click="toggleFavorite">
|
||||
<image class="star-icon" :src="isFavorite ? filledStarUrl : emptyStarUrl" />
|
||||
<text :class="{ 'active-fav': isFavorite }">{{ isFavorite ? '已收藏' : '收藏' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="article-content-wrapper">
|
||||
<view class="article-content">
|
||||
<rich-text :nodes="formattedHtmlContent"></rich-text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="recommend-section" v-if="recommendList.length > 0">
|
||||
<view class="section-header">
|
||||
<text class="section-title">相关推荐</text>
|
||||
<view class="refresh-btn" @click="refreshList">
|
||||
<image class="refresh-icon" :class="{ 'is-rotating': isRefreshing }"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/f2152145-df2a-49ab-87f5-f66b3207d0b0.png">
|
||||
</image>
|
||||
<text>换一批</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="list-container">
|
||||
<skill-card v-for="(item, index) in recommendList" :key="index" :item="item"></skill-card>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<tipsPopup2 :show="tipShow" @closePopup="closePopup" sureText="确认" @okBtn="okBtn">
|
||||
{{ tipsText }}
|
||||
</tipsPopup2>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from "@/utils/request";
|
||||
import SkillCard from "@/pages/home/components/skill-card.vue";
|
||||
import tipsPopup2 from "@/components/tips-popup/tips-popup2";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SkillCard,
|
||||
tipsPopup2
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
useMockData: false,
|
||||
|
||||
articleId: null,
|
||||
isFavorite: false,
|
||||
emptyStarUrl: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/53378402-5456-4a80-b2ec-7c18d43d970e.png',
|
||||
filledStarUrl: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/10461305-6bf8-4016-ae76-3415e055ec63.png',
|
||||
isRefreshing: false,
|
||||
|
||||
isLogin: false,
|
||||
tipShow: false,
|
||||
tipsText: "",
|
||||
tipType: "",
|
||||
|
||||
videoContext: null,
|
||||
isPlaying: false,
|
||||
isMuted: false,
|
||||
|
||||
showNativeControls: false,
|
||||
|
||||
currentTime: 0,
|
||||
duration: 0,
|
||||
sliderValue: 0,
|
||||
|
||||
iconPlay: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/88ca4fe3-645c-48a9-abda-1f9b45714970.png',
|
||||
iconPause: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/cf9d6dd6-e9df-4c46-bafa-e1a72f7ddbcd.png',
|
||||
iconSoundOn: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/9f13a630-7efd-4c61-b6fe-b6b282e28e42.png',
|
||||
iconMute: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/80f856c1-3d66-4b11-b21a-8eb6a3272a3c.png',
|
||||
iconFullscreen: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/4286ef33-6849-4851-8866-4230d2523a33.png',
|
||||
|
||||
article: {},
|
||||
recommendList: [],
|
||||
recommendPage: 1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
formattedHtmlContent() {
|
||||
if (!this.article.htmlContent) return '';
|
||||
let html = this.article.htmlContent;
|
||||
html = html.replace(/<img/gi, '<img style="max-width:100%; height:auto; display:block; border-radius:10px; margin: 20rpx 0;"');
|
||||
html = html.replace(/<p/gi, '<p style="margin-bottom: 24rpx; line-height: 40rpx;"');
|
||||
return html;
|
||||
},
|
||||
activeStyle() {
|
||||
return `width: ${this.sliderValue}%;`;
|
||||
},
|
||||
thumbStyle() {
|
||||
return `left: ${this.sliderValue}%;`;
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options && options.id) {
|
||||
this.articleId = parseInt(options.id, 10);
|
||||
} else {
|
||||
this.articleId = 1;
|
||||
}
|
||||
this.getPageData();
|
||||
},
|
||||
onShow() {
|
||||
this.isLogin = uni.getStorageSync("accessToken") ? true : false;
|
||||
},
|
||||
methods: {
|
||||
// 点击跳回集市专属页面(兼容官方和品牌方)
|
||||
goToAuthorMarket() {
|
||||
const isOfficial = this.article.linkType === 1 ? '1' : '0';
|
||||
const linkId = this.article.linkId || '';
|
||||
const name = encodeURIComponent(this.article.authorName || '');
|
||||
const avatar = encodeURIComponent(this.article.authorAvatar || '');
|
||||
const count = this.article.authorVideoCount || 0;
|
||||
|
||||
uni.navigateTo({
|
||||
url: `/pages/jingxuan/selected-skills?showAuthor=1&isOfficial=${isOfficial}&linkId=${linkId}&authorName=${name}&authorAvatar=${avatar}&videoCount=${count}`
|
||||
});
|
||||
},
|
||||
|
||||
getVideoContext() {
|
||||
if (!this.videoContext) {
|
||||
this.videoContext = uni.createVideoContext('customVideo', this);
|
||||
}
|
||||
return this.videoContext;
|
||||
},
|
||||
|
||||
closePopup() {
|
||||
this.tipShow = false;
|
||||
},
|
||||
okBtn() {
|
||||
if (this.tipType == "login") {
|
||||
uni.navigateTo({
|
||||
url: "/pages/blogPopup/blogPopup",
|
||||
});
|
||||
}
|
||||
this.tipShow = false;
|
||||
},
|
||||
|
||||
formatTime(sec) {
|
||||
if (!sec) return '00:00';
|
||||
sec = Math.round(sec);
|
||||
let m = Math.floor(sec / 60);
|
||||
let s = sec % 60;
|
||||
return (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
|
||||
},
|
||||
onLoadedMetaData(e) {
|
||||
this.duration = e.detail.duration;
|
||||
},
|
||||
onTimeUpdate(e) {
|
||||
if (e.detail.duration && this.duration === 0) {
|
||||
this.duration = e.detail.duration;
|
||||
}
|
||||
this.currentTime = e.detail.currentTime;
|
||||
if (this.duration > 0) {
|
||||
this.sliderValue = Number(((this.currentTime / this.duration) * 100).toFixed(2));
|
||||
}
|
||||
},
|
||||
onEnded() {
|
||||
this.isPlaying = false;
|
||||
this.currentTime = 0;
|
||||
this.sliderValue = 0;
|
||||
if (this.showNativeControls) {
|
||||
const ctx = this.getVideoContext();
|
||||
if (ctx) ctx.exitFullScreen();
|
||||
}
|
||||
},
|
||||
onPlay() { this.isPlaying = true; },
|
||||
onPause() { this.isPlaying = false; },
|
||||
|
||||
onFullScreenChange(e) {
|
||||
const isFull = e.detail.fullScreen;
|
||||
if (!isFull) {
|
||||
this.showNativeControls = false;
|
||||
} else {
|
||||
this.showNativeControls = true;
|
||||
}
|
||||
},
|
||||
|
||||
togglePlay() {
|
||||
const ctx = this.getVideoContext();
|
||||
if (!ctx) return;
|
||||
if (this.isPlaying) {
|
||||
ctx.pause();
|
||||
} else {
|
||||
ctx.play();
|
||||
}
|
||||
},
|
||||
toggleMute() {
|
||||
this.isMuted = !this.isMuted;
|
||||
},
|
||||
|
||||
toggleFullScreen() {
|
||||
const ctx = this.getVideoContext();
|
||||
if (!ctx) return;
|
||||
this.showNativeControls = true;
|
||||
this.$nextTick(() => {
|
||||
ctx.requestFullScreen({ direction: 90 });
|
||||
});
|
||||
},
|
||||
|
||||
toggleMockData() {
|
||||
this.useMockData = !this.useMockData;
|
||||
uni.showToast({ title: this.useMockData ? 'Mock已开启' : 'Mock已关闭', icon: 'none' });
|
||||
this.getPageData();
|
||||
},
|
||||
|
||||
getPageData() {
|
||||
if (this.useMockData) {
|
||||
this.injectMockData();
|
||||
return;
|
||||
}
|
||||
uni.showLoading({ title: '加载中...' });
|
||||
request.post("/sj/skill/details", {
|
||||
id: this.articleId
|
||||
}).then((res) => {
|
||||
if (res.code == 200 && res.data) {
|
||||
const data = res.data;
|
||||
this.article = {
|
||||
title: data.name || '暂无标题',
|
||||
// 【预留接口字段解析】:这里需要后端配合返回以下字段,如果没有的话目前会使用默认值
|
||||
linkType: data.link_type || 1, // 1=官方 2=品牌
|
||||
linkId: data.link_id || 0,
|
||||
authorName: data.link_name || '美融融平台',
|
||||
authorAvatar: data.link_logo || 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/bbe832bf-aae6-4579-b3cc-246d252488c3',
|
||||
authorVideoCount: data.link_publish_num || 0, // 关联者发布数
|
||||
|
||||
date: data.create_time ? data.create_time.substring(0, 10).replace(/-/g, '.') : '',
|
||||
videoSrc: data.video || '',
|
||||
poster: data.cover_img || '',
|
||||
htmlContent: data.detail || ''
|
||||
};
|
||||
this.isFavorite = data.collect_state === 1;
|
||||
request.post("/sj/skill/list", {
|
||||
page: 1,
|
||||
limit: 3,
|
||||
skill_id: data.id
|
||||
}).then((listRes) => {
|
||||
if (listRes.code == 200 && listRes.data && listRes.data.list) {
|
||||
// 使用 map 遍历数组,将后端返回的字段一对一映射成组件需要的字段
|
||||
this.recommendList = listRes.data.list.map(item => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.name || '暂无标题', // 映射标题
|
||||
coverSrc: item.cover_img || '', // 映射封面图
|
||||
type: item.link_name || '平台课程', // 映射来源(平台/品牌)
|
||||
typeIcon: item.link_logo || '', // 映射来源图标
|
||||
// 浏览量优先取总浏览量,如果没有则取实际/初始浏览量
|
||||
views: item.total_browse_num || item.real_browse_num || item.browse_num || 0,
|
||||
// 截取时间并格式化
|
||||
time: item.create_time ? item.create_time.substring(0, 10).replace(/-/g, '-') : ''
|
||||
};
|
||||
});
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error('获取推荐列表异常', err);
|
||||
});
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '获取数据失败', icon: 'none' });
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error('获取技能集市详情异常', err);
|
||||
}).finally(() => {
|
||||
uni.hideLoading();
|
||||
});
|
||||
},
|
||||
|
||||
toggleFavorite() {
|
||||
if (!this.isLogin) {
|
||||
if (this.isPlaying) {
|
||||
this.getVideoContext().pause();
|
||||
}
|
||||
this.tipsText = "您现在还未登录,是否确定前往登录?";
|
||||
this.tipShow = true;
|
||||
this.tipType = "login";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.useMockData) {
|
||||
this.isFavorite = !this.isFavorite;
|
||||
uni.showToast({ title: this.isFavorite ? '收藏成功' : '已取消收藏', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
uni.showLoading({ title: '处理中' });
|
||||
const targetState = this.isFavorite ? 2 : 1;
|
||||
|
||||
request.post("/sj/skill/collect", {
|
||||
id: this.articleId,
|
||||
state: targetState
|
||||
}).then(res => {
|
||||
if (res.code == 200) {
|
||||
this.isFavorite = !this.isFavorite;
|
||||
uni.showToast({ title: this.isFavorite ? '收藏成功' : '已取消收藏', icon: 'none' });
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '操作失败', icon: 'none' });
|
||||
}
|
||||
}).catch(err => {
|
||||
uni.showToast({ title: '网络异常', icon: 'none' });
|
||||
}).finally(() => {
|
||||
uni.hideLoading();
|
||||
});
|
||||
},
|
||||
|
||||
refreshList() {
|
||||
if (this.isRefreshing) return;
|
||||
this.isRefreshing = true;
|
||||
uni.showLoading({ title: '加载中' });
|
||||
|
||||
// 页码逻辑:到达10重置为1,否则+1
|
||||
if (this.recommendPage >= 10) {
|
||||
this.recommendPage = 1;
|
||||
} else {
|
||||
this.recommendPage++;
|
||||
}
|
||||
|
||||
request.post("/sj/skill/list", {
|
||||
page: this.recommendPage,
|
||||
limit: 3,
|
||||
skill_id: this.article.id
|
||||
}).then((res) => {
|
||||
if (res.code == 200 && res.data && res.data.list && res.data.list.length > 0) {
|
||||
this.recommendList = res.data.list.map(item => ({
|
||||
id: item.id,
|
||||
title: item.name || '暂无标题',
|
||||
coverSrc: item.cover_img || '',
|
||||
type: item.link_name || '平台课程',
|
||||
views: item.browse_num || 0,
|
||||
time: item.create_time ? item.create_time.split(' ')[0] : '',
|
||||
typeIcon: item.link_logo || '',
|
||||
video: item.video || ''
|
||||
}));
|
||||
} else {
|
||||
// 下一页没有数据,重置为1重新请求
|
||||
this.recommendPage = 1;
|
||||
request.post("/sj/skill/list", {
|
||||
page: 1,
|
||||
limit: 3,
|
||||
skill_id: this.article.id
|
||||
}).then((res2) => {
|
||||
if (res2.code == 200 && res2.data && res2.data.list) {
|
||||
this.recommendList = res2.data.list.map(item => ({
|
||||
id: item.id,
|
||||
title: item.name || '暂无标题',
|
||||
coverSrc: item.cover_img || '',
|
||||
type: item.link_name || '平台课程',
|
||||
views: item.browse_num || 0,
|
||||
time: item.create_time ? item.create_time.split(' ')[0] : '',
|
||||
typeIcon: item.link_logo || '',
|
||||
video: item.video || ''
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
this.isRefreshing = false;
|
||||
uni.hideLoading();
|
||||
}).catch(() => {
|
||||
this.isRefreshing = false;
|
||||
uni.hideLoading();
|
||||
});
|
||||
},
|
||||
|
||||
injectMockData() {
|
||||
this.isFavorite = false;
|
||||
this.article = {
|
||||
title: '穿戴甲的操作视频扫码验券操作',
|
||||
|
||||
// Mock作者相关数据(测试品牌跳转,将linkType改为2)
|
||||
linkType: 2,
|
||||
linkId: 101,
|
||||
authorName: '蜜丝卡伦官方品牌',
|
||||
authorAvatar: 'https://images.unsplash.com/photo-1512290923902-8a9f81dc236c?ixlib=rb-4.0.3&auto=format&fit=crop&w=100&q=80',
|
||||
authorVideoCount: 658,
|
||||
|
||||
date: '2026.03.03',
|
||||
videoSrc: 'https://vjs.zencdn.net/v/oceans.mp4',
|
||||
poster: 'https://images.unsplash.com/photo-1610992015732-2449b76344bc?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80',
|
||||
htmlContent: `
|
||||
<p>最近,一向以平价、良心、宠粉著称的胖东来,突然因为一条毛巾被推上风口浪尖。</p>
|
||||
<p>4月下旬,抖音博主“惊梦人-”连续发布多条探店视频,称自己跑遍许昌5家胖东来门店,发现一边是几块钱的玻璃水、洗衣液等亲民好物,另一边却摆着标价249元的高端毛巾,价格形成反差。</p>
|
||||
<img src="https://dummyimage.com/800x400/ff6b81/ffffff.png&text=占位图" alt="会员权益"/>
|
||||
`
|
||||
};
|
||||
this.loadMockRecommend();
|
||||
},
|
||||
|
||||
loadMockRecommend() {
|
||||
this.recommendList = [
|
||||
{
|
||||
id: 1,
|
||||
title: '穿戴甲的操作视频扫码验券操作教程...',
|
||||
coverSrc: 'https://images.unsplash.com/photo-1604654894610-df63bc536371?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
|
||||
type: '平台课程',
|
||||
typeIcon: 'https://dummyimage.com/100x100/e6505f/fff.png&text=融',
|
||||
views: 836000,
|
||||
time: '7小时前'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '脸部按摩操作步骤详情',
|
||||
coverSrc: 'https://images.unsplash.com/photo-1512290923902-8a9f81dc236c?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
|
||||
type: '脸缘品牌',
|
||||
typeIcon: 'https://dummyimage.com/100x100/e6505f/fff.png&text=缘',
|
||||
views: 8334,
|
||||
time: '1天前'
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.skill-detail-page {
|
||||
background-color: #ffffff;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 60rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mock-switch {
|
||||
position: fixed;
|
||||
right: 20rpx;
|
||||
top: 200rpx;
|
||||
background: #E5505F;
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 30rpx;
|
||||
z-index: 999;
|
||||
box-shadow: 0 4rpx 10rpx rgba(229, 80, 95, 0.4);
|
||||
}
|
||||
|
||||
.video-section {
|
||||
width: 100%;
|
||||
height: 420rpx;
|
||||
|
||||
.video-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.main-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fallback-poster {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.center-play-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.custom-control-bar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
z-index: 99;
|
||||
|
||||
.bar-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.bar-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
z-index: 101;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 10rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.ctrl-icon {
|
||||
width: 25rpx;
|
||||
height: 30rpx;
|
||||
margin: 0 10rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.mute-icon {
|
||||
width: 38rpx;
|
||||
height: 30rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.fullscreen-icon {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.time-text {
|
||||
font-size: 22rpx;
|
||||
color: #ffffff;
|
||||
line-height: 70rpx;
|
||||
}
|
||||
|
||||
.slider-track {
|
||||
flex: 1;
|
||||
height: 70rpx;
|
||||
margin: 0 20rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
.slider-bg {
|
||||
position: absolute;
|
||||
top: 33rpx;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 4rpx;
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.slider-active {
|
||||
position: absolute;
|
||||
top: 33rpx;
|
||||
left: 0;
|
||||
height: 4rpx;
|
||||
background-color: #FF4767;
|
||||
}
|
||||
|
||||
.slider-thumb {
|
||||
position: absolute;
|
||||
top: 25rpx;
|
||||
margin-left: -10rpx;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #FF4767;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.article-header {
|
||||
padding: 30rpx 30rpx 20rpx;
|
||||
|
||||
.title {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
line-height: 45rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.meta-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.author-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.avatar {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.author-name {
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
line-height: 33rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
line-height: 33rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.favorite-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
line-height: 33rpx;
|
||||
|
||||
.star-icon {
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
margin-right: 6rpx;
|
||||
margin-top: -2rpx;
|
||||
}
|
||||
|
||||
.active-fav {
|
||||
color: #FD5A8C;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.article-content-wrapper {
|
||||
.article-content {
|
||||
padding: 0 30rpx 40rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #2A2A2A;
|
||||
line-height: 40rpx;
|
||||
|
||||
::v-deep p {
|
||||
margin-bottom: 24rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
::v-deep img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
border-radius: 10rpx;
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 50rpx 0 80rpx;
|
||||
|
||||
.empty-icon {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
margin-bottom: 24rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 26rpx;
|
||||
color: #A9A9A9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.recommend-section {
|
||||
padding: 0 30rpx;
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.section-title {
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
line-height: 42rpx;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
|
||||
.refresh-icon {
|
||||
width: 24rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 8rpx;
|
||||
transition: transform 0.5s ease;
|
||||
|
||||
&.is-rotating {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -405,7 +405,7 @@
|
|||
.login {
|
||||
width: 630rpx;
|
||||
height: 96rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
color: #fff;
|
||||
font-size: 40rpx;
|
||||
line-height: 96rpx;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-switch v-model="mainSwitch.switch" activeColor="#FF4767" @change="handleSwitchChange('total',mainSwitch, $event)"></uv-switch>
|
||||
<uv-switch v-model="mainSwitch.switch" activeColor="#E8101E" @change="handleSwitchChange('total',mainSwitch, $event)"></uv-switch>
|
||||
</view>
|
||||
</view>
|
||||
<view class="settings-title" v-if="kindList.length">
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
</view>
|
||||
<view class="card-tip">{{ item.text }}</view>
|
||||
</view>
|
||||
<uv-switch v-model="item.switch" activeColor="#FF4767" @change="handleSwitchChange('branch',item, $event)"></uv-switch>
|
||||
<uv-switch v-model="item.switch" activeColor="#E8101E" @change="handleSwitchChange('branch',item, $event)"></uv-switch>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
|
@ -267,7 +267,7 @@
|
|||
}
|
||||
|
||||
.color-red {
|
||||
color: #FF4767 !important;
|
||||
color: #E8101E !important;
|
||||
}
|
||||
|
||||
/* 弹窗样式 */
|
||||
|
|
@ -324,7 +324,7 @@
|
|||
.dialog-btn {
|
||||
width: 476rpx;
|
||||
height: 86rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 44rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@
|
|||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uv-switch v-model="mainSwitch.switch" activeColor="#FF4767"
|
||||
<uv-switch v-model="mainSwitch.switch" activeColor="#E8101E"
|
||||
@change="handleSwitchChange('total',mainSwitch, $event)"></uv-switch>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
</view>
|
||||
<view class="card-tip">{{ item.text }}</view>
|
||||
</view>
|
||||
<uv-switch v-model="item.switch" activeColor="#FF4767"
|
||||
<uv-switch v-model="item.switch" activeColor="#E8101E"
|
||||
@change="handleSwitchChange('branch',item, $event)"></uv-switch>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -289,7 +289,7 @@
|
|||
}
|
||||
|
||||
.color-red {
|
||||
color: #FF4767 !important;
|
||||
color: #E8101E !important;
|
||||
}
|
||||
|
||||
/* 弹窗样式 */
|
||||
|
|
@ -346,7 +346,7 @@
|
|||
.dialog-btn {
|
||||
width: 476rpx;
|
||||
height: 86rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 44rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -437,7 +437,7 @@
|
|||
width: 300rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 40rpx;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
</view>
|
||||
<view class="card-tip"> 开启语音提示避免落单</view>
|
||||
</view>
|
||||
<uv-switch v-model="value" @change="changeVoice" activeColor="#FF4767"></uv-switch>
|
||||
<uv-switch v-model="value" @change="changeVoice" activeColor="#E8101E"></uv-switch>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
|
@ -292,7 +292,7 @@
|
|||
}
|
||||
|
||||
.color-red {
|
||||
color: #FF4767 !important;
|
||||
color: #E8101E !important;
|
||||
}
|
||||
|
||||
// 弹窗遮罩
|
||||
|
|
@ -348,7 +348,7 @@
|
|||
.dialog-btn {
|
||||
width: 400rpx;
|
||||
height: 88rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 44rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
3346
pages/my/my.vue
3346
pages/my/my.vue
File diff suppressed because it is too large
Load Diff
|
|
@ -1,670 +0,0 @@
|
|||
<template>
|
||||
<view class="collection-page">
|
||||
|
||||
<custom-navbar title="我的收藏" :showBack="true" backgroundColor="#FFFFFF" :show-headle="true" borderBottom="none"
|
||||
headleSrc="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/b18bac2f-3e4c-4586-9d45-0f088629c9d1.png"
|
||||
@onHeadleClick="goToSearch" class="serch-tap">
|
||||
</custom-navbar>
|
||||
|
||||
<view class="tab-bar-wrap" :style="{ top: navHeight + 'px' }">
|
||||
<view class="tab-bar">
|
||||
<view class="tab-items">
|
||||
<view class="tab-item" :class="{ active: currentTab === 'brand' }" @tap="switchTab('brand')">
|
||||
收藏的品牌
|
||||
</view>
|
||||
<view class="tab-item" :class="{ active: currentTab === 'course' }" @tap="switchTab('course')">
|
||||
收藏的课程
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="filter-panel" :class="{ 'show': filterVisible }" :style="{ top: filterTop + 'px' }"
|
||||
catchtouchmove="true">
|
||||
<view class="filter-mask" @tap="closeFilterPanel"></view>
|
||||
<view class="filter-container">
|
||||
|
||||
<scroll-view scroll-y class="filter-scroll" v-if="currentTab === 'brand'">
|
||||
<view class="filter-group" v-for="group in brandFilterData" :key="group.id">
|
||||
<view class="group-title">{{ group.title }}</view>
|
||||
<view class="pill-list">
|
||||
<view class="pill-item" v-for="sub in group.children" :key="sub.id"
|
||||
:class="{ active: selectedSecondIds.includes(sub.id) }" @tap="toggleSecondSelect(sub.id)">
|
||||
{{ sub.title }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view v-else class="course-filter">
|
||||
<view class="course-type-item" :class="{ active: selectedCourseType === 'platform' }"
|
||||
@tap="selectCourseType('platform')">
|
||||
平台课程
|
||||
</view>
|
||||
<view class="course-type-item" :class="{ active: selectedCourseType === 'brand' }"
|
||||
@tap="selectCourseType('brand')">
|
||||
品牌课程
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="filter-footer">
|
||||
<view class="reset-btn" @tap="resetFilter">重置</view>
|
||||
<view class="confirm-btn" @tap="applyFilterAndClose">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="collection-content" v-if="currentTab === 'brand'">
|
||||
<view class="brand-grid" v-if="filteredBrandList.length > 0">
|
||||
<brand-card class="brand-card-wrap" v-for="(item, index) in filteredBrandList" :key="index" :item="item"
|
||||
:tagKeys="item.tagKeys" @click="goToBrandDetail(item)"></brand-card>
|
||||
</view>
|
||||
<view class="empty-state" v-else>
|
||||
<image class="empty-icon"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/da814ede-1adc-4f90-8cdf-5357a12fab27.png">
|
||||
</image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="collection-content" v-else>
|
||||
<view class="course-list" v-if="filteredCourseList.length > 0">
|
||||
<skill-card v-for="(item, index) in filteredCourseList" :key="index" :item="item"></skill-card>
|
||||
</view>
|
||||
<view class="empty-state" v-else>
|
||||
<image class="empty-icon"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/da814ede-1adc-4f90-8cdf-5357a12fab27.png">
|
||||
</image>
|
||||
</view>
|
||||
</view>
|
||||
<view style="height: 120rpx;"></view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BrandCard from "@/pages/home/components/brand-card.vue"
|
||||
import SkillCard from "@/pages/home/components/skill-card.vue"
|
||||
import request from "@/utils/request"
|
||||
|
||||
// 数据模式开关:true=调用真实接口,false=使用模拟数据
|
||||
const USE_REAL_API = true
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BrandCard,
|
||||
SkillCard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
navHeight: 0, // 动态计算的导航栏高度
|
||||
filterTop: 0, // 动态计算的筛选框顶部起点
|
||||
|
||||
currentTab: 'brand',
|
||||
// 筛选相关
|
||||
filterVisible: false,
|
||||
|
||||
// 品牌筛选下拉数据 (合并一级和二级)
|
||||
brandFilterData: [],
|
||||
selectedSecondIds: [], // 选中的二级ID数组
|
||||
|
||||
// 课程筛选
|
||||
selectedCourseType: '', // 'platform' 或 'brand'
|
||||
// 原始数据(收藏的数据)
|
||||
rawBrandList: [],
|
||||
rawCourseList: [],
|
||||
// 展示数据(过滤后)
|
||||
filteredBrandList: [],
|
||||
filteredCourseList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filterIcon() {
|
||||
return this.filterVisible
|
||||
? 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e00ab2ac-bccf-42d8-820c-65727327e279.png'
|
||||
: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/bfe7a104-bef8-4432-9487-42f05e3e9035.png'
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 精准计算吸顶高度与下拉框起点,防止蒙版遮挡白色的Tab区
|
||||
const sysInfo = uni.getSystemInfoSync()
|
||||
const sbh = sysInfo.statusBarHeight || 0
|
||||
this.navHeight = sbh
|
||||
// Tab栏自身的高度大约为 106rpx,转化为 px 叠加上去
|
||||
this.filterTop = this.navHeight + uni.upx2px(106)
|
||||
|
||||
this.loadFilterCategories()
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
// 跳转搜索页
|
||||
goToSearch() {
|
||||
// this.currentTab 的值刚好是 'brand' 或 'course'
|
||||
uni.navigateTo({
|
||||
url: `/pages/search_common/search?type=collection_${this.currentTab}`
|
||||
});
|
||||
},
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
},
|
||||
addAddress() {
|
||||
// 外部方法占位
|
||||
},
|
||||
switchTab(tab) {
|
||||
if (this.currentTab === tab) return
|
||||
this.currentTab = tab
|
||||
// 重置筛选(不同tab筛选条件独立)
|
||||
if (tab === 'brand') {
|
||||
this.resetBrandFilter()
|
||||
} else {
|
||||
this.resetCourseFilter()
|
||||
}
|
||||
this.loadData()
|
||||
this.closeFilterPanel()
|
||||
},
|
||||
// 筛选面板控制
|
||||
toggleFilterPanel() {
|
||||
this.filterVisible = !this.filterVisible
|
||||
},
|
||||
closeFilterPanel() {
|
||||
this.filterVisible = false
|
||||
},
|
||||
|
||||
// 加载一级分类并自动组装其对应的二级分类,兼容 state === 1
|
||||
async loadFilterCategories() {
|
||||
try {
|
||||
const res = await request.post('/sj/firstclass', {})
|
||||
if ((res.code === 200 || res.state === 1) && res.data) {
|
||||
const firstClasses = res.data;
|
||||
|
||||
// 并发请求所有的二级分类
|
||||
const promises = firstClasses.map(async (first) => {
|
||||
try {
|
||||
const subRes = await request.post('/sj/secondclass', { id: first.id })
|
||||
return {
|
||||
id: first.id,
|
||||
title: first.title,
|
||||
children: ((subRes.code === 200 || subRes.state === 1) && subRes.data) ? subRes.data : []
|
||||
}
|
||||
} catch (e) {
|
||||
return { id: first.id, title: first.title, children: [] }
|
||||
}
|
||||
});
|
||||
|
||||
const filterData = await Promise.all(promises);
|
||||
// 过滤掉没有子分类的项,避免面板出现光秃秃的标题
|
||||
this.brandFilterData = filterData.filter(group => group.children.length > 0);
|
||||
} else {
|
||||
this.brandFilterData = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取分类字典失败', error)
|
||||
}
|
||||
},
|
||||
|
||||
toggleSecondSelect(secId) {
|
||||
const index = this.selectedSecondIds.indexOf(secId)
|
||||
if (index === -1) {
|
||||
this.selectedSecondIds.push(secId)
|
||||
} else {
|
||||
this.selectedSecondIds.splice(index, 1)
|
||||
}
|
||||
},
|
||||
// 课程筛选
|
||||
selectCourseType(type) {
|
||||
// 点击已选中的则取消选中
|
||||
if (this.selectedCourseType === type) {
|
||||
this.selectedCourseType = ''
|
||||
} else {
|
||||
this.selectedCourseType = type
|
||||
}
|
||||
},
|
||||
// 重置品牌筛选
|
||||
resetBrandFilter() {
|
||||
this.selectedSecondIds = []
|
||||
this.applyBrandFilter()
|
||||
},
|
||||
resetCourseFilter() {
|
||||
this.selectedCourseType = ''
|
||||
this.applyCourseFilter()
|
||||
},
|
||||
resetFilter() {
|
||||
if (this.currentTab === 'brand') {
|
||||
this.resetBrandFilter()
|
||||
} else {
|
||||
this.resetCourseFilter()
|
||||
}
|
||||
},
|
||||
applyFilterAndClose() {
|
||||
if (this.currentTab === 'brand') {
|
||||
this.applyBrandFilter()
|
||||
} else {
|
||||
this.applyCourseFilter()
|
||||
}
|
||||
this.closeFilterPanel()
|
||||
},
|
||||
// 品牌过滤逻辑(根据二级分类ID相交判断)
|
||||
applyBrandFilter() {
|
||||
if (!this.rawBrandList.length) {
|
||||
this.filteredBrandList = []
|
||||
return
|
||||
}
|
||||
if (this.selectedSecondIds.length === 0) {
|
||||
this.filteredBrandList = [...this.rawBrandList]
|
||||
} else {
|
||||
this.filteredBrandList = this.rawBrandList.filter(brand => {
|
||||
return brand.secondClassIds && brand.secondClassIds.some(id => this.selectedSecondIds.includes(id))
|
||||
})
|
||||
}
|
||||
},
|
||||
// 课程过滤逻辑(根据课程类型)
|
||||
applyCourseFilter() {
|
||||
if (!this.rawCourseList.length) {
|
||||
this.filteredCourseList = []
|
||||
return
|
||||
}
|
||||
if (!this.selectedCourseType) {
|
||||
this.filteredCourseList = [...this.rawCourseList]
|
||||
} else {
|
||||
this.filteredCourseList = this.rawCourseList.filter(course => {
|
||||
if (this.selectedCourseType === 'platform') return course.type === '平台课程'
|
||||
if (this.selectedCourseType === 'brand') return course.type === '品牌课程'
|
||||
return true
|
||||
})
|
||||
}
|
||||
},
|
||||
// 加载原始数据(根据当前Tab)
|
||||
loadData() {
|
||||
if (this.currentTab === 'brand') {
|
||||
this.loadBrandList()
|
||||
} else {
|
||||
this.loadCourseList()
|
||||
}
|
||||
},
|
||||
async loadBrandList() {
|
||||
if (USE_REAL_API) {
|
||||
await this.fetchRealBrandList()
|
||||
} else {
|
||||
this.mockBrandList()
|
||||
}
|
||||
this.applyBrandFilter()
|
||||
},
|
||||
async loadCourseList() {
|
||||
if (USE_REAL_API) {
|
||||
await this.fetchRealCourseList()
|
||||
} else {
|
||||
this.mockCourseList()
|
||||
}
|
||||
this.applyCourseFilter()
|
||||
},
|
||||
|
||||
// ============ 真实接口调用 ============
|
||||
async fetchRealBrandList() {
|
||||
try {
|
||||
// 1. 接口路径换成真实的品牌收藏列表
|
||||
const res = await request.post('/sj/brand/collectList', { page: 1, limit: 100 })
|
||||
|
||||
if ((res.code === 200 || res.state === 1) && res.data && res.data.list) {
|
||||
// 2. 不需要前端再做 filter(item => item.collect_state === 1) 了,直接用!
|
||||
this.rawBrandList = res.data.list.map(item => {
|
||||
let tags = []
|
||||
if (item.franchise_state == 1) tags.push('franchise')
|
||||
if (item.student_state == 1) tags.push('recruit')
|
||||
if (tags.length === 0) tags.push('more')
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
bgSrc: item.cover_img || 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/default.jpg',
|
||||
avatar: item.logo_img || 'https://dummyimage.com/100x100/ccc/fff.png&text=Avatar',
|
||||
tagKeys: tags,
|
||||
// 3. 强制转字符串,防止后端返回纯数字导致 split 报错,同时兼容后端没返回此字段的情况
|
||||
secondClassIds: item.second_class_ids ? String(item.second_class_ids).split(',').map(Number) : []
|
||||
}
|
||||
})
|
||||
console.log('成功获取品牌收藏列表:', this.rawBrandList)
|
||||
} else {
|
||||
this.rawBrandList = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取品牌收藏失败详情:', error)
|
||||
}
|
||||
},
|
||||
async fetchRealCourseList() {
|
||||
try {
|
||||
// 1. 接口路径换成真实的技能收藏列表
|
||||
const res = await request.post('/sj/skill/collectList', { page: 1, limit: 100 })
|
||||
|
||||
if ((res.code === 200 || res.state === 1) && res.data && res.data.list) {
|
||||
// 2. 同样不需要 filter,直接 map 映射数据
|
||||
this.rawCourseList = res.data.list.map(item => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.name,
|
||||
coverSrc: item.cover_img,
|
||||
type: item.link_name || (item.link_type == 1 ? '平台课程' : '品牌课程'),
|
||||
link_type: item.link_type,
|
||||
views: item.browse_num || 0,
|
||||
// 3. 使用安全的时间格式化
|
||||
time: item.create_time ? this.formatTimeAgo(item.create_time) : '',
|
||||
typeIcon: item.link_logo || ''
|
||||
}
|
||||
})
|
||||
console.log('成功获取课程收藏列表:', this.rawCourseList)
|
||||
} else {
|
||||
this.rawCourseList = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取课程收藏失败', error)
|
||||
}
|
||||
},
|
||||
|
||||
formatTimeAgo(timeStr) {
|
||||
if (!timeStr) return '';
|
||||
const timeStrSafe = String(timeStr);
|
||||
const now = new Date()
|
||||
const time = new Date(timeStrSafe.replace(/-/g, '/'))
|
||||
const diff = Math.floor((now - time) / 1000)
|
||||
if (diff < 3600) return Math.floor(diff / 60) + '分钟前'
|
||||
if (diff < 86400) return Math.floor(diff / 3600) + '小时前'
|
||||
if (diff < 604800) return Math.floor(diff / 86400) + '天前'
|
||||
return timeStrSafe.split(' ')[0]
|
||||
},
|
||||
goToBrandDetail(item) {
|
||||
if (item.id) {
|
||||
uni.navigateTo({ url: `/pages/brand/detail?id=${item.id}` })
|
||||
}
|
||||
},
|
||||
|
||||
// ============ 模拟数据兜底 ============
|
||||
mockBrandList() {
|
||||
this.rawBrandList = [
|
||||
{
|
||||
id: 1, name: '脸缘品牌', bgSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg',
|
||||
avatar: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg',
|
||||
tagKeys: ['franchise', 'recruit'], secondClassIds: [76, 77]
|
||||
},
|
||||
{
|
||||
id: 2, name: '美肌工坊', bgSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg',
|
||||
avatar: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg',
|
||||
tagKeys: ['franchise'], secondClassIds: [78]
|
||||
},
|
||||
{
|
||||
id: 3, name: '悦容堂', bgSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg',
|
||||
avatar: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg',
|
||||
tagKeys: ['recruit'], secondClassIds: [201, 202]
|
||||
}
|
||||
]
|
||||
},
|
||||
mockCourseList() {
|
||||
this.rawCourseList = [
|
||||
{ id: 1, title: '穿戴甲的操作视频扫码验券操作教程', coverSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg', type: '平台课程', views: 836000, time: '7小时前' },
|
||||
{ id: 2, title: '全身SPA的操作视频操作教程', coverSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg', type: '平台课程', views: 2344, time: '3天前' },
|
||||
{ id: 3, title: '高级面部护理手法详解', coverSrc: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e2220528-fdf6-4cad-a25d-ec6cbee1501e.jpg', type: '品牌课程', views: 56700, time: '1周前' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.collection-page {
|
||||
min-height: 100vh;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 将页面左右 padding 转移到内容区,保证 Tab 背景贯穿全屏 */
|
||||
.tab-bar-wrap {
|
||||
position: sticky;
|
||||
/* 吸顶,保证滑动页面时一直显示在最前面 */
|
||||
background: #fff;
|
||||
padding: 10rpx 24rpx;
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: transparent;
|
||||
padding: 10rpx 0;
|
||||
|
||||
.tab-items {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.tab-item {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #777777;
|
||||
background: #f5f5f5;
|
||||
border-radius: 27rpx;
|
||||
margin-right: 40rpx;
|
||||
padding: 9rpx 24rpx;
|
||||
|
||||
&.active {
|
||||
color: #FF4767;
|
||||
background: #FFECEF;
|
||||
border: 2rpx solid #FFB0BD;
|
||||
border-radius: 29rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10rpx 0;
|
||||
|
||||
.filter-text {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
margin-right: 6rpx;
|
||||
}
|
||||
|
||||
.filter-icon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
|
||||
/* 展开时切换为上下箭头图标,调整大小 */
|
||||
&.rotate {
|
||||
width: 18rpx;
|
||||
height: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 核心抽屉动画布局 */
|
||||
.filter-panel {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
/* 低于 Tab区的101,保证隐藏时躲在其后 */
|
||||
pointer-events: none;
|
||||
/* 面板关闭时,穿透点击到底部列表 */
|
||||
overflow: hidden;
|
||||
/* 防止抽屉向上滑出时外溢 */
|
||||
|
||||
&.show {
|
||||
pointer-events: auto;
|
||||
|
||||
/* 打开时恢复点击拦截 */
|
||||
.filter-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
transform: translateY(50rpx);
|
||||
/* 滑出 */
|
||||
}
|
||||
}
|
||||
|
||||
.filter-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border-radius: 0 0 30rpx 30rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
max-height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.05);
|
||||
transform: translateY(-100%);
|
||||
/* 默认隐藏在上方(即Tab背后) */
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 垂直分组设计的样式(图3) */
|
||||
.filter-scroll {
|
||||
max-height: 50vh;
|
||||
}
|
||||
|
||||
.filter-group {
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.group-title {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.pill-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/* 通用胶囊按钮 */
|
||||
.pill-item {
|
||||
width: calc(25% - 16rpx);
|
||||
/* 25%是一行四个,减去间距 */
|
||||
height: 58rpx;
|
||||
background: #F5F5F5;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
line-height: 37rpx;
|
||||
|
||||
/* 使用 flex 居中 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: 12rpx;
|
||||
box-sizing: border-box;
|
||||
/* 防止 padding 会撑大盒子 */
|
||||
|
||||
&.active {
|
||||
background: #FFF0F2;
|
||||
color: #FF4767;
|
||||
border: 1rpx solid #FFB0BD;
|
||||
}
|
||||
}
|
||||
|
||||
.course-filter {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
/* padding: 20rpx 0 40rpx; */
|
||||
|
||||
.course-type-item {
|
||||
background: #F5F5F5;
|
||||
color: #666666;
|
||||
font-size: 26rpx;
|
||||
padding: 12rpx 40rpx;
|
||||
border-radius: 12rpx;
|
||||
|
||||
&.active {
|
||||
background: #FFF0F2;
|
||||
color: #FF4767;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
/* border-top: 1rpx solid #F5F5F5; */
|
||||
|
||||
.reset-btn,
|
||||
.confirm-btn {
|
||||
width: 47%;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
border-radius: 40rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background: #F5F5F5;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background: #FF4767;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 内容区缩进补充 */
|
||||
.collection-content {
|
||||
padding: 0 24rpx 24rpx;
|
||||
margin-top: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.brand-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
.brand-card-wrap {
|
||||
width: 49.2%;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.course-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
|
||||
.empty-icon {
|
||||
width: 346rpx;
|
||||
height: 373rpx;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .icon-headle {
|
||||
width: 36rpx !important;
|
||||
height: 36rpx !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -400,7 +400,7 @@ export default {
|
|||
left: 60rpx;
|
||||
width: 630rpx;
|
||||
height: 96rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 58rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -499,7 +499,7 @@ export default {
|
|||
}
|
||||
|
||||
.region-tab.active {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -511,7 +511,7 @@ export default {
|
|||
transform: translateX(-50%);
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
|
||||
|
|
@ -552,7 +552,7 @@ export default {
|
|||
}
|
||||
|
||||
.popup-btn.confirm {
|
||||
background: linear-gradient(90deg, #FF4767 0%, #FF618F 100%);
|
||||
background: linear-gradient(90deg, #E8101E 0%, #FF618F 100%);
|
||||
}
|
||||
|
||||
.popup-btn .btn-text {
|
||||
|
|
|
|||
|
|
@ -1,356 +0,0 @@
|
|||
<template>
|
||||
<view class="notice-detail-page">
|
||||
<!-- 自定义顶部导航组件 -->
|
||||
<custom-navbar
|
||||
title="公告通知详情"
|
||||
:showBack="true"
|
||||
backgroundColor="linear-gradient(180deg, #E6ECFB 0%, #FFFFFF 100%)"
|
||||
:showHeadle="true"
|
||||
borderBottom="none"
|
||||
/>
|
||||
|
||||
<!-- 页面主要内容 -->
|
||||
<view class="page-content">
|
||||
<!-- 加载状态 -->
|
||||
<view v-if="loading" class="loading-container">
|
||||
<view class="loading-icon"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 详情内容 -->
|
||||
<view v-else-if="detailData.id" class="detail-card">
|
||||
<!-- 标题 -->
|
||||
<text class="detail-title">{{ detailData.title }}</text>
|
||||
|
||||
<!-- 发布时间 -->
|
||||
<view class="detail-time">
|
||||
<text class="time-text">时间:{{ formatTime(detailData.create_time) }}</text>
|
||||
<text class="browse-text"> <image class="browse-icon" src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/6133cbef-5861-40f8-80f5-d8a86477c94f.png" mode="aspectFit"></image> {{ detailData.browse_num }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 富文本内容 -->
|
||||
<view class="detail-content">
|
||||
<rich-text :nodes="detailData.content"></rich-text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态或错误 -->
|
||||
<view v-else-if="!loading && !detailData.id" class="empty-container">
|
||||
<image class="empty-img" src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/8c5e7b2a-3d4f-4b1e-9a7c-6e8f2d1b4a5c.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">公告不存在或已删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CustomNavbar from '@/components/custom-navbar/custom-navbar.vue';
|
||||
import request from '@/utils/request';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CustomNavbar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false, // 加载状态
|
||||
detailData: { // 公告详情数据
|
||||
id: null,
|
||||
title: '',
|
||||
create_time: '',
|
||||
content: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
const id = options.id;
|
||||
if (id) {
|
||||
this.fetchNoticeDetail(id);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '参数错误',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取公告详情
|
||||
fetchNoticeDetail(id) {
|
||||
this.loading = true;
|
||||
request.post('/sj/notice/details', { id: id })
|
||||
.then(res => {
|
||||
if (res.code === 200 && res.data) {
|
||||
this.detailData = res.data;
|
||||
// 动态设置页面标题(可选)
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.detailData.title || '公告详情'
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg || '获取详情失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('获取公告详情失败:', err);
|
||||
uni.showToast({
|
||||
title: '网络异常,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
formatTime(timeStr) {
|
||||
if (!timeStr) return '--:--:--';
|
||||
let formatted = timeStr;
|
||||
if (timeStr.includes('.') && !timeStr.includes('-')) {
|
||||
const match = timeStr.match(/(\d{4})\.(\d{2})\.(\d{2})(\d{2}:\d{2}:\d{2})/);
|
||||
if (match) {
|
||||
formatted = `${match[1]}-${match[2]}-${match[3]} ${match[4]}`;
|
||||
} else {
|
||||
formatted = timeStr.replace(/\./g, '-');
|
||||
}
|
||||
}
|
||||
// 如果是标准格式直接返回,否则返回原字符串
|
||||
if (formatted.includes('-') && formatted.includes(':')) {
|
||||
// 转换回点分隔显示,以匹配设计图风格: 2026.05.08 15:00:00
|
||||
const datePart = formatted.split(' ')[0];
|
||||
const timePart = formatted.split(' ')[1] || '';
|
||||
if (datePart && datePart.includes('-')) {
|
||||
const dotDate = datePart.replace(/-/g, '.');
|
||||
return `${dotDate} ${timePart}`.trim();
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
return timeStr;
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notice-detail-page {
|
||||
min-height: 100vh;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
// padding: 20rpx 24rpx 60rpx;
|
||||
}
|
||||
|
||||
// 加载状态
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
|
||||
.loading-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #e0e0e0;
|
||||
border-top-color: #FF4767;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// 详情卡片
|
||||
.detail-card {
|
||||
background: #ffffff;
|
||||
border-radius: 24rpx;
|
||||
padding: 20rpx 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.detail-title {
|
||||
display: block;
|
||||
margin-bottom: 14rpx;
|
||||
font-weight: 500;
|
||||
font-size: 40rpx;
|
||||
color: #333333;
|
||||
line-height: 56rpx;
|
||||
}
|
||||
|
||||
.detail-time {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
justify-content: space-between; // 两端对齐
|
||||
// border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
.time-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 10rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.time-text {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B6B6B6;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
.browse-icon {
|
||||
width: 38rpx;
|
||||
height: 22rpx;
|
||||
// margin-right: 10rpx;
|
||||
}
|
||||
.browse-text {
|
||||
margin-right: 10rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B08463;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #2A2A2A;
|
||||
line-height: 40rpx;
|
||||
overflow-x: hidden;
|
||||
|
||||
// 对rich-text内部样式进行补充
|
||||
::v-deep img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin: 30rpx 0;
|
||||
}
|
||||
|
||||
::v-deep p {
|
||||
margin-bottom: 20rpx; // 重置外边距,避免多余间距
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// 在需要分段的地方手动创建间距
|
||||
::v-deep br {
|
||||
display: block; // 让 <br> 标签表现正常
|
||||
margin-bottom: 30rpx; // 控制段落间距
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 空状态
|
||||
.empty-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 150rpx 0;
|
||||
|
||||
.empty-img {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
// 底部会员营销卡片(根据设计图样式)
|
||||
.member-card {
|
||||
background: linear-gradient(135deg, #FFE6E8 0%, #FFF0E6 100%);
|
||||
border-radius: 24rpx;
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 20rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||
|
||||
.member-info {
|
||||
flex: 1;
|
||||
|
||||
.member-price {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #FF4767;
|
||||
line-height: 44rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.member-desc {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
line-height: 34rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.member-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.tag-text, .tag-gift {
|
||||
font-size: 20rpx;
|
||||
background: rgba(255, 71, 103, 0.15);
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 20rpx;
|
||||
color: #FF4767;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.tag-gift {
|
||||
background: rgba(255, 193, 7, 0.2);
|
||||
color: #E6A100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.member-btn {
|
||||
background: linear-gradient(135deg, #FF4767, #FF6B8A);
|
||||
border-radius: 48rpx;
|
||||
padding: 14rpx 28rpx;
|
||||
text-align: center;
|
||||
min-width: 160rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(255, 71, 103, 0.3);
|
||||
|
||||
.btn-text {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #FFFFFF;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
|
||||
.btn-sub {
|
||||
display: block;
|
||||
font-size: 20rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
::v-deep .icon-headle {
|
||||
width: 32rpx !important;
|
||||
height: 32rpx !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
<template>
|
||||
<view class="notice-page">
|
||||
<!-- 自定义顶部导航组件 -->
|
||||
<custom-navbar title="公告通知" :showBack="true" backgroundColor="#FFFFFF" :show-headle="true"
|
||||
headleSrc="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/51ebca5d-95c5-4fb8-8aa3-560a79100d25.png"
|
||||
@onHeadleClick="goToSearch" class="nav-img-size" />
|
||||
|
||||
<view class="page-content">
|
||||
<!-- 加载状态 -->
|
||||
<view v-if="loading" class="loading-container">
|
||||
<view class="loading-icon"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 公告列表 -->
|
||||
<view v-else-if="noticeList.length > 0" class="notice-list">
|
||||
<NoticeCard v-for="item in noticeList" :key="item.id" :item="item" @click="goToDetail" />
|
||||
|
||||
<!-- 加载更多状态 -->
|
||||
<view v-if="loadingMore" class="load-more">
|
||||
<text>加载更多...</text>
|
||||
</view>
|
||||
<view v-else-if="!hasMore && noticeList.length > 0" class="no-more">
|
||||
<text>没有更多了</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 空状态 -->
|
||||
<view v-else class="empty-container">
|
||||
<image class="empty-img"
|
||||
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/8c5e7b2a-3d4f-4b1e-9a7c-6e8f2d1b4a5c.png"
|
||||
mode="aspectFit"></image>
|
||||
<text class="empty-text">暂无公告通知</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CustomNavbar from '@/components/custom-navbar/custom-navbar.vue';
|
||||
import NoticeCard from '@/pages/home/components/notice-card.vue';
|
||||
import request from '@/utils/request';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CustomNavbar,
|
||||
NoticeCard // 注册组件
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
loadingMore: false,
|
||||
noticeList: [],
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
hasMore: true
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
this.fetchNoticeList(true);
|
||||
},
|
||||
onPullDownRefresh() {
|
||||
this.fetchNoticeList(true);
|
||||
},
|
||||
onReachBottom() {
|
||||
if (!this.loadingMore && this.hasMore && !this.loading) {
|
||||
this.fetchNoticeList(false);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 跳转搜索页
|
||||
goToSearch() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/search_common/search?type=notice'
|
||||
});
|
||||
},
|
||||
|
||||
// 获取公告列表
|
||||
fetchNoticeList(reset = true) {
|
||||
if (reset) {
|
||||
this.page = 1;
|
||||
this.hasMore = true;
|
||||
this.loading = true;
|
||||
} else {
|
||||
if (!this.hasMore) return;
|
||||
this.loadingMore = true;
|
||||
// 非重置时页码+1
|
||||
this.page++;
|
||||
}
|
||||
|
||||
request.post('/sj/notice/list', {
|
||||
page: this.page,
|
||||
limit: this.limit
|
||||
}).then(res => {
|
||||
if (res.code === 200 && res.data) {
|
||||
const list = res.data.list || [];
|
||||
const total = res.data.total || 0;
|
||||
this.total = total;
|
||||
|
||||
if (reset) {
|
||||
this.noticeList = list;
|
||||
} else {
|
||||
this.noticeList = [...this.noticeList, ...list];
|
||||
}
|
||||
|
||||
// 判断是否还有更多数据
|
||||
this.hasMore = this.noticeList.length < total;
|
||||
} else {
|
||||
if (reset) this.noticeList = [];
|
||||
this.hasMore = false;
|
||||
// 非重置且请求失败时回滚页码
|
||||
if (!reset && this.page > 1) this.page--;
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('获取公告列表失败:', err);
|
||||
if (!reset && this.page > 1) this.page--; // 回滚页码
|
||||
uni.showToast({
|
||||
title: '加载失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
this.loadingMore = false;
|
||||
if (reset) {
|
||||
uni.stopPullDownRefresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到详情页(接收 NoticeCard 组件 $emit 传递的 item)
|
||||
goToDetail(item) {
|
||||
if (item.id) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/notice/detail?id=${item.id}`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notice-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f6f8;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
padding: 20rpx 20rpx 40rpx;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
|
||||
.loading-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #e0e0e0;
|
||||
border-top-color: #FF4767;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.load-more,
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 150rpx 0;
|
||||
|
||||
.empty-img {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-img-size::v-deep .icon-headle {
|
||||
width: 36rpx !important;
|
||||
height: 36rpx !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -275,18 +275,18 @@ export default {
|
|||
|
||||
.rating-score {
|
||||
font-size: 16rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
margin-left: 68rpx;
|
||||
}
|
||||
|
||||
.currency {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 32rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
@ -328,7 +328,7 @@ export default {
|
|||
}
|
||||
.load-date {
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.load-text {
|
||||
|
|
|
|||
|
|
@ -146,6 +146,9 @@
|
|||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -713,7 +716,7 @@ page {
|
|||
.real-price {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
/* 订单信息卡片 */
|
||||
.order-card {
|
||||
|
|
@ -785,13 +788,13 @@ page {
|
|||
margin-left: 20rpx;
|
||||
}
|
||||
.btn-border {
|
||||
border: 1rpx solid #FF4767;
|
||||
border: 1rpx solid #E8101E;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
.btn-bg {
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
}
|
||||
.button-text {
|
||||
font-size: 28rpx;
|
||||
|
|
@ -801,7 +804,7 @@ page {
|
|||
.btn-border .button-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
/* APP适配 */
|
||||
/* #ifdef APP-PLUS */
|
||||
|
|
@ -824,4 +827,4 @@ page {
|
|||
padding-top: calc(var(--status-bar-height) + env(safe-area-inset-top));
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<image :src="item.icon" mode="aspectFit" class="method-icon"></image>
|
||||
<text class="method-name">{{ item.name }}</text>
|
||||
</view>
|
||||
<agree-radio :isAgree="item.selected" :yesImg="`/static/images/agree_y.png`" :radioSize="`40rpx`" :noImg="`/static/images/icons/no_icon.png`"></agree-radio>
|
||||
<agree-radio :isAgree="item.selected" :yesImg="`/static/images/icons/yes_icon.png`" :radioSize="`40rpx`" :noImg="`/static/images/icons/no_icon.png`"></agree-radio>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -494,7 +494,7 @@
|
|||
::v-deep .uv-count-down__text {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #FF4767;;
|
||||
color: #E8101E;;
|
||||
line-height: 37rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
|
|
@ -559,13 +559,13 @@
|
|||
.total-amount .symbol {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.total-amount .amount {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.amount-lable {
|
||||
|
|
@ -576,7 +576,7 @@
|
|||
.pay-btn {
|
||||
width: 680rpx;
|
||||
height: 88rpx;
|
||||
background: linear-gradient( 180deg, #F52540 0%, #FF4767 100%);
|
||||
background: linear-gradient( 180deg, #F52540 0%, #E8101E 100%);
|
||||
border-radius: 43rpx;
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
|
|
|
|||
|
|
@ -623,7 +623,7 @@ export default {
|
|||
height: 28rpx;
|
||||
border: 3rpx;
|
||||
margin-right: 16rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
}
|
||||
|
||||
.service-item {
|
||||
|
|
@ -766,7 +766,7 @@ export default {
|
|||
.price-total .price {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.amount-lable {
|
||||
|
|
@ -777,7 +777,7 @@ export default {
|
|||
.submit-btn {
|
||||
width: 492rpx;
|
||||
height: 64rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 32rpx;
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
|
|
@ -984,8 +984,8 @@ export default {
|
|||
.isActive {
|
||||
background: rgba(252, 67, 124, 0.08);
|
||||
border-radius: 10rpx;
|
||||
border: 1rpx solid #FF4767;
|
||||
color: #FF4767;
|
||||
border: 1rpx solid #E8101E;
|
||||
color: #E8101E;
|
||||
/* 选中状态 */
|
||||
}
|
||||
|
||||
|
|
@ -1010,7 +1010,7 @@ export default {
|
|||
&__box {
|
||||
width: 648rpx;
|
||||
height: 94rpx;
|
||||
background: linear-gradient(140deg, #fa4e9a 0%, #FF4767 100%);
|
||||
background: linear-gradient(140deg, #fa4e9a 0%, #E8101E 100%);
|
||||
border-radius: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<view class="group-invite"
|
||||
v-if="orderInfo.state !=1 && orderInfo.team_buy_id && (orderInfo.team_buy_order_state==1||orderInfo.team_buy_order_state==2)">
|
||||
<view class="invite-text" v-if="orderInfo.team_buy_order_state == 1">参团成功,需邀请<text
|
||||
style="color: #FF4767">{{orderInfo.team_buy.person_num - orderInfo.team_buy.pay_person_num}}</text>人才可完成拼团
|
||||
style="color: #E8101E">{{orderInfo.team_buy.person_num - orderInfo.team_buy.pay_person_num}}</text>人才可完成拼团
|
||||
</view>
|
||||
<view class="invite-text" v-if="orderInfo.team_buy_order_state == 2">参团成功,已拼团成功!</view>
|
||||
|
||||
|
|
@ -266,16 +266,16 @@
|
|||
formatPriceNumber(this.orderInfo.cost_money-this.orderInfo.order_money),
|
||||
18,
|
||||
2
|
||||
)}rpx;color: #FF4767;line-height: 25rpx;text-align: left;font-style: normal;`" />
|
||||
)}rpx;color: #E8101E;line-height: 25rpx;text-align: left;font-style: normal;`" />
|
||||
</l-painter-view>
|
||||
<l-painter-view css="margin-top:44rpx;">
|
||||
<l-painter-text text="¥"
|
||||
css="font-weight: 500;font-size: 26rpx;color: #FF4767;line-height: 48rpx;text-align: left;font-style: normal;" />
|
||||
css="font-weight: 500;font-size: 26rpx;color: #E8101E;line-height: 48rpx;text-align: left;font-style: normal;" />
|
||||
<l-painter-text :text=" formatPriceNumber(this.orderInfo.order_money)" :css="`font-weight: 500;font-size:${formatPriceSize(
|
||||
formatPriceNumber(this.orderInfo.order_money),
|
||||
56,
|
||||
3
|
||||
)}rpx;color: #FF4767;line-height: 34rpx;text-align: left;font-style: normal;`" />
|
||||
)}rpx;color: #E8101E;line-height: 34rpx;text-align: left;font-style: normal;`" />
|
||||
</l-painter-view>
|
||||
<l-painter-view css="margin-top:0rpx;">
|
||||
<l-painter-text :text="`原价¥${formatPriceNumber(this.orderInfo.cost_money)}`" :css="`text-decoration: line-through;font-weight: 400;font-size:${formatPriceSize(
|
||||
|
|
@ -1005,7 +1005,7 @@
|
|||
.phone-btn {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
border-radius: 32rpx;
|
||||
}
|
||||
|
||||
|
|
@ -1249,7 +1249,7 @@
|
|||
.service-price2 {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 34rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -1282,7 +1282,7 @@
|
|||
font-family: DINPro, DINPro;
|
||||
font-weight: 500;
|
||||
font-size: 36rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 34rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -1352,7 +1352,7 @@
|
|||
}
|
||||
|
||||
.btn-bg {
|
||||
background-color: #FF4767;
|
||||
background-color: #E8101E;
|
||||
}
|
||||
|
||||
.button-text {
|
||||
|
|
@ -1444,7 +1444,7 @@
|
|||
align-items: center;
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -15,7 +15,7 @@
|
|||
<view>
|
||||
<view class="serve-card-right__content__title">{{item.title}}</view>
|
||||
<view class="serve-card-right__content__price"><text
|
||||
style="color: #FF4767;font-weight: 500;">¥{{item.server_price}} </text> {{' '}}|
|
||||
style="color: #E8101E;font-weight: 500;">¥{{item.server_price}} </text> {{' '}}|
|
||||
{{item.server_time}}分钟
|
||||
</view>
|
||||
</view>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
<text class="service-name">{{ item.server_title }}</text>
|
||||
<text class="order-time">下单时间:{{ item.pay_time }}</text>
|
||||
<text class="order-status">
|
||||
订单状态:<text style="color: #FF4767;">{{ getDescriptionByNumber(item.state) }}</text>
|
||||
订单状态:<text style="color: #E8101E;">{{ getDescriptionByNumber(item.state) }}</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<view class="promotion">
|
||||
<custom-navbar title="推广服务" :leftImg="'/static/images/whiteBack.png'" :showUser="true"
|
||||
backgroundColor="linear-gradient( 134deg, #F52540 0%, #FF4767 100%)" titleColor="#fff"
|
||||
backgroundColor="linear-gradient( 134deg, #F52540 0%, #E8101E 100%)" titleColor="#fff"
|
||||
borderBottom="none"></custom-navbar>
|
||||
<view class="promotion-search">
|
||||
<view class="promotion-add">
|
||||
|
|
@ -224,7 +224,7 @@
|
|||
<style lang="less">
|
||||
.promotion {
|
||||
.promotion-search {
|
||||
background: linear-gradient(134deg, #f52540 0%, #FF4767 100%);
|
||||
background: linear-gradient(134deg, #f52540 0%, #e8101e 100%);
|
||||
box-sizing: border-box;
|
||||
padding: 31rpx 20rpx 60rpx 20rpx;
|
||||
|
||||
|
|
@ -292,7 +292,7 @@
|
|||
position: relative;
|
||||
|
||||
&.active {
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
|
|
@ -325,7 +325,7 @@
|
|||
width: 100%;
|
||||
font-weight: 400;
|
||||
font-size: 22rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 30rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -374,7 +374,7 @@
|
|||
border: 1rpx solid rgba(232, 16, 30, 0.2);
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 33rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -398,7 +398,7 @@
|
|||
font-family: DINPro, DINPro;
|
||||
font-weight: 500;
|
||||
font-size: 36rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 46rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -468,12 +468,12 @@
|
|||
}
|
||||
|
||||
.closeModal {
|
||||
border: 2rpx solid #FF4767;
|
||||
color: #FF4767;
|
||||
border: 2rpx solid #E8101E;
|
||||
color: #E8101E;
|
||||
}
|
||||
|
||||
.sureModal {
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 40rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<view class="select-serve">
|
||||
<custom-navbar title="选择服务" backgroundColor="#FFFFFF"></custom-navbar>
|
||||
<view class="select-tip">
|
||||
<text style="color: #FF4767;">温馨提示:</text>您可自主勾选需推广的服务,灵活设置「比例」形式的推广佣金;
|
||||
<text style="color: #E8101E;">温馨提示:</text>您可自主勾选需推广的服务,灵活设置「比例」形式的推广佣金;
|
||||
配置完成后,服务将自动进入推广平台曝光,触达更多潜在客户;后续通过推广渠道(如达人链接、分享码)成功成交的订单,
|
||||
系统会从该笔订单中,自动扣除您预设的佣金,全程无需手动操作。
|
||||
</view>
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
&__btn {
|
||||
width: 690rpx;
|
||||
height: 78rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 798rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<view class="select-serve">
|
||||
<custom-navbar title="设置佣金" backgroundColor="#FFFFFF"></custom-navbar>
|
||||
<view class="select-tip">
|
||||
<text style="color: #FF4767;">温馨提示:</text>支持 按1%~30%区间设置佣金比例,订单成功成交后,系统将按实付金额 × 佣金比例自动扣减。
|
||||
<text style="color: #E8101E;">温馨提示:</text>支持 快速设置“百分比”(如每单返 2%)佣金,成功成交的订单,系统会按照实付金额*佣金比例进行扣减。
|
||||
</view>
|
||||
<view v-for="(item,index) in selectedItems" :key="index" class="serve-card">
|
||||
<image :src="item.photo[0]" mode="aspectFill" class="serve-card__img"></image>
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
<uv-modal ref="modal" title="提示" width="620rpx">
|
||||
<view class="slot-content">
|
||||
预估佣金按<text style="color: #FF4767;">「订单实付金额 × 佣金比例」</text>计算。因服务实付金额受活动参与程度影响存在波动,最终佣金以订单实际结算结果为准。
|
||||
预估佣金按<text style="color: #E8101E;">「订单实付金额 × 佣金比例」</text>计算。因服务实付金额受活动参与程度影响存在波动,最终佣金以订单实际结算结果为准。
|
||||
</view>
|
||||
<template v-slot:confirmButton>
|
||||
<view type="default" @click="closeModal" class="closeModal">确定</view>
|
||||
|
|
@ -271,7 +271,7 @@
|
|||
font-family: DINPro, DINPro;
|
||||
font-weight: 500;
|
||||
font-size: 22rpx;
|
||||
color: #FF4767;
|
||||
color: #E8101E;
|
||||
line-height: 34rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
|
@ -328,7 +328,7 @@
|
|||
&__btn {
|
||||
width: 690rpx;
|
||||
height: 78rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 798rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -347,7 +347,7 @@
|
|||
.closeModal {
|
||||
width: 556rpx;
|
||||
height: 80rpx;
|
||||
background: #FF4767;
|
||||
background: #E8101E;
|
||||
border-radius: 40rpx;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue