Compare commits
14 Commits
e301ddc6ec
...
custom/272
| Author | SHA1 | Date | |
|---|---|---|---|
| 40d411c57a | |||
| b079487c9a | |||
| ef7b609efb | |||
| 7a28bb7f7a | |||
| 921e8b79b1 | |||
| 0101c36012 | |||
| 469bc4da81 | |||
| 50072c45ab | |||
| c790d63005 | |||
| 71c866c0f8 | |||
| a5740f53af | |||
| 8f0a13c473 | |||
| 6d0c914e79 | |||
| 3fec0470cf |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,4 +2,3 @@
|
||||
/.hbuilderx
|
||||
/.idea
|
||||
/node_modules
|
||||
/iconfont-preview.html
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// 本地调试配置示例文件
|
||||
// 复制此文件并重命名为 local.config.js 以使用自定义本地配置
|
||||
|
||||
const localDevConfig = ({
|
||||
'460': { // 制氧设备平台
|
||||
uniacid: 460,
|
||||
domain: 'https://xcx30.5g-quickapp.com/',
|
||||
},
|
||||
'576-xcx30.5g': { // 活性石灰装备
|
||||
uniacid: 576,
|
||||
domain: 'https://xcx30.5g-quickapp.com/',
|
||||
},
|
||||
'2285': { // 数码喷墨墨水
|
||||
uniacid: 2285,
|
||||
domain: 'https://xcx.aigc-quickapp.com/',
|
||||
},
|
||||
'2811': { // POCT检测分析平台
|
||||
uniacid: 2811,
|
||||
domain: 'https://xcx6.aigc-quickapp.com/',
|
||||
},
|
||||
'2724': { // 生物菌肥
|
||||
uniacid: 2724,
|
||||
domain: 'https://xcx.aigc-quickapp.com/',
|
||||
},
|
||||
'2505': { // 煤矿钻机
|
||||
uniacid: 2505,
|
||||
domain: 'https://xcx.aigc-quickapp.com/',
|
||||
},
|
||||
'2777': { // 养老服务
|
||||
uniacid: 2777,
|
||||
domain: 'https://xcx.aigc-quickapp.com/',
|
||||
},
|
||||
'1': { // 开发平台
|
||||
uniacid: 1,
|
||||
domain: 'https://dev.aigc-quickapp.com',
|
||||
},
|
||||
'1-test': { // 测试平台
|
||||
uniacid: 1,
|
||||
domain: 'https://test.aigc-quickapp.com',
|
||||
},
|
||||
'local-2': { // 测试平台
|
||||
uniacid: 2,
|
||||
domain: 'http://localhost:8050/',
|
||||
},
|
||||
})['1']; // 选择要使用的环境配置
|
||||
|
||||
export default localDevConfig;
|
||||
@@ -6,34 +6,10 @@ const localDevConfig = ({
|
||||
uniacid: 460,
|
||||
domain: 'https://xcx30.5g-quickapp.com/',
|
||||
},
|
||||
'576-xcx30.5g': { // 活性石灰装备
|
||||
uniacid: 576,
|
||||
domain: 'https://xcx30.5g-quickapp.com/',
|
||||
},
|
||||
'2285': { // 数码喷墨墨水
|
||||
uniacid: 2285,
|
||||
domain: 'https://xcx.aigc-quickapp.com/',
|
||||
},
|
||||
'2811': { // POCT检测分析平台
|
||||
uniacid: 2811,
|
||||
domain: 'https://xcx6.aigc-quickapp.com/',
|
||||
},
|
||||
'2812': { // IVD数商模式
|
||||
uniacid: 2812,
|
||||
domain: 'https://xcx6.aigc-quickapp.com/',
|
||||
},
|
||||
'2724': { // 生物菌肥
|
||||
uniacid: 2724,
|
||||
domain: 'https://xcx.aigc-quickapp.com/',
|
||||
},
|
||||
'2505': { // 煤矿钻机
|
||||
uniacid: 2505,
|
||||
domain: 'https://xcx.aigc-quickapp.com/',
|
||||
},
|
||||
'2777': { // 养老服务
|
||||
uniacid: 2777,
|
||||
domain: 'https://xcx.aigc-quickapp.com/',
|
||||
},
|
||||
'1': { // 开发平台
|
||||
uniacid: 1,
|
||||
domain: 'https://dev.aigc-quickapp.com',
|
||||
@@ -42,14 +18,6 @@ const localDevConfig = ({
|
||||
uniacid: 1,
|
||||
domain: 'https://test.aigc-quickapp.com',
|
||||
},
|
||||
'local-2': { // 测试平台
|
||||
uniacid: 2,
|
||||
domain: 'http://localhost:8050/',
|
||||
},
|
||||
'local-2-dev': { // 本地开发测试平台
|
||||
uniacid: 2,
|
||||
domain: 'http://localhost:8050/',
|
||||
},
|
||||
})['2812']; // 选择要使用的环境配置
|
||||
})['2285']; // 选择要使用的环境配置
|
||||
|
||||
export default localDevConfig;
|
||||
9
App.vue
9
App.vue
@@ -8,7 +8,7 @@
|
||||
|
||||
export default {
|
||||
mixins: [auth],
|
||||
onLaunch: async function(options) {
|
||||
onLaunch: function(options) {
|
||||
// 方式:支持快应用,从url中query部分获取uniacid,或useragent中获取uniacid
|
||||
if(options.query.uniacid){
|
||||
uni.setStorageSync('uniacid', options.query.uniacid);
|
||||
@@ -40,7 +40,7 @@
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
if (this.$util.getDeviceInfo().platform == 'ios') {
|
||||
if (uni.getSystemInfoSync().platform == 'ios') {
|
||||
uni.setStorageSync('initUrl', location.href);
|
||||
}
|
||||
// #endif
|
||||
@@ -61,8 +61,7 @@
|
||||
|
||||
// 主题风格
|
||||
if (uni.getStorageSync('themeStyle')) {
|
||||
const themeData = await configExternal.loadTheme(uni.getStorageSync('themeStyle'));
|
||||
this.$store.commit('setThemeStyle', themeData);
|
||||
this.$store.commit('setThemeStyle', configExternal.loadThemeSync(uni.getStorageSync('themeStyle')));
|
||||
this.$store.dispatch('themeColorSet');
|
||||
}
|
||||
|
||||
@@ -314,7 +313,7 @@
|
||||
@import './common/css/iconfont.css';
|
||||
@import './common/css/icondiy.css'; // 自定义图标库
|
||||
@import './common/css/icon/extend.css'; // 扩展图标库
|
||||
page {
|
||||
page{
|
||||
background: #f4f6fa;
|
||||
}
|
||||
</style>
|
||||
@@ -123,7 +123,7 @@ image {
|
||||
}
|
||||
|
||||
.choose-store {
|
||||
::v-deep .uni-popup__wrapper{
|
||||
/deep/ .uni-popup__wrapper{
|
||||
background: none!important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,13 +870,13 @@
|
||||
// 海报
|
||||
// .uni-popup__wrapper-box
|
||||
.poster-layer {
|
||||
::v-deep .uni-popup__wrapper.center {
|
||||
/deep/ .uni-popup__wrapper.center {
|
||||
width: 100vw!important;
|
||||
height: 100vh!important;
|
||||
background: none!important;
|
||||
}
|
||||
|
||||
::v-deep .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
/deep/ .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
max-width: 100vw!important;
|
||||
max-height: 100vh!important;
|
||||
background: none!important;
|
||||
|
||||
@@ -559,7 +559,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar {
|
||||
/deep/::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
@@ -609,7 +609,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
font-weight: 500!important;
|
||||
}
|
||||
|
||||
::v-deep .reward-popup .uni-popup__wrapper-box {
|
||||
/deep/ .reward-popup .uni-popup__wrapper-box {
|
||||
background: none !important;
|
||||
max-width: unset !important;
|
||||
max-height: unset !important;
|
||||
@@ -618,7 +618,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
|
||||
// #ifdef H5
|
||||
// 下拉加载动画【页面】
|
||||
::v-deep body uni-page-refresh div{
|
||||
/deep/ body uni-page-refresh div{
|
||||
width: 14rpx !important;
|
||||
height: 14rpx !important;
|
||||
background-color: #ccc;
|
||||
@@ -626,7 +626,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
clip: rect(-152rpx, 90rpx, 90rpx, -30rpx) !important;
|
||||
animation:.6s backgroundChange linear infinite;
|
||||
}
|
||||
::v-deep body uni-page-refresh div::after{
|
||||
/deep/ body uni-page-refresh div::after{
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -22rpx;
|
||||
@@ -636,7 +636,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
background-color: #ccc;
|
||||
animation:.5s backgroundChange linear infinite;
|
||||
}
|
||||
::v-deep body uni-page-refresh div::before{
|
||||
/deep/ body uni-page-refresh div::before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: -22rpx;
|
||||
@@ -646,15 +646,15 @@ scroll-view ::-webkit-scrollbar {
|
||||
background-color: #ccc;
|
||||
animation:.7s backgroundChange linear infinite;
|
||||
}
|
||||
::v-deep body uni-page-refresh > div > div{
|
||||
/deep/ body uni-page-refresh > div > div{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// 下拉加载动画【scroll-view】
|
||||
::v-deep body .uni-scroll-view-refresher{
|
||||
/deep/ body .uni-scroll-view-refresher{
|
||||
background-color: transparent !important;
|
||||
}
|
||||
::v-deep body .uni-scroll-view-refresher div{
|
||||
/deep/ body .uni-scroll-view-refresher div{
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
@@ -666,7 +666,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
clip: rect(-152rpx, 90rpx, 90rpx, -30rpx) !important;
|
||||
animation:.6s backgroundChange linear infinite;
|
||||
}
|
||||
::v-deep body .uni-scroll-view-refresher div::after{
|
||||
/deep/ body .uni-scroll-view-refresher div::after{
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -22rpx;
|
||||
@@ -676,7 +676,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
background-color: #ccc;
|
||||
animation:.5s backgroundChange linear infinite;
|
||||
}
|
||||
::v-deep body .uni-scroll-view-refresher div::before{
|
||||
/deep/ body .uni-scroll-view-refresher div::before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: -22rpx;
|
||||
@@ -686,7 +686,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
background-color: #ccc;
|
||||
animation:.7s backgroundChange linear infinite;
|
||||
}
|
||||
::v-deep body .uni-scroll-view-refresher > div > div{
|
||||
/deep/ body .uni-scroll-view-refresher > div > div{
|
||||
display: none !important;
|
||||
}
|
||||
@keyframes backgroundChange {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// 修复图片垂直对齐问题,解决两张图片上下有空白缝隙问题
|
||||
::v-deep ._img {
|
||||
/deep/ ._img {
|
||||
vertical-align: top;
|
||||
}
|
||||
@@ -377,7 +377,7 @@ view {
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .goods-form {
|
||||
/deep/ .goods-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
@@ -1354,7 +1354,7 @@ view {
|
||||
border-bottom: 2rpx solid #F4F4F6;
|
||||
}
|
||||
|
||||
::v-deep .form-wrap {
|
||||
/deep/ .form-wrap {
|
||||
margin: 0 24rpx;
|
||||
|
||||
.icon-right {
|
||||
|
||||
@@ -60,107 +60,55 @@ export default {
|
||||
/**
|
||||
* 流式消息入口(自动适配平台)
|
||||
*/
|
||||
async sendStreamMessage(message, onChunk, onComplete) {
|
||||
// #ifdef MP-WEIXIN
|
||||
return new Promise((resolve, reject) => {
|
||||
const socketTask = wx.connectSocket({
|
||||
url: 'wss://dev.aigc-quickapp.com/ws/aikefu',
|
||||
header: {}
|
||||
});
|
||||
|
||||
let content = '';
|
||||
let conversationId = '';
|
||||
let isAuthenticated = false;
|
||||
|
||||
socketTask.onOpen(() => {
|
||||
console.log('WebSocket 连接成功,开始认证...');
|
||||
socketTask.send({
|
||||
data: JSON.stringify({
|
||||
action: 'auth',
|
||||
uniacid: store.state.uniacid || '1',
|
||||
token: store.state.token || 'test_token',
|
||||
user_id: store.state.memberInfo?.id || 'anonymous'
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
socketTask.onMessage((res) => {
|
||||
try {
|
||||
const data = JSON.parse(res.data);
|
||||
console.log('收到 WebSocket 消息:', data);
|
||||
|
||||
if (data.type === 'auth_success') {
|
||||
console.log('认证成功,发送聊天消息...');
|
||||
isAuthenticated = true;
|
||||
socketTask.send({
|
||||
data: JSON.stringify({
|
||||
action: 'chat',
|
||||
uniacid: store.state.uniacid || '1',
|
||||
query: message,
|
||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||
conversation_id: this.getConversationId() || ''
|
||||
})
|
||||
});
|
||||
} else if (data.type === 'auth_failed') {
|
||||
const errorMsg = '认证失败,请重新登录';
|
||||
console.error(errorMsg, data);
|
||||
reject(new Error(errorMsg));
|
||||
if (onComplete) onComplete({ error: errorMsg });
|
||||
socketTask.close();
|
||||
}
|
||||
|
||||
// 处理流式消息块
|
||||
else if (data.type === 'message' || data.event === 'message') {
|
||||
const text = data.answer || data.content || data.text || '';
|
||||
content += text;
|
||||
if (onChunk) onChunk(text);
|
||||
}
|
||||
|
||||
// 处理流结束
|
||||
else if (data.event === 'message_end' || data.type === 'message_end') {
|
||||
conversationId = data.conversation_id || '';
|
||||
if (conversationId) {
|
||||
this.setConversationId(conversationId);
|
||||
}
|
||||
if (onComplete) {
|
||||
onComplete({ content, conversation_id: conversationId });
|
||||
}
|
||||
resolve({ content, conversation_id: conversationId });
|
||||
socketTask.close();
|
||||
}
|
||||
|
||||
// 可选:处理 done
|
||||
else if (data.type === 'done') {
|
||||
console.log('对话完成:', data);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error('WebSocket 消息解析失败:', e, '原始数据:', res.data);
|
||||
}
|
||||
});
|
||||
|
||||
socketTask.onError((err) => {
|
||||
const errorMsg = 'WebSocket 连接失败';
|
||||
console.error(errorMsg, err);
|
||||
reject(new Error(errorMsg));
|
||||
if (onComplete) onComplete({ error: errorMsg });
|
||||
});
|
||||
|
||||
socketTask.onClose(() => {
|
||||
console.log('WebSocket 连接已关闭');
|
||||
});
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
if (!isAuthenticated || content === '') {
|
||||
console.warn('WebSocket 超时,强制关闭');
|
||||
socketTask.close();
|
||||
reject(new Error('AI服务响应超时'));
|
||||
if (onComplete) onComplete({ error: 'AI服务响应超时' });
|
||||
}
|
||||
}, 10000);
|
||||
});
|
||||
async sendStreamMessage(message, onChunk, onComplete) {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序:降级为普通请求 + 前端打字模拟
|
||||
try {
|
||||
const result = await this.sendMessage(message);
|
||||
const content = result.content || '';
|
||||
const conversationId = result.conversationId || '';
|
||||
|
||||
// 保存会话ID(确保连续对话)
|
||||
if (conversationId) {
|
||||
this.setConversationId(conversationId);
|
||||
}
|
||||
|
||||
// 模拟打字效果
|
||||
let index = 0;
|
||||
const chunkSize = 2; // 每次显示2个字符
|
||||
return new Promise((resolve) => {
|
||||
const timer = setInterval(() => {
|
||||
if (index < content.length) {
|
||||
const chunk = content.substring(index, index + chunkSize);
|
||||
index += chunkSize;
|
||||
if (onChunk) onChunk(chunk);
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
if (onComplete) {
|
||||
onComplete({
|
||||
content: content,
|
||||
conversation_id: conversationId
|
||||
});
|
||||
}
|
||||
resolve({ content, conversation_id: conversationId });
|
||||
}
|
||||
}, 80); // 打字速度:80ms/次
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('小程序流式消息降级失败:', error);
|
||||
if (onComplete) {
|
||||
onComplete({ error: error.message || '发送失败' });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
// #ifdef H5
|
||||
// H5:使用真实流式(EventSource / Fetch)
|
||||
return this.sendHttpStream(message, onChunk, onComplete);
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* HTTP 流式请求(仅 H5 使用)
|
||||
*/
|
||||
@@ -183,75 +131,64 @@ export default {
|
||||
conversation_id: this.getConversationId() || ''
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok || !response.body) {
|
||||
throw new Error('无效响应');
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
if (!response.body) {
|
||||
throw new Error('响应体不可用');
|
||||
}
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
let buffer = '';
|
||||
let content = '';
|
||||
let conversationId = '';
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
|
||||
// 按行分割,保留不完整的最后一行
|
||||
const lines = buffer.split('\n');
|
||||
buffer = lines.pop() || ''; // 未完成的行留到下次
|
||||
|
||||
|
||||
function processBuffer(buf, callback) {
|
||||
const lines = buf.split('\n');
|
||||
buf = lines.pop() || '';
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith('data:')) {
|
||||
try {
|
||||
const jsonStr = trimmed.slice(5).trim();
|
||||
if (jsonStr && jsonStr !== '[DONE]') {
|
||||
const jsonStr = trimmed.slice(5).trim();
|
||||
if (jsonStr) {
|
||||
try {
|
||||
const data = JSON.parse(jsonStr);
|
||||
if (data.event === 'message') {
|
||||
const text = data.answer || data.text || '';
|
||||
content += text;
|
||||
if (onChunk) onChunk(text);
|
||||
callback(text);
|
||||
}
|
||||
if (data.conversation_id) {
|
||||
conversationId = data.conversation_id;
|
||||
}
|
||||
if (data.event === 'message_end') {
|
||||
// 可提前结束
|
||||
// 可选:提前完成
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('解析流数据失败:', e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('解析失败:', e, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
// 处理最后残留的 buffer(如果有)
|
||||
if (buffer.trim().startsWith('data:')) {
|
||||
try {
|
||||
const jsonStr = buffer.trim().slice(5);
|
||||
if (jsonStr) {
|
||||
const data = JSON.parse(jsonStr);
|
||||
if (data.event === 'message') {
|
||||
const text = data.answer || '';
|
||||
content += text;
|
||||
if (onChunk) onChunk(text);
|
||||
}
|
||||
if (data.conversation_id) {
|
||||
conversationId = data.conversation_id;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('最后 buffer 解析失败:', e);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
buffer = processBuffer(buffer, (chunk) => {
|
||||
if (onChunk) onChunk(chunk);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (onComplete) {
|
||||
onComplete({ content, conversation_id: conversationId });
|
||||
onComplete({
|
||||
content,
|
||||
conversation_id: conversationId
|
||||
});
|
||||
}
|
||||
return { content, conversation_id: conversationId };
|
||||
} catch (error) {
|
||||
@@ -259,6 +196,11 @@ export default {
|
||||
throw error;
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 理论上不会执行到这里,但防止 fallback
|
||||
return this.sendStreamMessage(message, onChunk, onComplete);
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -489,4 +431,4 @@ export default {
|
||||
return null;
|
||||
// #endif
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -14,7 +14,7 @@ export const langConfig = {
|
||||
// 主题配置
|
||||
export const themeConfig = {
|
||||
// 主题列表
|
||||
themeList: ['default', 'red', 'green', 'blue', 'pink', 'gold', 'purple', 'yellow', 'black'],
|
||||
themeList: ['default', 'red', 'green', 'blue'],
|
||||
// 默认主题
|
||||
defaultTheme: 'default'
|
||||
};
|
||||
@@ -98,6 +98,28 @@ class ConfigExternal {
|
||||
return this.loadPromises[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载主题配置(同步方式)
|
||||
* @param {string} theme - 主题名称
|
||||
* @returns {object} - 主题配置
|
||||
*/
|
||||
loadThemeSync(theme = themeConfig.defaultTheme) {
|
||||
if (this.loadedConfigs[`theme_${theme}`]) {
|
||||
return this.loadedConfigs[`theme_${theme}`];
|
||||
}
|
||||
|
||||
try {
|
||||
// 动态加载主题配置
|
||||
const themeData = require(`@/common/js/style_color.js`)['default'][theme];
|
||||
console.log('sync themeData => ', themeData);
|
||||
this.loadedConfigs[`theme_${theme}`] = themeData;
|
||||
return themeData;
|
||||
} catch (error) {
|
||||
console.error(`加载主题 ${theme} 失败:`, error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载主题配置(异步方式)
|
||||
* @param {string} theme - 主题名称
|
||||
@@ -116,7 +138,7 @@ class ConfigExternal {
|
||||
try {
|
||||
// 动态加载主题配置
|
||||
const themeData = require(`@/common/js/style_color.js`)['default'][theme];
|
||||
// console.log('async themeData => ', themeData);
|
||||
console.log('async themeData => ', themeData);
|
||||
this.loadedConfigs[`theme_${theme}`] = themeData;
|
||||
resolve(themeData);
|
||||
} catch (error) {
|
||||
|
||||
@@ -20,10 +20,6 @@ try {
|
||||
// 默认域名, 自定义发行时可以修改
|
||||
let defaultDomain = '';
|
||||
|
||||
// #ifdef H5_XCX_5G_QUICKAPP_COM
|
||||
defaultDomain = 'https://xcx20.5g-quickapp.com';
|
||||
// #endif
|
||||
|
||||
// #ifdef H5_XCX_AIGC_QUICKAPP_COM
|
||||
defaultDomain = 'https://xcx.aigc-quickapp.com/';
|
||||
// #endif
|
||||
@@ -47,21 +43,19 @@ let localDevConfig = { uniacid: 0, domain: defaultDomain };
|
||||
|
||||
// #ifndef PRODUCTION
|
||||
// 尝试动态加载本地配置文件
|
||||
if (process?.env?.NODE_ENV === 'development') {
|
||||
try {
|
||||
// 尝试从项目根目录加载本地配置文件
|
||||
// 使用相对路径的方式,确保在不同平台下都能正确解析
|
||||
let customConfig = require('@/.local.config.js').default;
|
||||
if (customConfig) {
|
||||
localDevConfig = customConfig;
|
||||
}
|
||||
} catch (e) {
|
||||
// 如果本地配置文件不存在或加载失败,保持使用默认配置
|
||||
// 只在开发模式下输出提示信息
|
||||
// #ifdef WEB
|
||||
console.log('本地配置文件 .local.config.js 不存在,使用默认配置');
|
||||
// #endif
|
||||
try {
|
||||
// 尝试从项目根目录加载本地配置文件
|
||||
// 使用相对路径的方式,确保在不同平台下都能正确解析
|
||||
let customConfig = require('@/.local.config.js').default;
|
||||
if (customConfig) {
|
||||
localDevConfig = customConfig;
|
||||
}
|
||||
} catch (e) {
|
||||
// 如果本地配置文件不存在或加载失败,保持使用默认配置
|
||||
// 只在开发模式下输出提示信息
|
||||
// #ifdef WEB
|
||||
console.log('本地配置文件 .local.config.js 不存在,使用默认配置');
|
||||
// #endif
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
@@ -28,29 +28,28 @@ export class CustomerService {
|
||||
return this.latestPlatformConfig;
|
||||
}
|
||||
|
||||
// 优先级:外部传入 > vuex store > 空对象
|
||||
// 优先级:外部传入的最新配置 > vuex配置 > 空对象
|
||||
const servicerConfig = this.externalConfig || this.vm.$store.state.servicerConfig || {};
|
||||
console.log(`【实时客服配置】`, servicerConfig);
|
||||
|
||||
let platformConfig = null;
|
||||
|
||||
// #ifdef H5
|
||||
platformConfig = servicerConfig.h5 && typeof servicerConfig.h5 === 'object' ? servicerConfig.h5 : null;
|
||||
platformConfig = servicerConfig.h5 ? (typeof servicerConfig.h5 === 'object' ? servicerConfig.h5 : null) : null;
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
platformConfig = servicerConfig.weapp && typeof servicerConfig.weapp === 'object' ? servicerConfig.weapp : null;
|
||||
platformConfig = servicerConfig.weapp ? (typeof servicerConfig.weapp === 'object' ? servicerConfig.weapp : null) : null;
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-ALIPAY
|
||||
platformConfig = servicerConfig.aliapp && typeof servicerConfig.aliapp === 'object' ? servicerConfig.aliapp : null;
|
||||
platformConfig = servicerConfig.aliapp ? (typeof servicerConfig.aliapp === 'object' ? servicerConfig.aliapp : null) : null;
|
||||
// #endif
|
||||
|
||||
// #ifdef PC
|
||||
platformConfig = servicerConfig.pc && typeof servicerConfig.pc === 'object' ? servicerConfig.pc : null;
|
||||
platformConfig = servicerConfig.pc ? (typeof servicerConfig.pc === 'object' ? servicerConfig.pc : null) : null;
|
||||
// #endif
|
||||
|
||||
// 防止空数组被当作有效配置
|
||||
// 处理空数组情况(你的配置中pc/aliapp是空数组,转为null)
|
||||
if (Array.isArray(platformConfig)) {
|
||||
platformConfig = null;
|
||||
}
|
||||
@@ -83,25 +82,39 @@ export class CustomerService {
|
||||
validateConfig() {
|
||||
const config = this.getPlatformConfig();
|
||||
const wxworkConfig = this.getWxworkConfig();
|
||||
|
||||
|
||||
const result = {
|
||||
isValid: true,
|
||||
errors: [],
|
||||
warnings: []
|
||||
};
|
||||
|
||||
if (!config || !config.type) {
|
||||
if (!config) {
|
||||
result.isValid = false;
|
||||
result.errors.push('客服类型未配置');
|
||||
result.errors.push('客服配置不存在');
|
||||
return result;
|
||||
}
|
||||
|
||||
if (config.type === 'aikefu') {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!config.type) {
|
||||
result.isValid = false;
|
||||
result.errors.push('客服类型未配置');
|
||||
}
|
||||
|
||||
if (config.type === 'wxwork') {
|
||||
if (!wxworkConfig || !wxworkConfig.enable) {
|
||||
result.warnings.push('企业微信未启用');
|
||||
}
|
||||
if (!wxworkConfig.contact_url) {
|
||||
result.warnings.push('企业微信活码链接未配置');
|
||||
if (!wxworkConfig) {
|
||||
result.isValid = false;
|
||||
result.errors.push('企业微信配置不存在');
|
||||
} else {
|
||||
if (!wxworkConfig.enable) {
|
||||
result.warnings.push('企业微信功能未启用');
|
||||
}
|
||||
if (!wxworkConfig.contact_url) {
|
||||
result.warnings.push('企业微信活码链接未配置,将使用原有客服方式');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,39 +122,40 @@ export class CustomerService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到 AI 客服页面(Dify)
|
||||
* 跳转到Dify客服页面
|
||||
*/
|
||||
openDifyService() {
|
||||
try {
|
||||
// 清除未读数(如果存在)
|
||||
if (typeof this.vm.setAiUnreadCount === 'function') {
|
||||
if (this.vm.setAiUnreadCount) {
|
||||
this.vm.setAiUnreadCount(0);
|
||||
}
|
||||
|
||||
// ✅ 修正路径:必须与 pages.json 中注册的路径一致
|
||||
const aiChatUrl = '/pages_tool/ai-chat/index';
|
||||
|
||||
// ✅ 使用 navigateTo 保留返回栈(体验更好)
|
||||
uni.navigateTo({
|
||||
url: aiChatUrl,
|
||||
// 强制跳转,忽略框架层的封装
|
||||
uni.redirectTo({
|
||||
url: '/pages_tool/ai-chat/index',
|
||||
fail: (err) => {
|
||||
console.error('跳转 AI 客服失败:', err);
|
||||
// H5 兜底
|
||||
// 兜底:使用window.location跳转(H5)
|
||||
// #ifdef H5
|
||||
window.location.href = aiChatUrl;
|
||||
window.location.href = '/pages_tool/ai-chat/index';
|
||||
// #endif
|
||||
uni.showToast({ title: '打开客服失败', icon: 'none' });
|
||||
console.error('跳转Dify客服失败:', err);
|
||||
uni.showToast({
|
||||
title: '跳转客服失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('跳转 AI 客服异常:', e);
|
||||
uni.showToast({ title: '打开客服失败', icon: 'none' });
|
||||
console.error('跳转Dify客服异常:', e);
|
||||
uni.showToast({
|
||||
title: '跳转客服失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理客服点击事件(统一入口)
|
||||
* @param {Object} options 选项参数(用于消息卡片等)
|
||||
* 处理客服点击事件
|
||||
* @param {Object} options 选项参数
|
||||
*/
|
||||
handleCustomerClick(options = {}) {
|
||||
const validation = this.validateConfig();
|
||||
@@ -156,9 +170,6 @@ export class CustomerService {
|
||||
}
|
||||
|
||||
const config = this.getPlatformConfig();
|
||||
console.log('【当前客服配置】', config);
|
||||
console.log('【客服类型】', config.type);
|
||||
|
||||
const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
|
||||
|
||||
if (config.type === 'none') {
|
||||
@@ -166,51 +177,44 @@ export class CustomerService {
|
||||
return;
|
||||
}
|
||||
|
||||
// 核心路由:根据 type 决定行为
|
||||
// 核心分支:根据最新的type处理
|
||||
switch (config.type) {
|
||||
case 'aikefu':
|
||||
console.log('【跳转 AI 客服】目标路径: /pages_tool/ai-chat/index');
|
||||
this.openDifyService();
|
||||
break;
|
||||
case 'wxwork':
|
||||
console.log('【跳转企业微信客服】');
|
||||
this.openWxworkService(false, config, options);
|
||||
break;
|
||||
case 'third':
|
||||
console.log('【跳转第三方客服】');
|
||||
this.openThirdService(config);
|
||||
break;
|
||||
case 'miniprogram':
|
||||
console.log('【跳转第三方小程序客服】');
|
||||
this.openThirdService(config);
|
||||
break;
|
||||
case 'niushop':
|
||||
console.log('【跳转牛商客服】');
|
||||
this.openNiushopService(niushop);
|
||||
break;
|
||||
case 'weapp':
|
||||
console.log('【跳转微信官方客服】');
|
||||
this.openWeappService(config, options);
|
||||
break;
|
||||
case 'aliapp':
|
||||
console.log('【跳转支付宝客服】');
|
||||
this.openAliappService(config);
|
||||
break;
|
||||
default:
|
||||
console.error('【未知客服类型】', config.type);
|
||||
this.makePhoneCall();
|
||||
}
|
||||
}
|
||||
|
||||
// ================== 各类型客服实现 ==================
|
||||
|
||||
/**
|
||||
* 打开企业微信客服
|
||||
* @param {boolean} useOriginalService 是否使用原有客服方式
|
||||
* @param {Object} servicerConfig 客服配置
|
||||
* @param {Object} options 选项参数
|
||||
*/
|
||||
openWxworkService(useOriginalService = false, servicerConfig = null, options = {}) {
|
||||
const config = servicerConfig || this.getPlatformConfig();
|
||||
const wxworkConfig = this.getWxworkConfig();
|
||||
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
if (!useOriginalService && wxworkConfig?.enable && wxworkConfig?.contact_url) {
|
||||
if (wxworkConfig?.enable && wxworkConfig?.contact_url && !useOriginalService) {
|
||||
wx.navigateToMiniProgram({
|
||||
appId: 'wxeb490c6f9b154ef9',
|
||||
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig.contact_url)}`,
|
||||
@@ -221,16 +225,9 @@ export class CustomerService {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 检查是否有企业微信配置
|
||||
if (!config.wxwork_url && !config.corpid) {
|
||||
console.error('企业微信配置不完整,缺少 wxwork_url 或 corpid');
|
||||
uni.showToast({ title: '企业微信配置不完整', icon: 'none' });
|
||||
this.fallbackToPhoneCall();
|
||||
return;
|
||||
}
|
||||
wx.openCustomerServiceChat({
|
||||
extInfo: { url: config.wxwork_url || '' },
|
||||
corpId: config.corpid || '',
|
||||
extInfo: { url: config.wxwork_url },
|
||||
corpId: config.corpid,
|
||||
showMessageCard: true,
|
||||
sendMessageTitle,
|
||||
sendMessagePath,
|
||||
@@ -240,181 +237,224 @@ export class CustomerService {
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
if (!useOriginalService && wxworkConfig?.enable && wxworkConfig?.contact_url) {
|
||||
if (wxworkConfig?.enable && wxworkConfig?.contact_url) {
|
||||
window.location.href = wxworkConfig.contact_url;
|
||||
} else if (config.wxwork_url) {
|
||||
window.location.href = config.wxwork_url;
|
||||
location.href = config.wxwork_url;
|
||||
} else {
|
||||
this.fallbackToPhoneCall();
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开第三方客服
|
||||
* @param {Object} config 客服配置
|
||||
*/
|
||||
openThirdService(config) {
|
||||
console.log('【第三方客服配置】', config);
|
||||
console.log('【配置字段】', Object.keys(config));
|
||||
|
||||
// 支持多种可能的字段名
|
||||
const miniAppId = config.mini_app_id || config.miniAppId || config.appid || config.appId || config.app_id;
|
||||
const miniAppPath = config.mini_app_path || config.miniAppPath || config.path || config.page_path || '';
|
||||
|
||||
console.log('【解析后的小程序配置】AppID:', miniAppId, 'Path:', miniAppPath);
|
||||
|
||||
// 优先处理第三方微信小程序客服
|
||||
if (miniAppId) {
|
||||
console.log('【跳转第三方小程序】AppID:', miniAppId, 'Path:', miniAppPath);
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.navigateToMiniProgram({
|
||||
appId: miniAppId,
|
||||
path: miniAppPath,
|
||||
success: () => {
|
||||
console.log('【跳转第三方小程序成功】');
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('【跳转第三方小程序失败】', err);
|
||||
uni.showToast({ title: '跳转失败,请稍后重试', icon: 'none' });
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
uni.showToast({ title: '第三方小程序客服仅在微信小程序中可用', icon: 'none' });
|
||||
// #endif
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理第三方链接客服
|
||||
if (config.third_url) {
|
||||
console.log('【跳转第三方链接】', config.third_url);
|
||||
// #ifdef H5
|
||||
window.location.href = config.third_url;
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.setClipboardData({
|
||||
data: config.third_url,
|
||||
success: () => {
|
||||
uni.showToast({ title: '链接已复制,请在浏览器打开', icon: 'none' });
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
} else {
|
||||
console.error('【第三方客服配置不完整】缺少 mini_app_id 或 third_url');
|
||||
this.fallbackToPhoneCall();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开牛商客服
|
||||
* @param {Object} niushop 牛商参数
|
||||
*/
|
||||
openNiushopService(niushop) {
|
||||
if (Object.keys(niushop).length > 0 && this.vm.$util?.redirectTo) {
|
||||
if (Object.keys(niushop).length > 0) {
|
||||
this.vm.$util.redirectTo('/pages_tool/chat/room', niushop);
|
||||
} else {
|
||||
this.makePhoneCall();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开微信小程序客服
|
||||
* @param {Object} config 客服配置
|
||||
* @param {Object} options 选项参数
|
||||
*/
|
||||
openWeappService(config, options = {}) {
|
||||
// 如果 useOfficial 为 true 或 undefined,则使用原生系统客服(由 button open-type="contact" 触发)
|
||||
// 此方法仅用于自定义跳转(如 useOfficial: false)
|
||||
if (config.useOfficial !== false) {
|
||||
// 不做任何事,应由 <button open-type="contact"> 触发
|
||||
console.log('使用微信官方客服,请确保按钮为 <button open-type="contact">');
|
||||
if (!this.shouldUseCustomService(config)) {
|
||||
console.log('使用官方微信小程序客服');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('使用自定义微信小程序客服');
|
||||
this.handleCustomWeappService(config, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自定义微信小程序客服
|
||||
* @param {Object} config 客服配置
|
||||
* @param {Object} options 选项参数
|
||||
*/
|
||||
handleCustomWeappService(config, options = {}) {
|
||||
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
|
||||
|
||||
if (config.customServiceUrl) {
|
||||
let url = config.customServiceUrl;
|
||||
const params = [];
|
||||
const { sendMessageTitle, sendMessagePath, sendMessageImg } = options;
|
||||
if (sendMessageTitle) params.push(`title=${encodeURIComponent(sendMessageTitle)}`);
|
||||
if (sendMessagePath) params.push(`path=${encodeURIComponent(sendMessagePath)}`);
|
||||
if (sendMessageImg) params.push(`img=${encodeURIComponent(sendMessageImg)}`);
|
||||
|
||||
if (params.length > 0) {
|
||||
url += (url.includes('?') ? '&' : '?') + params.join('&');
|
||||
}
|
||||
uni.navigateTo({ url });
|
||||
|
||||
uni.navigateTo({
|
||||
url: url,
|
||||
fail: (err) => {
|
||||
console.error('跳转自定义客服页面失败:', err);
|
||||
this.tryThirdPartyService(config, options);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.tryThirdPartyService(config, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试使用第三方客服
|
||||
* @param {Object} config 客服配置
|
||||
* @param {Object} options 选项参数
|
||||
*/
|
||||
tryThirdPartyService(config, options = {}) {
|
||||
// 支持第三方微信小程序客服
|
||||
if (config.thirdPartyMiniAppId || config.mini_app_id) {
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.navigateToMiniProgram({
|
||||
appId: config.thirdPartyMiniAppId || config.mini_app_id,
|
||||
path: config.thirdPartyMiniAppPath || config.mini_app_path || ''
|
||||
});
|
||||
// #endif
|
||||
return;
|
||||
}
|
||||
|
||||
// 支持第三方链接客服
|
||||
if (config.thirdPartyServiceUrl || config.third_url) {
|
||||
const serviceUrl = config.thirdPartyServiceUrl || config.third_url;
|
||||
if (config.thirdPartyServiceUrl) {
|
||||
// #ifdef H5
|
||||
window.open(serviceUrl, '_blank');
|
||||
window.open(config.thirdPartyServiceUrl, '_blank');
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.setClipboardData({ data: serviceUrl });
|
||||
uni.showToast({ title: '客服链接已复制', icon: 'none' });
|
||||
if (config.thirdPartyMiniAppId) {
|
||||
wx.navigateToMiniProgram({
|
||||
appId: config.thirdPartyMiniAppId,
|
||||
path: config.thirdPartyMiniAppPath || '',
|
||||
fail: (err) => {
|
||||
console.error('跳转第三方小程序失败:', err);
|
||||
this.fallbackToPhoneCall();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.setClipboardData({
|
||||
data: config.thirdPartyServiceUrl,
|
||||
success: () => {
|
||||
uni.showModal({
|
||||
title: '客服链接已复制',
|
||||
content: '客服链接已复制到剪贴板,请在浏览器中粘贴访问',
|
||||
showCancel: false
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.fallbackToPhoneCall();
|
||||
}
|
||||
|
||||
/**
|
||||
* 降级到电话客服
|
||||
*/
|
||||
fallbackToPhoneCall() {
|
||||
uni.showModal({
|
||||
title: '联系客服',
|
||||
content: '在线客服暂时不可用,是否拨打电话联系客服?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.makePhoneCall();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开支付宝小程序客服
|
||||
* @param {Object} config 客服配置
|
||||
*/
|
||||
openAliappService(config) {
|
||||
if (config.type === 'aikefu') {
|
||||
this.openDifyService();
|
||||
} else if (config.type === 'third') {
|
||||
this.openThirdService(config);
|
||||
} else {
|
||||
// 支付宝原生客服由 button open-type="contact" 触发,此处不处理
|
||||
console.log('使用支付宝官方客服');
|
||||
console.log('支付宝小程序客服', config);
|
||||
switch (config.type) {
|
||||
case 'aikefu':
|
||||
this.openDifyService();
|
||||
break;
|
||||
case 'third':
|
||||
this.openThirdService(config);
|
||||
break;
|
||||
default:
|
||||
console.log('使用支付宝官方客服');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ================== 辅助方法 ==================
|
||||
|
||||
/**
|
||||
* 拨打电话
|
||||
*/
|
||||
makePhoneCall() {
|
||||
this.vm.$api.sendRequest({
|
||||
url: '/api/site/shopcontact',
|
||||
success: res => {
|
||||
if (res.code === 0 && res.data?.mobile) {
|
||||
uni.makePhoneCall({ phoneNumber: res.data.mobile });
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: res.data.mobile
|
||||
});
|
||||
} else {
|
||||
uni.showToast({ title: '暂无客服电话', icon: 'none' });
|
||||
uni.showToast({
|
||||
title: '暂无客服电话',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({ title: '获取客服电话失败', icon: 'none' });
|
||||
uni.showToast({
|
||||
title: '获取客服电话失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示无客服弹窗
|
||||
*/
|
||||
showNoServicePopup() {
|
||||
const siteInfo = this.vm.$store.state.siteInfo || {};
|
||||
const message = siteInfo?.site_tel
|
||||
? `请联系客服,客服电话是 ${siteInfo.site_tel}`
|
||||
? `请联系客服,客服电话是${siteInfo.site_tel}`
|
||||
: '抱歉,商家暂无客服,请线下联系';
|
||||
uni.showModal({ title: '联系客服', content: message, showCancel: false });
|
||||
}
|
||||
|
||||
showConfigErrorPopup(errors) {
|
||||
uni.showModal({
|
||||
title: '客服配置错误',
|
||||
content: `配置有误:\n${errors.join('\n')}`,
|
||||
title: '联系客服',
|
||||
content: message,
|
||||
showCancel: false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示配置错误弹窗
|
||||
* @param {Array} errors 错误列表
|
||||
*/
|
||||
showConfigErrorPopup(errors) {
|
||||
const message = errors.join('\n');
|
||||
uni.showModal({
|
||||
title: '配置错误',
|
||||
content: `客服配置有误:\n${message}`,
|
||||
showCancel: false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 降级处理:使用原有客服方式
|
||||
*/
|
||||
fallbackToOriginalService() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '无法直接添加企业微信,是否使用其他方式联系客服?',
|
||||
content: '无法直接添加企业微信客服,是否使用其他方式联系客服?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.openWxworkService(true);
|
||||
@@ -423,19 +463,9 @@ export class CustomerService {
|
||||
});
|
||||
}
|
||||
|
||||
fallbackToPhoneCall() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '在线客服不可用,是否拨打电话联系客服?',
|
||||
success: (res) => {
|
||||
if (res.confirm) this.makePhoneCall();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取按钮配置(用于 template 中 v-if / open-type 判断)
|
||||
* @returns {Object}
|
||||
* 获取客服按钮配置
|
||||
* @returns {Object} 按钮配置
|
||||
*/
|
||||
getButtonConfig() {
|
||||
const config = this.getPlatformConfig();
|
||||
@@ -443,23 +473,38 @@ export class CustomerService {
|
||||
|
||||
let openType = '';
|
||||
// #ifdef MP-WEIXIN
|
||||
if (config.type === 'weapp' && config.useOfficial !== false) {
|
||||
openType = 'contact';
|
||||
if (config.type === 'weapp') {
|
||||
openType = config.useOfficial !== false ? 'contact' : '';
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-ALIPAY
|
||||
if (config.type === 'aliapp') openType = 'contact';
|
||||
// #endif
|
||||
|
||||
return { ...config, openType };
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否应该使用自定义客服处理
|
||||
* @param {Object} config 客服配置
|
||||
* @returns {boolean} 是否使用自定义客服
|
||||
*/
|
||||
shouldUseCustomService(config) {
|
||||
// #ifdef MP-WEIXIN
|
||||
if (config?.type === 'weapp') {
|
||||
return config.useOfficial === false;
|
||||
}
|
||||
// #endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建客服服务实例
|
||||
* @param {Object} vueInstance Vue 实例(通常是 this)
|
||||
* @param {Object} externalConfig 可选:外部传入的最新配置(如从 DIY 数据中提取)
|
||||
* @returns {CustomerService}
|
||||
* @param {Object} vueInstance Vue实例
|
||||
* @param {Object} externalConfig 外部最新配置
|
||||
* @returns {CustomerService} 客服服务实例
|
||||
*/
|
||||
export function createCustomerService(vueInstance, externalConfig = null) {
|
||||
return new CustomerService(vueInstance, externalConfig);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import WxMap from 'common/js/map-wx-jssdk.js';
|
||||
import Config from '@/common/js/config.js';
|
||||
import util from '@/common/js/util.js';
|
||||
|
||||
let systemInfo = util.getDeviceInfo();
|
||||
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -609,10 +607,10 @@ export default {
|
||||
},
|
||||
// 分享给好友
|
||||
onShareAppMessage() {
|
||||
return this.mpShareData?.appMessage;
|
||||
return this.mpShareData.appMessage;
|
||||
},
|
||||
// 分享到朋友圈
|
||||
onShareTimeline() {
|
||||
return this.mpShareData?.timeLine;
|
||||
return this.mpShareData.timeLine;
|
||||
}
|
||||
}
|
||||
@@ -65,18 +65,10 @@ export default {
|
||||
componentRefresh() {
|
||||
return this.$store.state.componentRefresh;
|
||||
},
|
||||
// AI客服配置
|
||||
globalAIKefuConfig() {
|
||||
return this.$store.state.globalAIKefuConfig;
|
||||
},
|
||||
// 客服配置
|
||||
servicerConfig() {
|
||||
return this.$store.state.servicerConfig;
|
||||
},
|
||||
// 企业微信配置
|
||||
wxworkConfig() {
|
||||
return this.$store.state.wxworkConfig;
|
||||
},
|
||||
diySeckillInterval() {
|
||||
return this.$store.state.diySeckillInterval;
|
||||
},
|
||||
@@ -153,7 +145,7 @@ export default {
|
||||
if (isJump && route != 'pages/index/index') {
|
||||
uni.setStorageSync('manual_change_store', true); // 手动切换门店
|
||||
this.$store.dispatch('getCartNumber'); //重新获取购物车数据
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -240,7 +240,7 @@ export default {
|
||||
},
|
||||
goHome() {
|
||||
if (this.preview) return; // 开启预览,禁止任何操作和跳转
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
},
|
||||
goCart() {
|
||||
if (this.preview) return; // 开启预览,禁止任何操作和跳转
|
||||
|
||||
@@ -1,161 +1,195 @@
|
||||
import { langConfig } from './config-external.js';
|
||||
|
||||
var locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
|
||||
// 缓存已加载的语言包
|
||||
const loadedLangPacks = {};
|
||||
var loadedLangPacks = {};
|
||||
|
||||
// 处理页面目录映射
|
||||
function processRoutePath(route) {
|
||||
let routeParts = route.split("/");
|
||||
let routeParts = route.split("/");
|
||||
|
||||
// ---- 处理页面目录映射 <begin> 分包造成的,需要根据实际目录结构进行映射----
|
||||
if (routeParts[0] === 'pages_tool') {
|
||||
routeParts = [routeParts[1], ...routeParts.slice(2)];
|
||||
} else if (routeParts[0] === 'pages_goods') {
|
||||
routeParts[0] = 'goods';
|
||||
} else if (routeParts[0] === 'pages_member') {
|
||||
routeParts[0] = 'member';
|
||||
} else if (routeParts[0] === 'pages_order') {
|
||||
routeParts[0] = 'order';
|
||||
} else if (routeParts[0] === 'pages_promotion') {
|
||||
const promotionModules = ['point', 'fenxiao', 'merch'];
|
||||
if (routeParts[1] && promotionModules.includes(routeParts[1])) {
|
||||
routeParts = [routeParts[1], ...routeParts.slice(2)];
|
||||
}
|
||||
}
|
||||
// ---- 处理页面目录映射 <end>----
|
||||
|
||||
if (routeParts[0] === 'pages') {
|
||||
routeParts = routeParts.slice(1);
|
||||
}
|
||||
|
||||
return routeParts.join("/");
|
||||
// ---- 处理页面目录映射 <begin> 分包造成的,需要根据实际目录结构进行映射----
|
||||
// 先处理特殊的分包路径
|
||||
if (routeParts[0] === 'pages_tool') {
|
||||
// pages_tool 分包下的页面,直接使用子目录作为语言包路径
|
||||
routeParts = [routeParts[1], ...routeParts.slice(2)];
|
||||
} else if (routeParts[0] === 'pages_goods') {
|
||||
// pages_goods 分包映射到 goods 目录
|
||||
routeParts[0] = 'goods';
|
||||
} else if (routeParts[0] === 'pages_member') {
|
||||
// pages_member 分包映射到 member 目录
|
||||
routeParts[0] = 'member';
|
||||
} else if (routeParts[0] === 'pages_order') {
|
||||
// pages_order 分包映射到 order 目录
|
||||
routeParts[0] = 'order';
|
||||
} else if (routeParts[0] === 'pages_promotion') {
|
||||
// pages_promotion 分包特殊处理
|
||||
const promotionModules = ['point', 'fenxiao', 'merch'];
|
||||
if (routeParts[1] && promotionModules.includes(routeParts[1])) {
|
||||
routeParts = [routeParts[1], ...routeParts.slice(2)];
|
||||
}
|
||||
}
|
||||
// ---- 处理页面目录映射 <end>----
|
||||
|
||||
// 去掉pages目录,只保留子目录
|
||||
if (routeParts[0] === 'pages') {
|
||||
routeParts = routeParts.slice(1);
|
||||
}
|
||||
|
||||
return routeParts.join("/");
|
||||
}
|
||||
|
||||
// 加载语言包(同步方式)
|
||||
function loadLangPackSync(lang, path) {
|
||||
try {
|
||||
if (loadedLangPacks[`${lang}_${path}`]) {
|
||||
return loadedLangPacks[`${lang}_${path}`];
|
||||
}
|
||||
const langData = require(`@/lang/${lang}/${path}.js`).lang;
|
||||
loadedLangPacks[`${lang}_${path}`] = langData;
|
||||
return langData;
|
||||
} catch (error) {
|
||||
console.error(`加载语言包 ${lang}/${path} 失败:`, error);
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
if (loadedLangPacks[`${lang}_${path}`]) {
|
||||
return loadedLangPacks[`${lang}_${path}`];
|
||||
}
|
||||
const langData = require(`@/lang/${lang}/${path}.js`).lang;
|
||||
loadedLangPacks[`${lang}_${path}`] = langData;
|
||||
return langData;
|
||||
} catch (error) {
|
||||
console.error(`加载语言包 ${lang}/${path} 失败:`, error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
langList: langConfig.langList,
|
||||
/**
|
||||
* 解析多语言
|
||||
*/
|
||||
lang(field) {
|
||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
||||
if (!_this) return;
|
||||
langList: langConfig.langList,
|
||||
/**
|
||||
* * 解析多语言
|
||||
* @param {Object} field
|
||||
*/
|
||||
lang(field) {
|
||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
||||
if (!_this) return;
|
||||
|
||||
const locale = uni.getStorageSync('lang') || "zh-cn";
|
||||
var value = '';
|
||||
try {
|
||||
//公共语言包(同步加载)
|
||||
var lang = loadLangPackSync(locale, 'common');
|
||||
|
||||
//当前页面语言包(同步加载)
|
||||
let route = _this.route;
|
||||
let langPath = processRoutePath(route);
|
||||
// console.log(`当前页面语言包路径: ${langPath}`);
|
||||
|
||||
// 加载当前页面语言包
|
||||
let currentPageLang = loadLangPackSync(locale, langPath);
|
||||
|
||||
let value = '';
|
||||
let langPath = '';
|
||||
// 合并语言包
|
||||
let mergedLang = { ...lang, ...currentPageLang };
|
||||
|
||||
try {
|
||||
var lang = loadLangPackSync(locale, 'common');
|
||||
|
||||
let route = _this.route;
|
||||
langPath = processRoutePath(route);
|
||||
|
||||
let currentPageLang = loadLangPackSync(locale, langPath);
|
||||
// 解析字段
|
||||
var arr = field.split(".");
|
||||
if (arr.length > 1) {
|
||||
// 处理嵌套属性,如 common.currencySymbol
|
||||
let temp = mergedLang;
|
||||
let found = true;
|
||||
for (let key of arr) {
|
||||
if (temp[key] !== undefined) {
|
||||
temp = temp[key];
|
||||
} else {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = found ? temp : field;
|
||||
} else {
|
||||
value = mergedLang[field] !== undefined ? mergedLang[field] : field;
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error('解析语言包失败:', e);
|
||||
value = field;
|
||||
}
|
||||
|
||||
let mergedLang = { ...lang, ...currentPageLang };
|
||||
if (arguments.length > 1) {
|
||||
//有参数,需要替换
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
value = value.replace("{" + (i - 1) + "}", arguments[i]);
|
||||
}
|
||||
}
|
||||
if (value == undefined || (value == 'title' && field == 'title')) value = ''; // field
|
||||
|
||||
var arr = field.split(".");
|
||||
if (arr.length > 1) {
|
||||
let temp = mergedLang;
|
||||
let found = true;
|
||||
for (let key of arr) {
|
||||
if (temp[key] !== undefined) {
|
||||
temp = temp[key];
|
||||
} else {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = found ? temp : field;
|
||||
} else {
|
||||
value = mergedLang[field] !== undefined ? mergedLang[field] : field;
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error('解析语言包失败:', e, { langPath, field, locale });
|
||||
value = field;
|
||||
}
|
||||
// 多语言调试,注释后可以关闭控制台输出
|
||||
// console.log(`字段: ${field}, 值: ${value}`)
|
||||
return value;
|
||||
},
|
||||
/**
|
||||
* * 切换语言
|
||||
* @param {String} value 语言值
|
||||
* @param {String} url 切换后跳转的页面url
|
||||
*/
|
||||
change(value, url = '/pages_tool/member/index') {
|
||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
||||
if (!_this) return;
|
||||
|
||||
if (arguments.length > 1) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
value = value.replace("{" + (i - 1) + "}", arguments[i]);
|
||||
}
|
||||
}
|
||||
if (value == undefined || (value == 'title' && field == 'title')) value = '';
|
||||
uni.setStorageSync("lang", value);
|
||||
locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
|
||||
|
||||
if (field == value) {
|
||||
console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
|
||||
}
|
||||
// 清空已加载的语言包缓存
|
||||
loadedLangPacks = {};
|
||||
|
||||
return value;
|
||||
},
|
||||
/**
|
||||
* 切换语言
|
||||
*/
|
||||
change(value, url = '/pages_tool/member/index') {
|
||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
||||
if (!_this) return;
|
||||
this.refresh();
|
||||
|
||||
uni.setStorageSync("lang", value);
|
||||
const locale = uni.getStorageSync('lang') || "zh-cn";
|
||||
if (url) {
|
||||
uni.reLaunch({ url: url });
|
||||
}
|
||||
},
|
||||
//刷新标题、tabbar
|
||||
refresh() {
|
||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
||||
if (!_this) return;
|
||||
locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
|
||||
|
||||
this.title(this.lang("title"));
|
||||
|
||||
// ✅ 关键修复:清空所有语言包缓存(不再保留任何旧缓存)
|
||||
for (let key in loadedLangPacks) {
|
||||
delete loadedLangPacks[key];
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
|
||||
if (url) {
|
||||
uni.reLaunch({ url: url });
|
||||
}
|
||||
},
|
||||
//刷新标题、tabbar
|
||||
refresh() {
|
||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
||||
if (!_this) return;
|
||||
const locale = uni.getStorageSync('lang') || "zh-cn";
|
||||
|
||||
this.title(this.lang("title"));
|
||||
},
|
||||
title(str) {
|
||||
if (str) {
|
||||
uni.setNavigationBarTitle({
|
||||
title: str
|
||||
});
|
||||
}
|
||||
},
|
||||
// 获取语言包列表
|
||||
list() {
|
||||
var list = [];
|
||||
try {
|
||||
for (var i = 0; i < langConfig.langList.length; i++) {
|
||||
let langType = langConfig.langList[i];
|
||||
let item = loadLangPackSync(langType, 'common');
|
||||
list.push({
|
||||
name: item.common ? item.common.name : langType,
|
||||
value: langType
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取语言包列表失败:', e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
//设置tabbar的文字语言
|
||||
// uni.setTabBarItem({
|
||||
// index: 0,
|
||||
// text: this.lang("tabBar.home")
|
||||
// });
|
||||
// uni.setTabBarItem({
|
||||
// index: 1,
|
||||
// text: this.lang("tabBar.category")
|
||||
// });
|
||||
// uni.setTabBarItem({
|
||||
// index: 2,
|
||||
// text: this.lang("tabBar.cart")
|
||||
// });
|
||||
// uni.setTabBarItem({
|
||||
// index: 3,
|
||||
// text: this.lang("tabBar.member")
|
||||
// });
|
||||
},
|
||||
title(str) {
|
||||
if (str) {
|
||||
uni.setNavigationBarTitle({
|
||||
title: str,
|
||||
success: function (res) {
|
||||
},
|
||||
fail: function (err) {
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
// 获取语言包列表
|
||||
list() {
|
||||
var list = [];
|
||||
try {
|
||||
//公共语言包
|
||||
for (var i = 0; i < langConfig.langList.length; i++) {
|
||||
let langType = langConfig.langList[i];
|
||||
let item = loadLangPackSync(langType, 'common');
|
||||
list.push({
|
||||
name: item.common ? item.common.name : langType,
|
||||
value: langType
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取语言包列表失败:', e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import util from '@/common/js/util.js'
|
||||
import TransformCoordinate from './transformCoordinate.js'
|
||||
|
||||
function openMapByDefault(latitude, longitude, name) {
|
||||
@@ -86,8 +85,7 @@ export default {
|
||||
openMap(latitude, longitude, name, coord_type = 'gcj02') {
|
||||
let arr = getCoordByType(longitude, latitude, coord_type)
|
||||
// #ifdef APP-PLUS
|
||||
let platform = util.getDeviceInfo().platform;
|
||||
switch (platform) {
|
||||
switch (uni.getSystemInfoSync().platform) {
|
||||
case 'android':
|
||||
console.log('运行Android上')
|
||||
openMapByAndroid(arr[1], arr[0], name)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { EventSafety } from '@/common/js/event-safety.js'
|
||||
import util from '@/common/js/util.js'
|
||||
import { EventSafety } from './event-safety'
|
||||
|
||||
export class NavigationHelper {
|
||||
constructor() {
|
||||
@@ -60,7 +59,7 @@ export class NavigationHelper {
|
||||
// 微信小程序精确计算
|
||||
try {
|
||||
const menuButtonInfo = wx.getMenuButtonBoundingClientRect()
|
||||
let systemInfo = util.getDeviceInfo();
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
|
||||
const height = menuButtonInfo.bottom +
|
||||
(menuButtonInfo.top - systemInfo.statusBarHeight)
|
||||
@@ -120,7 +119,7 @@ export class NavigationHelper {
|
||||
// 获取状态栏高度
|
||||
getStatusBarHeight() {
|
||||
// #ifdef MP-WEIXIN
|
||||
let systemInfo = util.getDeviceInfo();
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
return systemInfo.statusBarHeight || 20
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
@@ -139,7 +138,7 @@ export class NavigationHelper {
|
||||
// 获取安全区域
|
||||
getSafeAreaInsets() {
|
||||
try {
|
||||
let systemInfo = util.getDeviceInfo();
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
return systemInfo.safeArea || {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
// 文件分享工具函数
|
||||
export default {
|
||||
/**
|
||||
* 生成文件预览链接
|
||||
* @param {Object} file - 文件对象,包含 name 和 url 属性
|
||||
* @returns {string} - 生成的文件预览链接
|
||||
*/
|
||||
generateFilePreviewUrl(file) {
|
||||
// 推断文件类型
|
||||
let fileType = '';
|
||||
if (file.name) {
|
||||
const ext = file.name.split('.').pop().toLowerCase();
|
||||
if (['pdf'].includes(ext)) {
|
||||
fileType = 'pdf';
|
||||
} else if (['doc', 'docx'].includes(ext)) {
|
||||
fileType = 'word';
|
||||
} else if (['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'].includes(ext)) {
|
||||
fileType = 'video';
|
||||
}
|
||||
}
|
||||
|
||||
// 构建文件预览链接
|
||||
const previewUrl = `/pages_tool/file-preview/file-preview?fileName=${encodeURIComponent(file.name)}&fileUrl=${encodeURIComponent(file.url || '')}&fileType=${encodeURIComponent(fileType)}`;
|
||||
return previewUrl;
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享文件
|
||||
* @param {Object} file - 文件对象,包含 name 和 url 属性
|
||||
* @param {string} title - 分享标题,默认使用文件名
|
||||
* @param {string} desc - 分享描述,默认使用固定文案
|
||||
*/
|
||||
shareFile(file, title = file.name, desc = '查看企业文件:' + file.name) {
|
||||
// 生成文件预览链接
|
||||
const filePreviewUrl = this.generateFilePreviewUrl(file);
|
||||
|
||||
// #ifdef H5
|
||||
// H5 平台分享
|
||||
if (navigator.share) {
|
||||
// 使用 Web Share API
|
||||
navigator.share({
|
||||
title: title,
|
||||
text: desc,
|
||||
url: filePreviewUrl
|
||||
}).catch(err => {
|
||||
console.error('分享失败:', err);
|
||||
uni.showToast({ title: '分享失败', icon: 'none' });
|
||||
});
|
||||
} else {
|
||||
// 不支持 Web Share API 的浏览器
|
||||
uni.setClipboardData({
|
||||
data: filePreviewUrl,
|
||||
success: () => {
|
||||
uni.showToast({ title: '链接已复制,请粘贴分享', icon: 'success' });
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({ title: '复制失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序分享
|
||||
uni.showActionSheet({
|
||||
itemList: ['发送给朋友', '分享到朋友圈'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
// 发送给朋友
|
||||
uni.shareAppMessage({
|
||||
title: title,
|
||||
path: filePreviewUrl,
|
||||
success: () => {
|
||||
uni.showToast({ title: '分享成功', icon: 'success' });
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({ title: '分享失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
} else if (res.tapIndex === 1) {
|
||||
// 分享到朋友圈
|
||||
uni.shareTimeline({
|
||||
title: desc,
|
||||
path: filePreviewUrl,
|
||||
success: () => {
|
||||
uni.showToast({ title: '分享成功', icon: 'success' });
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({ title: '分享失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 用户取消分享
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
}
|
||||
};
|
||||
@@ -1,460 +1,419 @@
|
||||
/**
|
||||
* 颜色配置
|
||||
* 包含默认颜色和其他颜色
|
||||
* 特别注意:
|
||||
* 1. 分组不会被计算成Key,分组下的属性会被计算成Key
|
||||
* 2. 分组下的属性如果有相同的Key,会被覆盖
|
||||
* 3. 例如:hoverNav,hoverNav_bg_color和hoverNav_text_color, 不会生成hoverNav_hoverNav_bg_color和hoverNav_hoverNav_text_color
|
||||
* 问题原因:历史遗留
|
||||
*/
|
||||
export default {
|
||||
'default': {
|
||||
//红色
|
||||
name: 'default',
|
||||
main_color: '#F4391c',
|
||||
aux_color: '#F7B500',
|
||||
bg_color: '#FF4646',//主题背景
|
||||
bg_color_shallow: '#FF4646',//主题背景渐变浅色
|
||||
promotion_color: '#FF4646',//活动背景
|
||||
promotion_aux_color: '#F7B500',//活动背景辅色
|
||||
main_color_shallow: '#FFF4F4',//淡背景
|
||||
price_color: 'rgb(252,82,39)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
...{
|
||||
goods_price: 'rgb(252,82,39,1)',//价格
|
||||
promotion_tag: '#FF4646',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#FF4646',//按钮颜色
|
||||
goods_btn_color_shallow: '#F7B500',//副按钮颜色
|
||||
},
|
||||
...{
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
...{
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
...{
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
hover_nav_bg_color: '#FFFC', //背景色: 红色 '#c6251b', 白色: '#FFFC'
|
||||
hover_nav_text_color: '#000' // 文字颜色: 白色 '#FFFFFF', 黑色: '#000'
|
||||
},
|
||||
},
|
||||
'green': {
|
||||
name: 'green',
|
||||
main_color: '#19C650',
|
||||
aux_color: '#FA6400',
|
||||
bg_color: '#19C650',
|
||||
bg_color_shallow: '#19C650',
|
||||
promotion_color: '#19C650',
|
||||
promotion_aux_color: '#FA6400',
|
||||
main_color_shallow: '#F0FFF5',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
...{
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#19C650',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#19C650',//按钮颜色
|
||||
goods_btn_color_shallow: '#FA6400',//副按钮颜色
|
||||
},
|
||||
...{
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
...{
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
...{
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
hover_nav_bg_color: '#19C650',//背景色
|
||||
hover_nav_text_color: '#FFFFFF'
|
||||
},
|
||||
},
|
||||
'blue': {
|
||||
name: 'blue',
|
||||
main_color: '#36ABFF',
|
||||
aux_color: '#FA6400',
|
||||
bg_color: '#36ABFF',
|
||||
bg_color_shallow: '#36ABFF',
|
||||
promotion_color: '#36ABFF ',
|
||||
promotion_aux_color: '#FA6400',
|
||||
main_color_shallow: '#E2F3FF',
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
...{
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#36ABFF',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#36ABFF',//按钮颜色
|
||||
goods_btn_color_shallow: '#FA6400',//副按钮颜色
|
||||
},
|
||||
...{
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
...{
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
...{
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
hover_nav_bg_color: '#36ABFF',//背景色
|
||||
hover_nav_text_color: '#FFFFFF'
|
||||
},
|
||||
},
|
||||
'pink': {
|
||||
name: 'pink',
|
||||
main_color: '#FF407E',
|
||||
aux_color: '#F7B500',
|
||||
bg_color: '#FF407E',//主题背景
|
||||
bg_color_shallow: '#FF407E',//主题背景渐变浅色
|
||||
promotion_color: '#FF407E',//活动背景
|
||||
promotion_aux_color: '#F7B500',//活动背景辅色
|
||||
main_color_shallow: '#FFF5F8',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
...{
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#FF407E',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#FF407E',//按钮颜色
|
||||
goods_btn_color_shallow: '#F7B500',//副按钮颜色
|
||||
},
|
||||
...{
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
...{
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
...{
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
hover_nav_bg_color: '#FF407E',//背景色
|
||||
hover_nav_text_color: '#FFFFFF'
|
||||
},
|
||||
},
|
||||
'gold': {
|
||||
name: 'gold',
|
||||
main_color: '#CFAF70',
|
||||
aux_color: '#444444',
|
||||
bg_color: '#CFAF70',//主题背景
|
||||
bg_color_shallow: '#CFAF70',//主题背景渐变浅色
|
||||
promotion_color: '#CFAF70',//活动背景
|
||||
promotion_aux_color: '#444444',//活动背景辅色
|
||||
main_color_shallow: '#FFFAF1',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
...{
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#CFAF70',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#CFAF70',//按钮颜色
|
||||
goods_btn_color_shallow: '#444444',//副按钮颜色
|
||||
},
|
||||
...{
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
...{
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
...{
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
hover_nav_bg_color: '#CFAF70',//背景色
|
||||
hover_nav_text_color: '#FFFFFF'
|
||||
},
|
||||
},
|
||||
'purple': {
|
||||
name: 'purple',
|
||||
main_color: '#A253FF',
|
||||
aux_color: '#222222',
|
||||
bg_color: '#A253FF',//主题背景
|
||||
bg_color_shallow: '#A253FF',//主题背景渐变浅色
|
||||
promotion_color: '#A253FF',//活动背景
|
||||
promotion_aux_color: '#222222',//活动背景辅色
|
||||
main_color_shallow: '#F8F3FF',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
...{
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#A253FF',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#A253FF',//按钮颜色
|
||||
goods_btn_color_shallow: '#222222',//副按钮颜色
|
||||
},
|
||||
...{
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
...{
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
...{
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
hover_nav_bg_color: '#A253FF',//背景色
|
||||
hover_nav_text_color: '#FFFFFF'
|
||||
},
|
||||
},
|
||||
'yellow': {
|
||||
name: 'yellow',
|
||||
main_color: '#FFD009',
|
||||
aux_color: '#1D262E',
|
||||
bg_color: '#FFD009',//主题背景
|
||||
bg_color_shallow: '#FFD009',//主题背景渐变浅色
|
||||
promotion_color: '#FFD009',//活动背景
|
||||
promotion_aux_color: '#1D262E',//活动背景辅色
|
||||
main_color_shallow: '#FFFBEF',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#303133',//按钮文字颜色
|
||||
...{
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#FFD009',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#FFD009',//按钮颜色
|
||||
goods_btn_color_shallow: '#1D262E',//副按钮颜色
|
||||
},
|
||||
...{
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
...{
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
...{
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
hover_nav_bg_color: '#FFD009',//背景色
|
||||
hover_nav_text_color: '#303133'
|
||||
},
|
||||
},
|
||||
'black': {
|
||||
name: 'black',
|
||||
main_color: '#222222',
|
||||
aux_color: '#FFFFFF',
|
||||
bg_color: '#222222',//主题背景
|
||||
bg_color_shallow: '#333333',//主题背景渐变浅色
|
||||
promotion_color: '#222222',//活动背景
|
||||
promotion_aux_color: '#FA8B00',//活动背景辅色
|
||||
main_color_shallow: '#efefef',//淡背景
|
||||
price_color: 'rgba(255,0,0,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
...{
|
||||
goods_price: 'rgba(255,0,0,1)',//价格
|
||||
promotion_tag: '#222222',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#222222',
|
||||
goods_cart_num_corner: '#FF0000',//购物车数量角标
|
||||
goods_btn_color: '#222222',//按钮颜色
|
||||
goods_btn_color_shallow: '#FA8B00',//副按钮颜色
|
||||
},
|
||||
...{
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
...{
|
||||
super_member_start_bg: '#fadcb5',
|
||||
super_member_end_bg: '#f6bd74',
|
||||
super_member_start_text_color: '#ab6126',
|
||||
super_member_end_text_color: '#d19336',
|
||||
},
|
||||
...{
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
...{
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
...{
|
||||
hover_nav_bg_color: '#222222',//背景色
|
||||
hover_nav_text_color: '#FFFFFF'
|
||||
},
|
||||
}
|
||||
}
|
||||
export default {
|
||||
'default': {
|
||||
//红色
|
||||
name: 'default',
|
||||
main_color: '#F4391c',
|
||||
aux_color: '#F7B500',
|
||||
bg_color: '#FF4646',//主题背景
|
||||
bg_color_shallow: '#FF4646',//主题背景渐变浅色
|
||||
promotion_color: '#FF4646',//活动背景
|
||||
promotion_aux_color: '#F7B500',//活动背景辅色
|
||||
main_color_shallow: '#FFF4F4',//淡背景
|
||||
price_color: 'rgb(252,82,39)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
goods_detail: {
|
||||
goods_price: 'rgb(252,82,39,1)',//价格
|
||||
promotion_tag: '#FF4646',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#FF4646',//按钮颜色
|
||||
goods_btn_color_shallow: '#F7B500',//副按钮颜色
|
||||
},
|
||||
pintuan: {
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
super_member: {
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
bargain: {
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
seckill: {
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
giftcard: {
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
groupby: {
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
},
|
||||
'green': {
|
||||
name: 'green',
|
||||
main_color: '#19C650',
|
||||
aux_color: '#FA6400',
|
||||
bg_color: '#19C650',
|
||||
bg_color_shallow: '#19C650',
|
||||
promotion_color: '#19C650',
|
||||
promotion_aux_color: '#FA6400',
|
||||
main_color_shallow: '#F0FFF5',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
goods_detail: {
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#19C650',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#19C650',//按钮颜色
|
||||
goods_btn_color_shallow: '#FA6400',//副按钮颜色
|
||||
},
|
||||
pintuan: {
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
super_member: {
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
bargain: {
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
seckill: {
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
giftcard: {
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
groupby: {
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
},
|
||||
'blue': {
|
||||
name: 'blue',
|
||||
main_color: '#36ABFF',
|
||||
aux_color: '#FA6400',
|
||||
bg_color: '#36ABFF',
|
||||
bg_color_shallow: '#36ABFF',
|
||||
promotion_color: '#36ABFF ',
|
||||
promotion_aux_color: '#FA6400',
|
||||
main_color_shallow: '#E2F3FF',
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
goods_detail: {
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#36ABFF',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#36ABFF',//按钮颜色
|
||||
goods_btn_color_shallow: '#FA6400',//副按钮颜色
|
||||
},
|
||||
pintuan: {
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
super_member: {
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
bargain: {
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
seckill: {
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
giftcard: {
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
groupby: {
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
},
|
||||
'pink': {
|
||||
name: 'pink',
|
||||
main_color: '#FF407E',
|
||||
aux_color: '#F7B500',
|
||||
bg_color: '#FF407E',//主题背景
|
||||
bg_color_shallow: '#FF407E',//主题背景渐变浅色
|
||||
promotion_color: '#FF407E',//活动背景
|
||||
promotion_aux_color: '#F7B500',//活动背景辅色
|
||||
main_color_shallow: '#FFF5F8',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
goods_detail: {
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#FF407E',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#FF407E',//按钮颜色
|
||||
goods_btn_color_shallow: '#F7B500',//副按钮颜色
|
||||
},
|
||||
pintuan: {
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
super_member: {
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
bargain: {
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
seckill: {
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
giftcard: {
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
groupby: {
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
},
|
||||
'gold': {
|
||||
name: 'gold',
|
||||
main_color: '#CFAF70',
|
||||
aux_color: '#444444',
|
||||
bg_color: '#CFAF70',//主题背景
|
||||
bg_color_shallow: '#CFAF70',//主题背景渐变浅色
|
||||
promotion_color: '#CFAF70',//活动背景
|
||||
promotion_aux_color: '#444444',//活动背景辅色
|
||||
main_color_shallow: '#FFFAF1',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
goods_detail: {
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#CFAF70',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#CFAF70',//按钮颜色
|
||||
goods_btn_color_shallow: '#444444',//副按钮颜色
|
||||
},
|
||||
pintuan: {
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
super_member: {
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
bargain: {
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
seckill: {
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
giftcard: {
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
groupby: {
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
},
|
||||
'purple': {
|
||||
name: 'purple',
|
||||
main_color: '#A253FF',
|
||||
aux_color: '#222222',
|
||||
bg_color: '#A253FF',//主题背景
|
||||
bg_color_shallow: '#A253FF',//主题背景渐变浅色
|
||||
promotion_color: '#A253FF',//活动背景
|
||||
promotion_aux_color: '#222222',//活动背景辅色
|
||||
main_color_shallow: '#F8F3FF',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
goods_detail: {
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#A253FF',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#A253FF',//按钮颜色
|
||||
goods_btn_color_shallow: '#222222',//副按钮颜色
|
||||
},
|
||||
pintuan: {
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
super_member: {
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
bargain: {
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
seckill: {
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
giftcard: {
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
groupby: {
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
},
|
||||
'yellow': {
|
||||
name: 'yellow',
|
||||
main_color: '#FFD009',
|
||||
aux_color: '#1D262E',
|
||||
bg_color: '#FFD009',//主题背景
|
||||
bg_color_shallow: '#FFD009',//主题背景渐变浅色
|
||||
promotion_color: '#FFD009',//活动背景
|
||||
promotion_aux_color: '#1D262E',//活动背景辅色
|
||||
main_color_shallow: '#FFFBEF',//淡背景
|
||||
price_color: 'rgba(252,82,39,1)',//价格颜色
|
||||
btn_text_color: '#303133',//按钮文字颜色
|
||||
goods_detail: {
|
||||
goods_price: 'rgba(252,82,39,1)',//价格
|
||||
promotion_tag: '#FFD009',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#FC5227',
|
||||
goods_cart_num_corner: '#FC5227',//购物车数量角标
|
||||
goods_btn_color: '#FFD009',//按钮颜色
|
||||
goods_btn_color_shallow: '#1D262E',//副按钮颜色
|
||||
},
|
||||
pintuan: {
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
super_member: {
|
||||
super_member_start_bg: '#7c7878',
|
||||
super_member_end_bg: '#201a18',
|
||||
super_member_start_text_color: '#FFDBA6',
|
||||
super_member_end_text_color: '#FFEBCA',
|
||||
},
|
||||
bargain: {
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
seckill: {
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
giftcard: {
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
groupby: {
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
},
|
||||
'black': {
|
||||
name: 'black',
|
||||
main_color: '#222222',
|
||||
aux_color: '#FFFFFF',
|
||||
bg_color: '#222222',//主题背景
|
||||
bg_color_shallow: '#333333',//主题背景渐变浅色
|
||||
promotion_color: '#222222',//活动背景
|
||||
promotion_aux_color: '#FA8B00',//活动背景辅色
|
||||
main_color_shallow: '#efefef',//淡背景
|
||||
price_color: 'rgba(255,0,0,1)',//价格颜色
|
||||
btn_text_color: '#FFFFFF',//按钮文字颜色
|
||||
goods_detail: {
|
||||
goods_price: 'rgba(255,0,0,1)',//价格
|
||||
promotion_tag: '#222222',
|
||||
goods_card_bg: '#201A18',//会员卡背景
|
||||
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
|
||||
goods_card_color: '#FFD792',
|
||||
goods_coupon: '#222222',
|
||||
goods_cart_num_corner: '#FF0000',//购物车数量角标
|
||||
goods_btn_color: '#222222',//按钮颜色
|
||||
goods_btn_color_shallow: '#FA8B00',//副按钮颜色
|
||||
},
|
||||
pintuan: {
|
||||
pintuan_label_bg: '#F7B500',
|
||||
pintuan_label_color: '#FFFFFF',
|
||||
pintuan_color: '#FA6400',
|
||||
pintuan_promotion_color: '#FA3A1D',//活动背景
|
||||
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
|
||||
},
|
||||
super_member: {
|
||||
super_member_start_bg: '#fadcb5',
|
||||
super_member_end_bg: '#f6bd74',
|
||||
super_member_start_text_color: '#ab6126',
|
||||
super_member_end_text_color: '#d19336',
|
||||
},
|
||||
bargain: {
|
||||
bargain_promotion_color: '#F0353E',//活动背景
|
||||
bargain_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
seckill: {
|
||||
seckill_promotion_color: '#F83530',//活动背景
|
||||
seckill_promotion_aux_color: '#FD9A01',//活动辅色
|
||||
},
|
||||
giftcard: {
|
||||
giftcard_promotion_color: '#FF3369',//活动背景
|
||||
giftcard_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
groupby: {
|
||||
groupby_promotion_color: '#E64136',//活动背景
|
||||
groupby_promotion_aux_color: '#F7B500',//活动辅色
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* 将常用的Uniapp提供的函数,存放到这里,按需引用
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* 显示错误信息
|
||||
* @param {Exception} err
|
||||
* @param {Boolean} useModal
|
||||
*/
|
||||
const showError = (err, useModal = false) => {
|
||||
const content = err?.message || err?.errMsg || err?.toString();
|
||||
if (!useModal) {
|
||||
uni.showToast({
|
||||
title: content,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
} else {
|
||||
uni.showModal({
|
||||
title: '错误提示',
|
||||
content,
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打电话
|
||||
* @param {string} mobile 电话号码
|
||||
*/
|
||||
export const makePhoneCall = (mobile) => {
|
||||
try {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: `${mobile}`,
|
||||
success(e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文本(返回 Promise)
|
||||
* @param {*} text
|
||||
* @param {*} options
|
||||
* @returns {Promise} 返回 Promise,成功时 resolve,失败时 reject
|
||||
*/
|
||||
export const copyTextAsync = (text, { copySuccess = '', copyFailed = '' } = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 输入验证
|
||||
if (!text && text !== '') {
|
||||
const error = new Error('复制文本不能为空');
|
||||
showError(error);
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// 超时监测
|
||||
const timeoutId = setTimeout(() => {
|
||||
let error = new Error('复制操作长时间无响应,请检查相关权限及配置是否正确');
|
||||
// #ifdef MP-WEIXIN
|
||||
error = new Error([
|
||||
'复制操作长时间无响应!',
|
||||
'原因:',
|
||||
'1.微信平台->用户隐私保护指引->"剪贴板"功能未添加或审核未通过;',
|
||||
'2.微信平台对剪贴板API调用频率有限制'
|
||||
].join('\r\n'));
|
||||
// #endif
|
||||
showError(error, true);
|
||||
reject(error);
|
||||
}, 5000);
|
||||
|
||||
try {
|
||||
uni.setClipboardData({
|
||||
data: `${text}`,
|
||||
success: (res) => {
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
try {
|
||||
if (copySuccess) {
|
||||
uni.showToast({
|
||||
title: copySuccess,
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
showError(e);
|
||||
}
|
||||
|
||||
resolve(res);
|
||||
},
|
||||
fail: (err) => {
|
||||
clearTimeout(timeoutId);
|
||||
try {
|
||||
uni.showToast({
|
||||
title: err.message || err.errMsg || copyFailed || '复制失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
} catch (e) {
|
||||
showError(e);
|
||||
}
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
clearTimeout(timeoutId);
|
||||
showError(err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文本(回调形式,兼容旧代码)
|
||||
* @param {*} text
|
||||
* @param {*} options
|
||||
* @param {Function} callback 回调函数,接收 (success, error) 参数
|
||||
*/
|
||||
export const copyText = (text, options = {}, callback) => {
|
||||
copyTextAsync(text, options)
|
||||
.then(res => {
|
||||
if (callback) callback(true, null);
|
||||
})
|
||||
.catch(err => {
|
||||
if (callback) callback(false, err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开定位
|
||||
* @param {Object} options
|
||||
*/
|
||||
export const openLocation = ({ latitude, longitude, name } = {}) => {
|
||||
try {
|
||||
uni.openLocation({
|
||||
latitude,
|
||||
longitude,
|
||||
name,
|
||||
});
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
}
|
||||
}
|
||||
@@ -7,20 +7,15 @@ import {
|
||||
|
||||
|
||||
|
||||
// 关于页面路径,使用常量导出
|
||||
// 首页路径
|
||||
export const INDEX_PAGE_URL = '/pages/index/index';
|
||||
export const CATEGORY_PAGE_URL = '/pages_goods/category';
|
||||
export const CONTACT_PAGE_URL = '/pages_tool/contact/contact';
|
||||
export const MEMBER_PAGE_URL = '/pages_tool/member/index';
|
||||
export const LOGIN_PAGE_URL = '/pages_tool/login/login';
|
||||
export const AI_CHAT_PAGE_URL = '/pages_tool/ai-chat/index';
|
||||
|
||||
// 当前最新的tabBar.list (参见pages.json 中的tabBar.list 配置)
|
||||
export const systemTabBarList = [
|
||||
INDEX_PAGE_URL,
|
||||
CATEGORY_PAGE_URL,
|
||||
CONTACT_PAGE_URL,
|
||||
MEMBER_PAGE_URL
|
||||
'/pages_goods/category',
|
||||
'/pages_tool/contact/contact',
|
||||
'/pages_tool/member/index'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -37,28 +32,10 @@ export const adaptSubpackageUrl = (url) => {
|
||||
*/
|
||||
// 定义前缀映射表
|
||||
const urlPrefixMap = {
|
||||
'/pages/promotion/': '/pages_promotion/',
|
||||
'/pages/order/': '/pages_order/',
|
||||
'/pages/goods/': '/pages_goods/',
|
||||
|
||||
'/pages/contact/': '/pages_tool/contact/',
|
||||
'/pages/member/': '/pages_tool/member/',
|
||||
'/pages/login/': '/pages_tool/login/',
|
||||
'/pages/agreement/': '/pages_tool/agreement/',
|
||||
'/pages/article/': '/pages_tool/article/',
|
||||
'/pages/cases/': '/pages_tool/cases/',
|
||||
'/pages/contact/': '/pages_tool/contact/',
|
||||
'/pages/files/': '/pages_tool/files/',
|
||||
'/pages/form/': '/pages_tool/form/',
|
||||
'/pages/help/': '/pages_tool/help/',
|
||||
'/pages/notice/': '/pages_tool/notice/',
|
||||
'/pages/pay/': '/pages_tool/pay/',
|
||||
'/pages/recharge/': '/pages_tool/recharge/',
|
||||
'/pages/seal/': '/pages_tool/seal/',
|
||||
'/pages/storeclose/': '/pages_tool/storeclose/',
|
||||
'/pages/vr/': '/pages_tool/vr/',
|
||||
'/pages/weapp/': '/pages_tool/weapp/',
|
||||
'/pages/webview/': '/pages_tool/webview/',
|
||||
'/pages/vr': '/pages_tool/vr/'
|
||||
};
|
||||
|
||||
// 构建正则表达式
|
||||
@@ -84,55 +61,18 @@ export const adaptSubpackageUrl = (url) => {
|
||||
return replacePrefix(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查tabBar是否激活
|
||||
* @param {string} linkUrl 链接路径 /pages/goods/category
|
||||
* @param {string} currentPageRoute 当前页面路径 /pages_goods/category
|
||||
* @returns {boolean} 是否激活
|
||||
*/
|
||||
export const checkTabBarActive = (linkUrl, currentPageRoute) => {
|
||||
const linkUrlParts = adaptSubpackageUrl(linkUrl).split('/');
|
||||
const currentPageRouteParts = currentPageRoute.split('/');
|
||||
|
||||
// console.log('diy-bottom-nav verify:', { linkUrlParts, currentPageRouteParts});
|
||||
|
||||
try {
|
||||
// 二级页面
|
||||
if (linkUrlParts[2] === currentPageRouteParts[2]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 一级页面,限定只能是goods相关
|
||||
if (linkUrlParts[1] === currentPageRouteParts[1] && linkUrlParts[1] === 'pages_goods') {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('diy-bottom-nav verify error:', error);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export default {
|
||||
/** 导出页面URL常量 */
|
||||
MEMBER_PAGE_URL,
|
||||
CATEGORY_PAGE_URL,
|
||||
CONTACT_PAGE_URL,
|
||||
INDEX_PAGE_URL,
|
||||
LOGIN_PAGE_URL,
|
||||
AI_CHAT_PAGE_URL,
|
||||
|
||||
/**
|
||||
* 页面跳转
|
||||
* @param {string} to 跳转链接 /pages/idnex/index
|
||||
* @param {Object} param 参数 {key : value, ...}, 默认{}
|
||||
* @param {string} mode 模式 navigateTo、redirectTo、reLaunch、tabbar, 默认navigateTo
|
||||
* @param {Object} param 参数 {key : value, ...}
|
||||
* @param {string} mode 模式
|
||||
*/
|
||||
redirectTo(to, param = {}, mode = 'navigateTo') {
|
||||
redirectTo(to, param, mode) {
|
||||
let url = to;
|
||||
|
||||
// 替换url中的前缀
|
||||
console.log('页面跳转 redirectTo', to, param, mode);
|
||||
console.log('redirectTo', to, param, mode);
|
||||
url = adaptSubpackageUrl(url);
|
||||
console.log('adaptSubpackageUrl', url);
|
||||
|
||||
@@ -151,7 +91,7 @@ export default {
|
||||
const tabBarUrl = systemTabBarList[i];
|
||||
if (url.indexOf(tabBarUrl) == 0) {
|
||||
// 首页特殊处理,采用switchTab, 其他页面采用redirectTo, 不能返回,不能退回
|
||||
(tabBarUrl == INDEX_PAGE_URL ? uni.switchTab : uni.redirectTo)({ url });
|
||||
(tabBarUrl == INDEX_PAGE_URL ? uni.switchTab : uni.redirectTo)({url});
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -159,26 +99,26 @@ export default {
|
||||
// 如果url不包含tabBarList中的路径,根据mode判断跳转方式
|
||||
switch (mode) {
|
||||
case 'tabbar':
|
||||
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。重置页面栈,仅保留 tabBar 页面
|
||||
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
|
||||
uni.switchTab({
|
||||
url
|
||||
});
|
||||
break;
|
||||
case 'redirectTo':
|
||||
// 关闭当前页面,跳转到应用内的某个页面。替换栈顶页面,长度不变(上限10层)
|
||||
// 关闭当前页面,跳转到应用内的某个页面。
|
||||
uni.redirectTo({
|
||||
url
|
||||
});
|
||||
break;
|
||||
case 'reLaunch':
|
||||
// 关闭所有页面,打开到应用内的某个页面。清空栈后打开新页面,长度=1
|
||||
// 关闭所有页面,打开到应用内的某个页面。
|
||||
uni.reLaunch({
|
||||
url
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// 保留当前页面,跳转到应用内的某个页面,新增页面到栈顶,长度+1(上限10层)
|
||||
console.log('保留当前页面,navigateTo跳转到应用内的某个页面', url);
|
||||
// 保留当前页面,跳转到应用内的某个页面
|
||||
console.log('保留当前页面,跳转到应用内的某个页面', url);
|
||||
uni.navigateTo({
|
||||
url
|
||||
});
|
||||
@@ -190,6 +130,8 @@ export default {
|
||||
* @param {Object} params 参数,针对商品、相册里面的图片区分大中小,size: big、mid、small
|
||||
*/
|
||||
img(img_path, params) {
|
||||
|
||||
|
||||
var path = "";
|
||||
if (img_path != undefined && img_path != "") {
|
||||
if (img_path.split(',').length > 1) {
|
||||
@@ -549,7 +491,7 @@ export default {
|
||||
* 检测苹果X以上的手机
|
||||
*/
|
||||
isIPhoneX() {
|
||||
let res = this.getDeviceInfo();
|
||||
let res = uni.getSystemInfoSync();
|
||||
if (res.model.search('iPhone X') != -1) {
|
||||
return true;
|
||||
}
|
||||
@@ -557,33 +499,13 @@ export default {
|
||||
},
|
||||
//判断安卓还是iOS
|
||||
isAndroid() {
|
||||
let platform = this.getDeviceInfo().platform;
|
||||
let platform = uni.getSystemInfoSync().platform
|
||||
if (platform == 'ios') {
|
||||
return false;
|
||||
} else if (platform == 'android') {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取设备信息(包含降级处理)
|
||||
*/
|
||||
getDeviceInfo() {
|
||||
try {
|
||||
return uni.getDeviceInfo();
|
||||
} catch (e) {
|
||||
return uni.getSystemInfoSync();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取窗口信息(包含降级处理)
|
||||
*/
|
||||
getWindowInfo() {
|
||||
try {
|
||||
return uni.getWindowInfo();
|
||||
} catch (e) {
|
||||
return uni.getSystemInfoSync();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 深度拷贝对象
|
||||
* @param {Object} obj
|
||||
@@ -605,36 +527,6 @@ export default {
|
||||
}
|
||||
return cloneObj
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 打开微信企业客服
|
||||
* @param {Function} fallbackFunc 降级处理函数
|
||||
*/
|
||||
openWxWorkServiceChat(fallbackFunc) {
|
||||
// #ifdef MP-WEIXIN
|
||||
let wxworkConfig = store.state?.wxworkConfig
|
||||
if (wxworkConfig?.enable && wxworkConfig?.contact_url) {
|
||||
// 直接使用活码链接跳转
|
||||
wx.navigateToMiniProgram({
|
||||
appId: 'wxeb490c6f9b154ef9', // 是企业微信官方小程序的AppID(固定值, 由腾讯企业微信团队维护, 不需要修改,用于展示"添加企业微信联系人"的官方页面)
|
||||
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig?.contact_url)}`,
|
||||
success: () => {
|
||||
console.log('跳转企业微信成功');
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('跳转企业微信失败:', err);
|
||||
// 降级处理:使用原有客服方式
|
||||
fallbackFunc && fallbackFunc();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fallbackFunc && fallbackFunc();
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* 自定义模板的跳转链接
|
||||
* @param {Object} link
|
||||
@@ -657,6 +549,7 @@ export default {
|
||||
|
||||
} else if (link.appid) {
|
||||
// 跳转其他小程序
|
||||
|
||||
uni.navigateToMiniProgram({
|
||||
appId: link.appid,
|
||||
path: link.page
|
||||
@@ -664,6 +557,7 @@ export default {
|
||||
|
||||
} else if (link.name == 'MOBILE' && !link.wap_url) {
|
||||
// 拨打电话
|
||||
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: link.mobile,
|
||||
success: (res) => {
|
||||
@@ -696,19 +590,16 @@ export default {
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
this.openWxWorkServiceChat(() => {
|
||||
wx.openCustomerServiceChat({
|
||||
extInfo: {
|
||||
url: config.wxwork_url
|
||||
},
|
||||
corpId: config.corpid,
|
||||
showMessageCard: true,
|
||||
sendMessageTitle: 'this.sendMessageTitle',
|
||||
sendMessagePath: 'this.sendMessagePath',
|
||||
sendMessageImg: 'this.sendMessageImg'
|
||||
});
|
||||
wx.openCustomerServiceChat({
|
||||
extInfo: {
|
||||
url: config.wxwork_url
|
||||
},
|
||||
corpId: config.corpid,
|
||||
showMessageCard: true,
|
||||
sendMessageTitle: 'this.sendMessageTitle',
|
||||
sendMessagePath: 'this.sendMessagePath',
|
||||
sendMessageImg: 'this.sendMessageImg'
|
||||
});
|
||||
|
||||
// #endif
|
||||
break;
|
||||
case 'third':
|
||||
@@ -759,7 +650,7 @@ export default {
|
||||
*/
|
||||
uniappIsIPhoneX() {
|
||||
let isIphoneX = false;
|
||||
let systemInfo = this.getDeviceInfo();
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
// #ifdef MP
|
||||
if (systemInfo.model.search('iPhone X') != -1 || systemInfo.model.search('iPhone 11') != -1 || systemInfo.model.search('iPhone 12') != -1 || systemInfo.model.search('iPhone 13') != -1) {
|
||||
isIphoneX = true;
|
||||
@@ -786,7 +677,7 @@ export default {
|
||||
*/
|
||||
uniappIsIPhone11() {
|
||||
let isIphone11 = false;
|
||||
let systemInfo = this.getDeviceInfo();
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
// #ifdef MP
|
||||
if (systemInfo.model.search('iPhone 11') != -1) {
|
||||
isIphone11 = true;
|
||||
@@ -797,7 +688,7 @@ export default {
|
||||
// #ifdef H5
|
||||
//判断该浏览器是否为safaria浏览器
|
||||
isSafari() {
|
||||
let res = this.getDeviceInfo();
|
||||
let res = uni.getSystemInfoSync();
|
||||
var ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.indexOf('applewebkit') > -1 && ua.indexOf('mobile') > -1 && ua.indexOf('safari') > -1 &&
|
||||
ua.indexOf('linux') === -1 && ua.indexOf('android') === -1 && ua.indexOf('chrome') === -1 &&
|
||||
@@ -836,22 +727,13 @@ export default {
|
||||
let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
|
||||
return routes.length ? routes[routes.length - 1].route : '';
|
||||
},
|
||||
goBack(backUrl = INDEX_PAGE_URL) {
|
||||
goBack(backUrl = '/pages/index/index') {
|
||||
if (getCurrentPages().length == 1) {
|
||||
this.redirectTo(backUrl);
|
||||
} else {
|
||||
uni.navigateBack();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 隐藏“返回首页/小房子”按钮
|
||||
* 这个函数,用到页面show, onshow 的生命周期时
|
||||
*/
|
||||
hideHomeButton() {
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.hideHomeButton();
|
||||
// #endif
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param val 转化时间字符串 (转化时分秒)
|
||||
@@ -1201,74 +1083,5 @@ export default {
|
||||
verifyMobile(mobile) {
|
||||
var parse = /^\d{11}$/.test(mobile);
|
||||
return parse;
|
||||
},
|
||||
/**
|
||||
* 判断是否为快应用环境
|
||||
* @returns {boolean} 是否为快应用
|
||||
*/
|
||||
isQuickApp() {
|
||||
// #ifndef QUICKAPP-WEBVIEW
|
||||
let _isQuickApp = false;
|
||||
try {
|
||||
const ua = navigator?.userAgent?.toLowerCase();
|
||||
// console.log('ua = ', ua);
|
||||
_isQuickApp = ua.indexOf('quickapp') !== -1;
|
||||
|
||||
if (!_isQuickApp) {
|
||||
// 特殊说明由于网站是嵌入到快应用的Webview组件中<web>,UA中不会包含quickapp字符串,
|
||||
// 但是会包含uniacid参数,所以这里通过uniacid参数来判断是否为快应用环境
|
||||
_isQuickApp = ua.indexOf('uniacid=') !== -1;
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
if (!_isQuickApp) {
|
||||
const systemInfo = this.getDeviceInfo();
|
||||
_isQuickApp = systemInfo?.platform === 'quickapp' || process?.env?.UNI_PLATFORM === 'quickapp';
|
||||
}
|
||||
return _isQuickApp;
|
||||
// #endif
|
||||
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* 判断是否为华为快应用环境
|
||||
* @returns {boolean} 是否为华为快应用
|
||||
*/
|
||||
isHuaweiQuickApp() {
|
||||
if (!this.isQuickApp()) return false;
|
||||
|
||||
// #ifndef QUICKAPP-WEBVIEW-HUAWEI
|
||||
const systemInfo = this.getDeviceInfo();
|
||||
return systemInfo.brand === 'HUAWEI' || systemInfo.manufacturer === 'HUAWEI' ||
|
||||
(typeof qh !== 'undefined' && qh.platform === 'huawei');
|
||||
// #endif
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* 蛇形命名转驼峰命名
|
||||
* @param {string} str 蛇形命名字符串
|
||||
* @returns {string} 驼峰命名字符串
|
||||
*/
|
||||
snakeToCamel(str) {
|
||||
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
||||
},
|
||||
|
||||
/**
|
||||
* 蛇形命名转驼峰命名(递归处理对象中的所有属性名)
|
||||
* @param {Object} obj 包含蛇形命名字符串属性的对象
|
||||
* @returns {Object} 驼峰命名字符串属性的对象
|
||||
*/
|
||||
snakeToCamelForObj(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) return obj;
|
||||
if (Array.isArray(obj)) return obj.map(this.snakeToCamelForObj.bind(this));
|
||||
const newObj = {};
|
||||
for (const key in obj) {
|
||||
if (Object.hasOwnProperty.call(obj, key)) {
|
||||
const newKey = this.snakeToCamel(key);
|
||||
newObj[newKey] = this.snakeToCamelForObj(obj[key]);
|
||||
}
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
// 公共微信视频号样式
|
||||
|
||||
// CSS 变量
|
||||
:root {
|
||||
// 尺寸变量
|
||||
--channel-play-btn-size: 80rpx;
|
||||
--channel-play-btn-small-size: 60rpx;
|
||||
--channel-play-btn-icon-size: 40rpx;
|
||||
--channel-play-btn-icon-small-size: 30rpx;
|
||||
--channel-border-radius: 12rpx;
|
||||
--channel-stats-padding: 10rpx;
|
||||
--channel-info-wrap-padding: 10rpx 0;
|
||||
|
||||
// 字体变量
|
||||
--channel-name-font-size: 28rpx;
|
||||
--video-title-font-size: 28rpx;
|
||||
--video-title-small-font-size: 24rpx;
|
||||
--video-stats-font-size: 24rpx;
|
||||
--channel-stats-font-size: 20rpx;
|
||||
|
||||
// 颜色变量
|
||||
--channel-name-color: #333;
|
||||
--video-title-color: #333;
|
||||
--video-title-small-color: #666;
|
||||
--video-stats-color: #999;
|
||||
--channel-stats-color: #fff;
|
||||
--channel-border-color: #f0f0f0;
|
||||
--channel-play-btn-bg: rgba(0, 0, 0, 0.4);
|
||||
--channel-stats-bg: linear-gradient(transparent, rgba(0, 0, 0, 0.6));
|
||||
|
||||
// 间距变量
|
||||
--channel-name-margin-bottom: 4rpx;
|
||||
--video-title-margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 375px) {
|
||||
:root {
|
||||
--channel-play-btn-size: 70rpx;
|
||||
--channel-play-btn-small-size: 50rpx;
|
||||
--channel-play-btn-icon-size: 35rpx;
|
||||
--channel-play-btn-icon-small-size: 25rpx;
|
||||
--channel-name-font-size: 24rpx;
|
||||
--video-title-font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 750px) {
|
||||
:root {
|
||||
--channel-play-btn-size: 90rpx;
|
||||
--channel-play-btn-small-size: 70rpx;
|
||||
--channel-play-btn-icon-size: 45rpx;
|
||||
--channel-play-btn-icon-small-size: 35rpx;
|
||||
--channel-name-font-size: 32rpx;
|
||||
--video-title-font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 播放按钮样式
|
||||
.channel-play-btn {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--channel-play-btn-size);
|
||||
height: var(--channel-play-btn-size);
|
||||
background-color: var(--channel-play-btn-bg);
|
||||
border-radius: 50%;
|
||||
|
||||
.play-icon {
|
||||
width: var(--channel-play-btn-icon-size);
|
||||
height: var(--channel-play-btn-icon-size);
|
||||
}
|
||||
}
|
||||
|
||||
// 小尺寸播放按钮(用于列表)
|
||||
.channel-play-btn.small {
|
||||
width: var(--channel-play-btn-small-size);
|
||||
height: var(--channel-play-btn-small-size);
|
||||
|
||||
.play-icon {
|
||||
width: var(--channel-play-btn-icon-small-size);
|
||||
height: var(--channel-play-btn-icon-small-size);
|
||||
}
|
||||
}
|
||||
|
||||
// 视频统计信息
|
||||
.channel-stats {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--channel-stats-bg);
|
||||
padding: var(--channel-stats-padding);
|
||||
color: var(--channel-stats-color);
|
||||
font-size: var(--channel-stats-font-size);
|
||||
}
|
||||
|
||||
// 视频信息容器
|
||||
.channel-info-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding: var(--channel-info-wrap-padding);
|
||||
|
||||
.channel-name {
|
||||
margin-bottom: var(--channel-name-margin-bottom);
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
font-size: var(--channel-name-font-size);
|
||||
font-weight: 500;
|
||||
color: var(--channel-name-color);
|
||||
}
|
||||
|
||||
.video-title {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
font-size: var(--video-title-small-font-size);
|
||||
color: var(--video-title-small-color);
|
||||
}
|
||||
}
|
||||
|
||||
// 视频标题
|
||||
.video-title {
|
||||
font-size: var(--video-title-font-size);
|
||||
font-weight: 500;
|
||||
color: var(--video-title-color);
|
||||
margin-bottom: var(--video-title-margin-bottom);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
// 视频统计信息(非绝对定位版本)
|
||||
.video-stats {
|
||||
font-size: var(--video-stats-font-size);
|
||||
color: var(--video-stats-color);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<view class="article-wrap" :style="warpCss">
|
||||
<view :class="['list-wrap', value.style]" :style="warpCss">
|
||||
<!-- 自动垂直滚动 -->
|
||||
<swiper class="auto-scroll-swiper" :style="[swiperStyle]" :vertical="swiperConfig.vertical !== false"
|
||||
<swiper class="auto-scroll-swiper" :style="swiperStyle" :vertical="swiperConfig.vertical !== false"
|
||||
:autoplay="swiperConfig.autoplay !== false" :circular="swiperConfig.circular !== false"
|
||||
:interval="swiperConfig.interval || 3000" :duration="swiperConfig.duration || 500"
|
||||
:display-multiple-items="safeDisplayMultipleItems">
|
||||
<swiper-item v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)">
|
||||
<swiper-item v-for="(item, index) in list" :key="index" @click="toDetail(item)">
|
||||
<view class="swiper-item-content">
|
||||
<view :class="['item', value.ornament.type]" :style="itemCss">
|
||||
<view class="article-img">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<view class="time" :style="{ color: value.timecolor }">
|
||||
{{ audiotime }}
|
||||
</view>
|
||||
<view @tap.stop="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"
|
||||
<view @click="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"
|
||||
style="padding-top: 18rpx"></view>
|
||||
</view>
|
||||
<view class="fui-audio style3" :style="{ background: value.background }" v-else>
|
||||
@@ -30,7 +30,7 @@
|
||||
<!-- {{audios[value.id].audiotime}} -->
|
||||
{{ audiotime }}
|
||||
</view>
|
||||
<view @tap.stop="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"></view>
|
||||
<view @click="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
:style="{ color: value.titleStyle.textColor }">低至0元免费拿</view>
|
||||
<view class="head-right"
|
||||
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
||||
@tap.stop="$util.redirectTo('/pages_promotion/bargain/list')">
|
||||
@click="$util.redirectTo('/pages_promotion/bargain/list')">
|
||||
<text>{{ value.titleStyle.more }}</text>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<!-- 商品列表 -->
|
||||
<template v-if="value.template == 'row1-of1'">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -84,7 +84,7 @@
|
||||
|
||||
<template v-if="value.template == 'horizontal-slide'">
|
||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -130,7 +130,7 @@
|
||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
@@ -365,7 +365,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
::v-deep .uni-scroll-view ::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view ::-webkit-scrollbar {
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
display: none;
|
||||
width: 0;
|
||||
@@ -374,7 +374,7 @@ export default {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar {
|
||||
/deep/::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<view data-component-name="diy-bottom-nav" v-if="tabBarList && tabBarList.list">
|
||||
<view class="tab-bar" :style="{ backgroundColor: tabBarList.backgroundColor }">
|
||||
<view class="tabbar-border"></view>
|
||||
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @tap.stop="redirectTo(item.link)">
|
||||
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @click="redirectTo(item.link)">
|
||||
<view class="bd">
|
||||
<block v-if="item.link.wap_url == '/pages_goods/cart'">
|
||||
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2"
|
||||
@@ -59,7 +59,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { adaptSubpackageUrl, checkTabBarActive } from '@/common/js/util.js'
|
||||
import { adaptSubpackageUrl } from '@/common/js/util.js'
|
||||
import DiyMinx from './minx.js'
|
||||
// 底部导航栏
|
||||
export default {
|
||||
@@ -145,16 +145,27 @@ export default {
|
||||
let linkUrl = link.wap_url;
|
||||
|
||||
// 首页特殊处理
|
||||
if (linkUrl === this.$util.INDEX_PAGE_URL && this.name === 'DIY_VIEW_INDEX') {
|
||||
if (linkUrl === '/pages/index/index' && this.name === 'DIY_VIEW_INDEX') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// console.log('diy-bottom-nav verify:', { likkUrl: adaptSubpackageUrl(linkUrl), currentPageRoute: currentPageRoute});
|
||||
|
||||
// 精确匹配当前路径
|
||||
if (adaptSubpackageUrl(linkUrl) === currentPageRoute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return checkTabBarActive(linkUrl, currentPageRoute);
|
||||
// 同属于一个子包的路径,也认为是匹配的
|
||||
try {
|
||||
if (adaptSubpackageUrl(linkUrl).split('/')[1] === currentPageRoute.split('/')[1]) {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('diy-bottom-nav verify error:', error);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view data-component-name="diy-category-item" class="item-wrap" :class="type">
|
||||
<block v-if="type == 'category' && category.child_list && category.child_list.length">
|
||||
<view class="category-adv" v-if="category.image_adv" @tap.stop="diyRedirectTo(category.link_url)">
|
||||
<view class="category-adv" v-if="category.image_adv" @click="diyRedirectTo(category.link_url)">
|
||||
<image :src="$util.img(category.image_adv)" mode="widthFix" />
|
||||
</view>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<view class="category-title">{{ category.category_name }}</view>
|
||||
<view class="category-list">
|
||||
<view class="category-item" v-for="(one, oneIndex) in category.child_list" :key="oneIndex"
|
||||
@tap.stop="$util.redirectTo('/pages_goods/list', { category_id: one.category_id })">
|
||||
@click="$util.redirectTo('/pages_goods/list', { category_id: one.category_id })">
|
||||
<view class="img-box">
|
||||
<image :src="$util.img(one.image)" mode="widthFix" />
|
||||
</view>
|
||||
@@ -23,7 +23,7 @@
|
||||
<view class="category-title">{{ one.category_name }}</view>
|
||||
<view class="category-list">
|
||||
<view class="category-item" v-for="(two, twoIndex) in one.child_list" :key="twoIndex"
|
||||
@tap.stop="$util.redirectTo('/pages_goods/list', { category_id: two.category_id })">
|
||||
@click="$util.redirectTo('/pages_goods/list', { category_id: two.category_id })">
|
||||
<view class="img-box">
|
||||
<image :src="$util.img(two.image)" mode="widthFix" :lazy-load="true" />
|
||||
</view>
|
||||
@@ -44,22 +44,22 @@
|
||||
:class="{ 'screen-category-4': value.template == 4 }" :scroll-with-animation="true"
|
||||
:scroll-into-view="scrollIntoView">
|
||||
<view class="item" id="category-2--1" :class="{ selected: categoryId == -1 }"
|
||||
@tap.stop="selectCategory(-1)">全部</view>
|
||||
@click="selectCategory(-1)">全部</view>
|
||||
<view class="item" :id="'category-2-' + oneIndex"
|
||||
:class="{ selected: categoryId == oneIndex }" @tap.stop="selectCategory(oneIndex)"
|
||||
:class="{ selected: categoryId == oneIndex }" @click="selectCategory(oneIndex)"
|
||||
v-for="(one, oneIndex) in category.child_list" :key="oneIndex">
|
||||
{{ one.category_name }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="iconfont icon-unfold" @tap.stop="$refs.screenCategoryPopup.open()"></view>
|
||||
<view class="iconfont icon-unfold" @click="$refs.screenCategoryPopup.open()"></view>
|
||||
</view>
|
||||
<uni-popup type="top" ref="screenCategoryPopup">
|
||||
<view class="screen-category-popup" @tap.stop="$refs.screenCategoryPopup.close()">
|
||||
<view class="screen-category-popup" @click="$refs.screenCategoryPopup.close()">
|
||||
<scroll-view scroll-y="true" class="screen-category"
|
||||
:class="{ 'screen-category-4': value.template == 4 }">
|
||||
<view class="title">全部</view>
|
||||
<view class="item" :class="{ selected: categoryId == oneIndex }"
|
||||
@tap.stop="selectCategory(oneIndex)" v-for="(one, oneIndex) in category.child_list"
|
||||
@click="selectCategory(oneIndex)" v-for="(one, oneIndex) in category.child_list"
|
||||
:key="oneIndex">
|
||||
{{ one.category_name }}
|
||||
</view>
|
||||
@@ -81,13 +81,13 @@
|
||||
:data-template="value.template">
|
||||
<block v-if="goodsList.length">
|
||||
<view class="goods-item" v-for="(item, index) in goodsList" :key="index">
|
||||
<view class="goods-img" @tap.stop="toDetail(item)">
|
||||
<view class="goods-img" @click="toDetail(item)">
|
||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" />
|
||||
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-wrap">
|
||||
<view class="name-wrap" @tap.stop="toDetail(item)">
|
||||
<view class="name-wrap" @click="toDetail(item)">
|
||||
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
|
||||
</view>
|
||||
<view class="price-wrap">
|
||||
@@ -100,7 +100,7 @@
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询底价' }}</text>
|
||||
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询价' }}</text>
|
||||
</block>
|
||||
</view>
|
||||
<view class="member-price-tag"
|
||||
@@ -122,25 +122,25 @@
|
||||
</view>
|
||||
<!-- <view class="right-wrap" v-if="value.template == 2 || value.template == 4">
|
||||
<block v-if="item.is_virtual">
|
||||
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-if="item.goods_spec_format" class="color-base-bg select-sku" @tap.stop="selectSku(item)">
|
||||
<view v-if="item.goods_spec_format" class="color-base-bg select-sku" @click="selectSku(item)">
|
||||
<text>选规格</text>
|
||||
<text class="num-tag" v-if="item.num">{{ item.num }}</text>
|
||||
</view>
|
||||
<block v-else>
|
||||
<block v-if="cartList['goods_' + item.goods_id]&&cartList['goods_' + item.goods_id]['sku_' + item.sku_id]">
|
||||
<view class="num-action reduce" @tap.stop="reduce(item)">
|
||||
<view class="num-action reduce" @click="reduce(item)">
|
||||
<text class="iconfont icon-jian"></text>
|
||||
</view>
|
||||
<view class="num">{{ cartList['goods_' + item.goods_id]['sku_' + item.sku_id].num }}</view>
|
||||
<view class="num-action" :id="'cart-num-' + index" @tap.stop="increase($event, item)">
|
||||
<view class="num-action" :id="'cart-num-' + index" @click="increase($event, item)">
|
||||
<text class="iconfont icon-jia"></text>
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="num-action" v-else :id="'cart-num-' + index" @tap.stop="increase($event, item, 0)">
|
||||
<view class="num-action" v-else :id="'cart-num-' + index" @click="increase($event, item, 0)">
|
||||
<text class="iconfont icon-jia"></text>
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
@@ -148,7 +148,7 @@
|
||||
</block>
|
||||
</view> -->
|
||||
<!-- <view class="right-wrap" v-if="value.template == 3">
|
||||
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
@@ -158,7 +158,7 @@
|
||||
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" />
|
||||
</view>
|
||||
<!-- <view class="end-tips" ref="endTips" v-if="last && (categoryId == -1 || !category.child_list || (category.child_list && categoryId == category.child_list.length - 1))">已经到底了~</view>
|
||||
<view class="end-tips" ref="endTips" v-else @tap.stop="switchCategory('next')">
|
||||
<view class="end-tips" ref="endTips" v-else @click="switchCategory('next')">
|
||||
<text class="iconfont icon-xiangshangzhanhang"></text>
|
||||
上滑查看下一分类
|
||||
</view> -->
|
||||
@@ -173,13 +173,13 @@
|
||||
<view class="goods-list" :class="{ 'double-column': !isList, 'single-column': isList }"
|
||||
:data-template="value.template">
|
||||
<view class="goods-item" v-for="(item, index) in goodsList" :key="index">
|
||||
<view class="goods-img" @tap.stop="toDetail(item)">
|
||||
<view class="goods-img" @click="toDetail(item)">
|
||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"
|
||||
:lazy-load="true" />
|
||||
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}</view>
|
||||
</view>
|
||||
<view class="info-wrap">
|
||||
<view class="name-wrap" @tap.stop="toDetail(item)">
|
||||
<view class="name-wrap" @click="toDetail(item)">
|
||||
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
|
||||
</view>
|
||||
<view class="price-wrap">
|
||||
@@ -192,7 +192,7 @@
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询底价' }}</text>
|
||||
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询价' }}</text>
|
||||
</block>
|
||||
|
||||
</view>
|
||||
@@ -214,30 +214,30 @@
|
||||
</view>
|
||||
<view class="right-wrap" v-if="value.template == 2">
|
||||
<block v-if="item.is_virtual">
|
||||
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-if="item.goods_spec_format" class="color-base-bg select-sku"
|
||||
@tap.stop="selectSku(item)">
|
||||
@click="selectSku(item)">
|
||||
<text>选规格</text>
|
||||
<text class="num-tag" v-if="item.num">{{ item.num }}</text>
|
||||
</view>
|
||||
<block v-else>
|
||||
<block
|
||||
v-if="cartList['goods_' + item.goods_id] && cartList['goods_' + item.goods_id]['sku_' + item.sku_id]">
|
||||
<view class="num-action reduce" @tap.stop="reduce(item)">
|
||||
<view class="num-action reduce" @click="reduce(item)">
|
||||
<text class="iconfont icon-jian"></text>
|
||||
</view>
|
||||
<view class="num">{{ cartList['goods_' + item.goods_id]['sku_' +
|
||||
item.sku_id].num }}</view>
|
||||
<view class="num-action" :id="'cart-num-' + index"
|
||||
@tap.stop="increase($event, item)">
|
||||
@click="increase($event, item)">
|
||||
<text class="iconfont icon-jia"></text>
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="num-action" v-else :id="'cart-num-' + index"
|
||||
@tap.stop="increase($event, item, 0)">
|
||||
@click="increase($event, item, 0)">
|
||||
<text class="iconfont icon-jia"></text>
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
@@ -245,7 +245,7 @@
|
||||
</block>
|
||||
</view>
|
||||
<view class="right-wrap" v-if="value.template == 3">
|
||||
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1160,7 +1160,7 @@ export default {
|
||||
.right-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
justify-content: end;
|
||||
|
||||
.num {
|
||||
width: auto;
|
||||
@@ -1314,7 +1314,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .uni-popup__wrapper-box {
|
||||
/deep/ .uni-popup__wrapper-box {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@@ -1348,7 +1348,7 @@ export default {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
::v-deep .loading-layer {
|
||||
/deep/ .loading-layer {
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
:style="{ height: 'calc(100vh - ' + tabBarHeight + ')' }">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<!-- <block v-if="value.template == 4">
|
||||
<view class="search-box" v-if="value.search" @tap.stop="$util.redirectTo('/pages_tool/goods/search')" :style="navbarInnerStyle">
|
||||
<view class="search-box" v-if="value.search" @click="$util.redirectTo('/pages_tool/goods/search')" :style="navbarInnerStyle">
|
||||
<view class="search-content">
|
||||
<input type="text" class="uni-input font-size-tag" maxlength="50" :placeholder="$lang('search')" confirm-type="search" @tap.stop="onClickSearch()" disabled="true" />
|
||||
<input type="text" class="uni-input font-size-tag" maxlength="50" :placeholder="$lang('search')" confirm-type="search" @click.stop="onClickSearch()" @tap.stop="onClickSearch()" disabled="true" />
|
||||
<text class="iconfont icon-sousuo3"></text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -13,35 +13,35 @@
|
||||
</block> -->
|
||||
<block v-if="value.template != 4">
|
||||
<!-- <view :style="navbarInnerStyle">商品分类</view> -->
|
||||
<view class="search-box" v-if="value.search" @tap.stop="onClickSearch()"
|
||||
<view class="search-box" v-if="value.search" @click="onClickSearch()" @tap.stop="onClickSearch()"
|
||||
:style="wxSearchHeight">
|
||||
<view class="search-content">
|
||||
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('search')"
|
||||
confirm-type="search" @tap.stop="onClickSearch()"
|
||||
confirm-type="search" @click.stop="onClickSearch()" @tap.stop="onClickSearch()"
|
||||
disabled="true" />
|
||||
<text class="iconfont icon-sousuo3"></text>
|
||||
</view>
|
||||
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
|
||||
@tap.stop.prevent="changeListStyle()"></view>
|
||||
@click.stop.prevent="changeListStyle()"></view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="search-box" v-if="value.search" @tap.stop="onClickSearch()">
|
||||
<view class="search-box" v-if="value.search" @click="onClickSearch()" @tap.stop="onClickSearch()">
|
||||
<view class="search-content">
|
||||
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('search')" confirm-type="search"
|
||||
@tap.stop="onClickSearch()" disabled="true" />
|
||||
@click.stop="onClickSearch()" @tap.stop="onClickSearch()" disabled="true" />
|
||||
<text class="iconfont icon-sousuo3"></text>
|
||||
</view>
|
||||
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
|
||||
@tap.stop.prevent="changeListStyle()"></view>
|
||||
@click.stop.prevent="changeListStyle()"></view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<view class="template-four wx" v-if="value.template == 4">
|
||||
<scroll-view scroll-x="true" class="template-four-wrap" :scroll-with-animation="true"
|
||||
:scroll-into-view="'category-one-' + oneCategorySelect" enable-flex="true">
|
||||
<view class="category-item" :id="'category-one-' + index" v-for="(item, index) in templateFourData"
|
||||
:key="index" :class="{ select: oneCategorySelect == index }" @tap.stop="templateFourOneFn(index)">
|
||||
:key="index" :class="{ select: oneCategorySelect == index }" @click="templateFourOneFn(index)">
|
||||
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
|
||||
<image :src="$util.img(item.image)" mode="aspectFill" />
|
||||
</view>
|
||||
@@ -49,7 +49,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="category-item-all" @tap.stop="$refs.templateFourPopup.open()">
|
||||
<view class="category-item-all" @click="$refs.templateFourPopup.open()">
|
||||
<view class="category-item-all-wrap">
|
||||
<text class="text">展开</text>
|
||||
<image class="img" :src="$util.img('/public/uniapp/category/unfold.png')" mode="aspectFill"></image>
|
||||
@@ -59,7 +59,7 @@
|
||||
<view class="template-four-popup">
|
||||
<scroll-view scroll-y="true" class="template-four-scroll" enable-flex="true">
|
||||
<view class="item" :class="{ selected: oneCategorySelect == index }"
|
||||
@tap.stop="templateFourOneFn(index)" v-for="(item, index) in templateFourData" :key="index">
|
||||
@click="templateFourOneFn(index)" v-for="(item, index) in templateFourData" :key="index">
|
||||
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
|
||||
<image :src="$util.img(item.image)" mode="aspectFill"></image>
|
||||
</view>
|
||||
@@ -67,7 +67,7 @@
|
||||
item.category_name }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="pack-up" @tap.stop="$refs.templateFourPopup.close()">
|
||||
<view class="pack-up" @click="$refs.templateFourPopup.close()">
|
||||
<text>点击收起</text>
|
||||
<text class="iconfont icon-iconangledown-copy"></text>
|
||||
</view>
|
||||
@@ -83,7 +83,7 @@
|
||||
{ select: select == index },
|
||||
{ 'border-bottom': value.template == 4 && select + 1 === index },
|
||||
{ 'border-top': value.template == 4 && select - 1 === index }
|
||||
]" @tap.stop="switchOneCategory(index)">
|
||||
]" @click="switchOneCategory(index)">
|
||||
<view class="">{{ item.category_name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -130,7 +130,7 @@
|
||||
|
||||
<!-- <view class="cart-box" v-if="(value.template == 2 || value.template == 4) && value.quickBuy && storeToken && categoryTree && categoryTree.length">
|
||||
<view class="left-wrap">
|
||||
<view class="cart-icon" ref="cartIcon" :animation="cartAnimation" @tap.stop="$util.redirectTo('/pages_goods/cart')">
|
||||
<view class="cart-icon" ref="cartIcon" :animation="cartAnimation" @click="$util.redirectTo('/pages_goods/cart')">
|
||||
<text class="iconfont icon-ziyuan1"></text>
|
||||
<view class="num" v-if="cartNumber">{{ cartNumber < 99 ? cartNumber : '99+' }}</view>
|
||||
</view>
|
||||
@@ -141,7 +141,7 @@
|
||||
<text class="unit font-size-tag price-font">.{{ cartTotalMoney[1] ? cartTotalMoney[1] : '00' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="right-wrap"><button type="primary" class="settlement-btn" @tap.stop="settlement">去结算</button>
|
||||
<view class="right-wrap"><button type="primary" class="settlement-btn" @click="settlement">去结算</button>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
@@ -161,11 +161,15 @@ let menuButtonInfo = {};
|
||||
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
|
||||
// #endif
|
||||
|
||||
import nsGoodsSkuCategory from '@/components/ns-goods-sku/ns-goods-sku-category.vue';
|
||||
import DiyMinx from './minx.js'
|
||||
var contentWrapHeight, query, cartPosition;
|
||||
|
||||
// 商品分类
|
||||
export default {
|
||||
components: {
|
||||
nsGoodsSkuCategory
|
||||
},
|
||||
name: 'diy-category',
|
||||
props: {
|
||||
value: {
|
||||
@@ -548,7 +552,7 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="scss">
|
||||
.category-page-wrap {
|
||||
width: 100vw;
|
||||
// height: calc(100vh - var(--tab-bar-height, 0));
|
||||
@@ -818,7 +822,7 @@ export default {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
::v-deep .template-four {
|
||||
/deep/ .template-four {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
|
||||
@@ -1,645 +0,0 @@
|
||||
<template>
|
||||
<view class="channel-list-container" :style="[componentStyle, { '--row-count': value.rowCount }]">
|
||||
<!-- 轮播模式 -->
|
||||
<swiper v-if="value.showStyle == 'carousel' && carouselConfig.type != 'hide'" :indicator-dots="isIndicatorDots"
|
||||
:autoplay="carouselConfig.autoplay || false" :interval="carouselConfig.interval || 3000"
|
||||
:duration="carouselConfig.duration || 500" :circular="carouselConfig.circular || false"
|
||||
:style="swiperHeight" class="channel-swiper">
|
||||
<swiper-item v-for="(slide, slideIndex) in swiperSlides" :key="slideIndex">
|
||||
<view :class="['swiper-slide-content', 'row1-of' + value.rowCount]">
|
||||
<view v-for="(item, index) in slide" :key="index" :class="['channel-item', value.mode]">
|
||||
<!-- 视频号视频卡片,轮播模式 -->
|
||||
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
|
||||
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
|
||||
:show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
|
||||
:play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
|
||||
<!-- 固定布局模式 -->
|
||||
<view v-else-if="value.showStyle == 'fixed'" :class="['channel-list', 'row1-of' + value.rowCount]">
|
||||
<view v-for="(item, index) in value.list" :key="index" class="channel-item">
|
||||
<!-- 视频号视频卡片,列表模式 -->
|
||||
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
|
||||
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
|
||||
:show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
|
||||
:play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 其他布局模式(如滚动布局) -->
|
||||
<scroll-view v-else
|
||||
:class="['channel-nav', value.showStyle == 'fixed' ? 'fixed-layout' : 'singleSlide', 'row1-of' + value.rowCount]"
|
||||
:scroll-x="true"
|
||||
:scroll-y="false"
|
||||
:enhanced="true"
|
||||
:bounces="false">
|
||||
<view class="uni-scroll-view-content">
|
||||
<view v-for="(item, index) in value.list" :key="index"
|
||||
:class="['channel-nav-item', value.mode, 'row1-of' + value.rowCount]">
|
||||
<!-- 视频号视频卡片,滚动模式 -->
|
||||
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
|
||||
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
|
||||
:show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
|
||||
:play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 微信视频号列表组件
|
||||
* 支持多种布局模式,包括固定布局和滚动布局
|
||||
* 可配置列数、视频高度、标题行数等属性
|
||||
* 用于在页面中展示多个微信视频号视频
|
||||
*/
|
||||
import DiyMinx from './minx.js'
|
||||
import { wechatChannelUtil, wechatChannelConfig } from './js/wechat-channel.js'
|
||||
|
||||
export default {
|
||||
name: 'diy-channel-list',
|
||||
props: {
|
||||
/**
|
||||
* 组件配置数据
|
||||
* @type {Object}
|
||||
* @default () => ({})
|
||||
* @property {string} showStyle - 显示样式,可选值:carousel, fixed, singleSlide
|
||||
* @property {number} rowCount - 每行显示的视频数量
|
||||
* @property {Array} list - 视频列表数据
|
||||
* @property {string} componentBgColor - 组件背景色
|
||||
* @property {string} componentAngle - 组件圆角类型,可选值:round
|
||||
* @property {number} topAroundRadius - 顶部圆角半径
|
||||
* @property {number} bottomAroundRadius - 底部圆角半径
|
||||
* @property {Object} ornament - 装饰效果配置
|
||||
* @property {boolean} showViewCount - 是否显示播放量,可选值:true, false
|
||||
* @property {number} titleLineClamp - 标题显示行数
|
||||
* @property {string} aspectRatio - 视频比例,可选值:16:9, 3:4
|
||||
* @property {boolean} showPlayBtn - 是否显示播放按钮
|
||||
* @property {Object} coverStyle - 视频封面图样式
|
||||
* @property {Object} playBtnStyle - 播放按钮样式
|
||||
* @property {string} mode - 显示模式, 可选值:video, text, image, graphic
|
||||
* @property {number} imageSize - 图片尺寸(仅在特定模式下使用)
|
||||
* @property {number} pageCount - 每页显示的视频数量
|
||||
* @property {Object} carousel - 轮播配置
|
||||
* @property {string} carousel.type - 轮播类型,可选值:default, hide
|
||||
* @property {boolean} carousel.autoplay - 是否自动播放,默认false
|
||||
* @property {number} carousel.interval - 自动播放间隔,默认3000ms
|
||||
* @property {number} carousel.duration - 切换动画时长,默认500ms
|
||||
* @property {boolean} carousel.circular - 是否循环播放,默认false
|
||||
*/
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
mixins: [DiyMinx],
|
||||
data() {
|
||||
return {
|
||||
pageWidth: '', // 页面宽度
|
||||
indicatorDots: false, // 是否显示轮播指示器
|
||||
swiperCurrent: 0 // 当前轮播索引
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 组件创建时的逻辑
|
||||
// 可以在这里进行初始化操作,如获取页面宽度等
|
||||
},
|
||||
mounted() {
|
||||
// 组件挂载后添加鼠标拖拽滚动功能
|
||||
if (!['fixed', 'carousel'].includes(this.value?.showStyle)) {
|
||||
this.$nextTick(() => {
|
||||
this.addMouseDragScroll();
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/**
|
||||
* 组件刷新监听
|
||||
* 当组件需要刷新时触发
|
||||
* @param {*} newValue - 新值
|
||||
*/
|
||||
componentRefresh(newValue) {
|
||||
// 监听组件刷新
|
||||
// 可以在这里处理组件刷新时的逻辑
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
carouselConfig() {
|
||||
return this.value?.carousel || {
|
||||
type: 'default',
|
||||
autoplay: false,
|
||||
interval: 3000,
|
||||
duration: 500,
|
||||
circular: true
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件样式
|
||||
* 根据配置动态生成样式字符串,包括背景色、圆角、阴影和边框
|
||||
* @returns {string} 样式字符串
|
||||
*/
|
||||
componentStyle() {
|
||||
const style = {};
|
||||
// 背景色
|
||||
if (this.value?.componentBgColor) {
|
||||
style.backgroundColor = this.value?.componentBgColor;
|
||||
}
|
||||
|
||||
// 圆角样式
|
||||
if (this.value?.componentAngle == 'round') {
|
||||
style.borderTopLeftRadius = (2 * this.value?.topAroundRadius) + 'rpx';
|
||||
style.borderTopRightRadius = (2 * this.value?.topAroundRadius) + 'rpx';
|
||||
style.borderBottomLeftRadius = (2 * this.value?.bottomAroundRadius) + 'rpx';
|
||||
style.borderBottomRightRadius = (2 * this.value?.bottomAroundRadius) + 'rpx';
|
||||
}
|
||||
|
||||
// 装饰效果:阴影
|
||||
style.boxShadow = this.value?.ornament?.type == 'shadow' ? '0 0 10rpx ' + this.value?.ornament?.color : '';
|
||||
// 装饰效果:边框
|
||||
style.border = this.value?.ornament?.type == 'stroke' ? '2rpx solid ' + this.value?.ornament?.color : '';
|
||||
|
||||
return style;
|
||||
},
|
||||
|
||||
/**
|
||||
* 轮播高度
|
||||
* 根据模式和配置计算轮播高度
|
||||
* @returns {string} 轮播高度样式
|
||||
*/
|
||||
swiperHeight() {
|
||||
let height = 0;
|
||||
|
||||
const pageCount = this.value?.pageCount || 1;
|
||||
|
||||
// 根据不同模式计算高度
|
||||
if (this.value?.mode == 'graphic') {
|
||||
height = (49 + this.value?.imageSize) * pageCount;
|
||||
} else if (this.value?.mode == 'img') {
|
||||
height = (22 + this.value?.imageSize) * pageCount;
|
||||
} else if (this.value?.mode == 'text') {
|
||||
height = 43 * pageCount;
|
||||
} else { // 默认视频模式
|
||||
if (this.value?.aspectRatio == '16:9') {
|
||||
height = [250, 160, 140, 120][this.value.rowCount - 1];
|
||||
} else {
|
||||
height = [510, 280, 220, 180][this.value.rowCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return 'height:' + (2 * height) + 'rpx';
|
||||
},
|
||||
|
||||
/**
|
||||
* 是否显示指示器
|
||||
* 根据轮播配置和列表长度判断是否显示指示器
|
||||
* @returns {boolean} 是否显示指示器
|
||||
*/
|
||||
isIndicatorDots() {
|
||||
// 当轮播类型不是隐藏,且视频数量超过一页时显示指示器
|
||||
const pageCount = this.value?.pageCount || 1;
|
||||
return this.value?.carousel?.type != 'hide' && Math.ceil(this.value?.list?.length / (pageCount * this.value?.rowCount)) > 1
|
||||
},
|
||||
|
||||
/**
|
||||
* 轮播幻灯片数据
|
||||
* 将视频列表分割成轮播所需的幻灯片数据
|
||||
* @returns {Array} 轮播幻灯片数据
|
||||
*/
|
||||
swiperSlides() {
|
||||
const slides = [];
|
||||
const list = this.value?.list || [];
|
||||
const pageSize = (this.value?.pageCount || 1) * (this.value?.rowCount || 1);
|
||||
|
||||
// 将列表数据分割成每页显示的数量
|
||||
for (let i = 0; i < list.length; i += pageSize) {
|
||||
slides.push(list.slice(i, i + pageSize));
|
||||
}
|
||||
|
||||
return slides;
|
||||
},
|
||||
/**
|
||||
* 视频封面样式
|
||||
* 根据aspectRatio属性动态计算封面样式
|
||||
* @returns {Object} 封面样式对象
|
||||
*/
|
||||
computedCoverStyle() {
|
||||
const aspectRatio = this.value?.aspectRatio || '16:9';
|
||||
let paddingTop = '56.25%'; // 默认 16:9 比例
|
||||
|
||||
if (aspectRatio === '3:4') {
|
||||
paddingTop = '133.33%'; // 3:4 比例
|
||||
}
|
||||
|
||||
return {
|
||||
width: '100%',
|
||||
height: '0',
|
||||
paddingTop: paddingTop
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 播放视频
|
||||
* 触发 video-play 事件,并在微信小程序中调用视频播放接口
|
||||
* @param {Object} item - 视频数据对象
|
||||
*/
|
||||
async playVideo(item) {
|
||||
await this.__$emitEvent({
|
||||
eventName: 'video-play',
|
||||
data: item,
|
||||
promiseCallback: async (event, handler, awaitedResult) => {
|
||||
if (!awaitedResult) return;
|
||||
try {
|
||||
// 发送视频被点击播放事件
|
||||
this.$emit('channel-video-click-play', item);
|
||||
console.log('播放视频:', item);
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 在微信小程序环境中调用视频播放接口
|
||||
await wechatChannelUtil.playVideo(item);
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
if (item?.channelType === 'wechat') {
|
||||
uni.showToast({
|
||||
title: '视频号仅支持在微信小程序环境中播放',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
} else {
|
||||
// 在非微信小程序环境中,直接触发事件
|
||||
this.$emit('video-play', item);
|
||||
}
|
||||
// #endif
|
||||
} catch (err) {
|
||||
console.error('打开视频号失败', err);
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 图片加载错误处理
|
||||
* 当图片加载失败时,设置默认图片
|
||||
* @param {number} index - 图片索引
|
||||
*/
|
||||
imgError(index) {
|
||||
// 图片加载失败的处理逻辑
|
||||
console.log('图片加载失败:', index);
|
||||
// 为失败的图片设置默认图片
|
||||
const item = this.value.list[index];
|
||||
if (item) {
|
||||
// 使用默认图片替代加载失败的图片
|
||||
// #ifdef MP-WEIXIN
|
||||
item.coverUrl = wechatChannelConfig.video.defaultCoverUrl;
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 添加鼠标拖拽滚动功能
|
||||
* 在Web环境中实现与微信小程序相同的拖拽滚动效果
|
||||
*/
|
||||
addMouseDragScroll() {
|
||||
// 只在Web环境中添加
|
||||
// #ifndef MP
|
||||
console.log('addMouseDragScroll called');
|
||||
|
||||
let isDragging = false;
|
||||
let startX = 0;
|
||||
let startScrollLeft = 0;
|
||||
let currentScrollElement = null;
|
||||
|
||||
// 查找最近的可滚动祖先元素
|
||||
const findScrollableParent = (element) => {
|
||||
while (element && element !== document) {
|
||||
const style = window.getComputedStyle(element);
|
||||
if (style.overflowX === 'auto' || style.overflowX === 'scroll') {
|
||||
return element;
|
||||
}
|
||||
element = element.parentElement;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// 鼠标按下事件
|
||||
const handleMouseDown = (e) => {
|
||||
// 检查是否点击在组件内
|
||||
if (this.$el.contains(e.target)) {
|
||||
console.log('mousedown event in component:', e);
|
||||
// 查找可滚动元素
|
||||
currentScrollElement = findScrollableParent(e.target);
|
||||
if (currentScrollElement) {
|
||||
console.log('Found scrollable element:', currentScrollElement);
|
||||
isDragging = true;
|
||||
startX = e.pageX;
|
||||
startScrollLeft = currentScrollElement.scrollLeft;
|
||||
currentScrollElement.style.cursor = 'grabbing';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 鼠标移动事件
|
||||
const handleMouseMove = (e) => {
|
||||
if (!isDragging || !currentScrollElement) return;
|
||||
console.log('mousemove event:', e);
|
||||
e.preventDefault();
|
||||
const dx = e.pageX - startX;
|
||||
currentScrollElement.scrollLeft = startScrollLeft - dx;
|
||||
console.log('scrollLeft:', currentScrollElement.scrollLeft);
|
||||
};
|
||||
|
||||
// 鼠标释放事件
|
||||
const handleMouseUp = () => {
|
||||
if (isDragging && currentScrollElement) {
|
||||
console.log('mouseup event');
|
||||
currentScrollElement.style.cursor = 'grab';
|
||||
}
|
||||
isDragging = false;
|
||||
currentScrollElement = null;
|
||||
};
|
||||
|
||||
// 添加全局事件监听器
|
||||
document.addEventListener('mousedown', handleMouseDown);
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
document.addEventListener('mouseleave', handleMouseUp);
|
||||
|
||||
console.log('Global mouse event listeners added');
|
||||
|
||||
// 组件销毁时移除事件监听器
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
document.removeEventListener('mousedown', handleMouseDown);
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
document.removeEventListener('mouseleave', handleMouseUp);
|
||||
console.log('Global mouse event listeners removed');
|
||||
});
|
||||
|
||||
// 为所有.channel-nav元素添加必要的样式
|
||||
setTimeout(() => {
|
||||
const channelNavs = document.querySelectorAll('.channel-nav');
|
||||
console.log('Found channel-nav elements:', channelNavs.length);
|
||||
channelNavs.forEach(element => {
|
||||
element.style.overflowX = 'auto';
|
||||
element.style.overflowY = 'hidden';
|
||||
element.style.whiteSpace = 'nowrap';
|
||||
element.style.width = '100%';
|
||||
element.style.maxWidth = '100%';
|
||||
element.style.cursor = 'grab';
|
||||
element.style.userSelect = 'none'; // 防止文本选择
|
||||
console.log('Added styles to channel-nav:', element);
|
||||
});
|
||||
}, 100); // 延迟执行,确保DOM已完全渲染
|
||||
|
||||
console.log('Mouse drag scroll setup completed');
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './css/common-channel.scss';
|
||||
|
||||
.channel-list-container {
|
||||
padding: 16px 16px 0px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表布局样式
|
||||
*/
|
||||
.channel-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--row-count, 2), 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航布局样式
|
||||
* 支持固定布局和滚动布局
|
||||
*/
|
||||
.channel-nav {
|
||||
box-sizing: border-box;
|
||||
padding: 16rpx;
|
||||
|
||||
// 确保在H5环境中可以水平滚动
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
|
||||
// 隐藏滚动条但保留滚动功能
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
// 启用触摸滚动和鼠标拖拽滚动
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scroll-behavior: smooth;
|
||||
|
||||
.uni-scroll-view-content {
|
||||
/* #ifdef MP-WEIXIN */
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 16rpx;
|
||||
/* #endif */
|
||||
/* #ifndef MP-WEIXIN */
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--row-count, 2), 1fr);
|
||||
gap: 16rpx;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
// 单滑动模式
|
||||
&.singleSlide {
|
||||
.uni-scroll-view-content {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 16rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.channel-nav-item {
|
||||
flex-shrink: 0;
|
||||
width: 280rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.channel-nav-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
|
||||
/* #ifdef MP-WEIXIN */
|
||||
&.row1-of1 {
|
||||
width: 100%;
|
||||
}
|
||||
&.row1-of2 {
|
||||
width: calc(50% - 8rpx);
|
||||
}
|
||||
&.row1-of3 {
|
||||
width: calc(33.333% - 10.67rpx);
|
||||
}
|
||||
&.row1-of4 {
|
||||
width: calc(25% - 12rpx);
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
// 1 列布局
|
||||
&.row1-of1 {
|
||||
.uni-scroll-view-content {
|
||||
// #ifndef MP-WEIXIN
|
||||
grid-template-columns: 1fr;
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
|
||||
// 2 列布局
|
||||
&.row1-of2 {
|
||||
.uni-scroll-view-content {
|
||||
// #ifndef MP-WEIXIN
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
// #endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 3 列布局
|
||||
&.row1-of3 {
|
||||
.uni-scroll-view-content {
|
||||
// #ifndef MP-WEIXIN
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
// #endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 4 列布局
|
||||
&.row1-of4 {
|
||||
.uni-scroll-view-content {
|
||||
// #ifndef MP-WEIXIN
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
// #endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保所有视频卡片高度一致
|
||||
*/
|
||||
.channel-item,
|
||||
.channel-nav-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮播样式
|
||||
* 支持轮播模式的布局和样式
|
||||
*/
|
||||
.channel-swiper {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.swiper-slide-content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--row-count, 2), 1fr);
|
||||
gap: 16rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.channel-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// 轮播模式下的 1 列布局
|
||||
&.row1-of1 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
// 轮播模式下的 2 列布局
|
||||
&.row1-of2 {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
// 轮播模式下的 3 列布局
|
||||
&.row1-of3 {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
// 轮播模式下的 4 列布局
|
||||
&.row1-of4 {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应式调整
|
||||
* 在小屏幕设备上调整布局和间距
|
||||
*/
|
||||
@media (max-width: 375px) {
|
||||
|
||||
.channel-list,
|
||||
.channel-nav,
|
||||
.channel-swiper .swiper-slide-content {
|
||||
gap: 12rpx;
|
||||
padding: 12rpx;
|
||||
}
|
||||
|
||||
// 小屏幕上的单滑动模式
|
||||
.channel-nav {
|
||||
&.singleSlide {
|
||||
.uni-scroll-view-content {
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.channel-nav-item {
|
||||
width: 240rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频比例样式调整
|
||||
* 根据不同的视频比例调整布局
|
||||
*/
|
||||
|
||||
// // 3:4 比例的视频卡片样式
|
||||
// .channel-video.ratio-3-4 {
|
||||
// // 调整视频卡片的整体高度
|
||||
// ::v-deep .video-cover-wrap {
|
||||
// padding-top: 133.33%; // 3:4 比例
|
||||
// }
|
||||
|
||||
// // 列表模式下的3:4比例调整
|
||||
// &.list-mode {
|
||||
// ::v-deep .video-cover-wrap {
|
||||
// padding-top: 133.33%; // 3:4 比例
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 16:9 比例的视频卡片样式(默认)
|
||||
// .channel-video.ratio-16-9 {
|
||||
// // 保持默认的16:9比例
|
||||
// ::v-deep .video-cover-wrap {
|
||||
// padding-top: 56.25%; // 16:9 比例
|
||||
// }
|
||||
|
||||
// // 列表模式下的16:9比例保持默认
|
||||
// &.list-mode {
|
||||
// ::v-deep .video-cover-wrap {
|
||||
// padding-top: 56.25%; // 16:9 比例
|
||||
// }
|
||||
// }
|
||||
// }</style>
|
||||
@@ -1,489 +0,0 @@
|
||||
<template>
|
||||
<view class="channel-video" :class="{ 'list-mode': listMode }">
|
||||
<!-- 嵌入式视频播放 -->
|
||||
<view v-if="canUseEmbedMode" class="embed-video-container">
|
||||
<view class="video-cover-wrap" :style="[coverStyle]">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<native-component>
|
||||
<!-- 嵌入式视频播放组件 -->
|
||||
<channel-video :feed-id="value.feedId" :finder-user-name="value.finderUserName"
|
||||
:feed-token="value.feedToken" :auto-play="autoPlay">
|
||||
</channel-video>
|
||||
</native-component>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<view class="video-info">
|
||||
<!-- 视频标题,支持多行显示控制 -->
|
||||
<view class="video-title" :style="{ '--title-line-clamp': titleLineClamp }">{{ value.videoTitle }}
|
||||
</view>
|
||||
<!-- 视频统计信息 -->
|
||||
<view class="video-stats" v-if="showViewCount && value.showViewCount">{{ value.viewCount }}次观看</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 跳转式视频播放 -->
|
||||
<view v-else @tap.stop="playVideo" class="video-container">
|
||||
<view class="video-cover-wrap" :style="[coverStyle]">
|
||||
<image class="video-cover" :src="$util.img(value.coverUrl)" mode="aspectFill"></image>
|
||||
<view class="channel-play-btn" v-if="showPlayBtn" :style="[playBtnStyle]">
|
||||
<view class="play-icon-css"></view>
|
||||
</view>
|
||||
<view class="video-stats-overlay" v-if="showViewCount && value.showViewCount">
|
||||
{{ value.viewCount }}次观看
|
||||
</view>
|
||||
</view>
|
||||
<view class="video-info">
|
||||
<!-- 视频标题,支持多行显示控制 -->
|
||||
<view class="video-title" :style="{ '--title-line-clamp': titleLineClamp }">{{ value.videoTitle }}
|
||||
</view>
|
||||
<!-- 视频统计信息,非列表模式下显示 -->
|
||||
<view class="video-stats" v-if="showViewCount && value.showViewCount && !listMode">{{ value.viewCount }}次观看</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { wechatChannelUtil, wechatChannelConfig } from './js/wechat-channel.js'
|
||||
|
||||
/**
|
||||
* 微信视频号视频卡片组件
|
||||
* 支持嵌入式播放和跳转式播放两种模式
|
||||
* 可配置列表模式、视频高度、标题行数等属性
|
||||
*/
|
||||
export default {
|
||||
name: 'diy-channel-video',
|
||||
props: {
|
||||
/**
|
||||
* 视频数据对象
|
||||
* @type {Object}
|
||||
* @required
|
||||
* @property {string} feedId - 视频 feedId
|
||||
* @property {string} feedToken - 视频 token
|
||||
* @property {string} coverUrl - 视频封面图
|
||||
* @property {string} videoTitle - 视频标题
|
||||
* @property {number} viewCount - 观看次数
|
||||
* @property {boolean} showViewCount - 是否显示观看次数
|
||||
* @property {boolean} embedMode - 是否启用嵌入式播放
|
||||
*/
|
||||
value: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
/**
|
||||
* 是否为列表模式
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
listMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 是否显示观看次数,由父组件可以整体配置 */
|
||||
showViewCount: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/**
|
||||
* 标题显示行数
|
||||
* @type {number}
|
||||
* @default 1
|
||||
*/
|
||||
titleLineClamp: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
/** 是否显示播放按钮 */
|
||||
showPlayBtn: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/**
|
||||
* 视频封面图样式
|
||||
* 采用 16:9 比例的响应式高度
|
||||
*/
|
||||
coverStyle: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
width: '100%',
|
||||
height: '0',
|
||||
paddingTop: '56.25%' // 16:9 比例
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 播放按钮样式
|
||||
*/
|
||||
playBtnStyle: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
width: '60rpx',
|
||||
height: '60rpx',
|
||||
borderRadius: '30rpx',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)'
|
||||
})
|
||||
},
|
||||
/** 是否自动播放 */
|
||||
autoPlay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* 是否支持嵌入式播放
|
||||
* @returns {boolean}
|
||||
*/
|
||||
canUseEmbedMode() {
|
||||
// #ifdef MP-WEIXIN
|
||||
const enableEmbedMode = Boolean(this.value?.embedMode)
|
||||
&& Boolean(this.value?.feedToken)
|
||||
&& wechatChannelUtil.isEmbedModeSupported();
|
||||
console.log('enableEmbedMode', enableEmbedMode);
|
||||
return enableEmbedMode;
|
||||
// #endif
|
||||
return false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 播放视频
|
||||
* 触发 video-play 事件,由父组件处理具体播放逻辑
|
||||
*/
|
||||
async playVideo() {
|
||||
this.$emit('video-play', this.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import './css/common-channel.scss';
|
||||
|
||||
/**
|
||||
* 视频卡片容器样式
|
||||
* 包含卡片基础样式、悬停效果和列表模式样式
|
||||
*/
|
||||
.channel-video {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
// 悬停效果
|
||||
&:hover {
|
||||
transform: translateY(-4rpx);
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
// 列表模式样式调整
|
||||
&.list-mode {
|
||||
border-radius: 10rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.08);
|
||||
|
||||
.video-info {
|
||||
padding: 14rpx;
|
||||
|
||||
.video-title {
|
||||
font-size: 24rpx;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频容器样式
|
||||
* 用于跳转式播放模式
|
||||
*/
|
||||
.video-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* 嵌入式视频容器样式
|
||||
* 与视频容器样式保持一致
|
||||
*/
|
||||
.embed-video-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频封面容器
|
||||
*/
|
||||
.video-cover-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 56.25%;
|
||||
/* 16:9 比例 */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12rpx 12rpx 0 0;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
// 悬停时缩放效果
|
||||
.channel-video:hover & {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
// 列表模式下的边框圆角调整
|
||||
.channel-video.list-mode & {
|
||||
border-radius: 10rpx 10rpx 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频封面图片
|
||||
* 绝对定位填充整个容器
|
||||
*/
|
||||
.video-cover {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频统计信息遮罩
|
||||
* 显示在视频封面底部
|
||||
*/
|
||||
.video-stats-overlay {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
|
||||
padding: 12rpx 16rpx;
|
||||
color: #fff;
|
||||
font-size: 20rpx;
|
||||
text-align: right;
|
||||
font-weight: 500;
|
||||
transition: opacity 0.3s ease;
|
||||
|
||||
// 悬停时的透明度变化
|
||||
.channel-video:hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.channel-video:not(:hover) & {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频信息区域
|
||||
* 包含标题和统计信息
|
||||
*/
|
||||
.video-info {
|
||||
padding: 16rpx;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
background-color: #fff;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
// 悬停时的背景色变化
|
||||
.channel-video:hover & {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频标题
|
||||
* 支持多行显示控制和渐变遮罩效果
|
||||
*/
|
||||
.video-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
margin-bottom: 10rpx;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: var(--title-line-clamp, 2);
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: color 0.3s ease;
|
||||
position: relative;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
white-space: normal;
|
||||
|
||||
// 悬停时的颜色变化
|
||||
.channel-video:hover & {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
// 列表模式下的样式调整
|
||||
.channel-video.list-mode & {
|
||||
-webkit-line-clamp: var(--title-line-clamp, 1);
|
||||
font-size: 24rpx;
|
||||
margin-bottom: 6rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
// 添加渐变遮罩效果,让过长的文字有柔和的结束
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 40rpx;
|
||||
height: 1.4em;
|
||||
background: linear-gradient(to right, transparent, #fff 90%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// 列表模式下的遮罩高度调整
|
||||
.channel-video.list-mode &::after {
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
// 根据行数调整遮罩高度
|
||||
&[style*="--title-line-clamp: 1"]::after {
|
||||
height: 1.4em;
|
||||
}
|
||||
|
||||
&[style*="--title-line-clamp: 3"]::after {
|
||||
height: 4.2em;
|
||||
}
|
||||
|
||||
&[style*="--title-line-clamp: 4"]::after {
|
||||
height: 5.6em;
|
||||
}
|
||||
|
||||
// 列表模式下的多行遮罩高度调整
|
||||
.channel-video.list-mode &[style*="--title-line-clamp: 1"]::after {
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.channel-video.list-mode &[style*="--title-line-clamp: 3"]::after {
|
||||
height: 3.9em;
|
||||
}
|
||||
|
||||
.channel-video.list-mode &[style*="--title-line-clamp: 4"]::after {
|
||||
height: 5.2em;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频统计信息
|
||||
* 显示观看次数等数据
|
||||
*/
|
||||
.video-stats {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
margin-top: 6rpx;
|
||||
transition: color 0.3s ease;
|
||||
|
||||
// 悬停时的颜色变化
|
||||
.channel-video:hover & {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表模式下的播放按钮样式
|
||||
* 更小的尺寸和悬停效果
|
||||
*/
|
||||
.channel-video.list-mode .channel-play-btn {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
// 悬停效果
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
// 播放图标尺寸
|
||||
.play-icon {
|
||||
width: 25rpx;
|
||||
height: 25rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用播放按钮样式优化
|
||||
* 添加悬停效果
|
||||
*/
|
||||
.channel-play-btn {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
// 悬停效果
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 纯 CSS 播放按钮图标
|
||||
*/
|
||||
.play-icon-css {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 12rpx solid transparent;
|
||||
border-bottom: 12rpx solid transparent;
|
||||
border-left: 18rpx solid #fff;
|
||||
margin-left: 4rpx;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
// 悬停时的缩放效果
|
||||
.channel-play-btn:hover & {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
// 列表模式下的尺寸调整
|
||||
.channel-video.list-mode & {
|
||||
border-top: 10rpx solid transparent;
|
||||
border-bottom: 10rpx solid transparent;
|
||||
border-left: 15rpx solid #fff;
|
||||
margin-left: 3rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 原生组件样式控制
|
||||
* 确保 native-component 和 channel-video 正确填充容器
|
||||
*/
|
||||
native-component {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* channel-video 组件样式控制
|
||||
* 避免受到 wx-channel-video 全局样式的影响
|
||||
*/
|
||||
channel-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
@@ -16,7 +16,7 @@
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style1-bg.png') + ')',
|
||||
marginRight: couponItemHeight + 'px',
|
||||
marginLeft: couponItemHeight + 'px'
|
||||
}" @tap.stop="couponAction(item, index)">
|
||||
}" @click="couponAction(item, index)">
|
||||
|
||||
<view class="coupon-info">
|
||||
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
||||
@@ -52,7 +52,7 @@
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_bg1.png') + ')',
|
||||
marginRight: couponItemHeight + 'px',
|
||||
marginLeft: couponItemHeight + 'px'
|
||||
}" @tap.stop="couponAction(item, index)">
|
||||
}" @click="couponAction(item, index)">
|
||||
<view class="coupon-info">
|
||||
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
||||
v-if="!parseInt(item.discount)">
|
||||
@@ -87,7 +87,7 @@
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_shu.png') + ')',
|
||||
marginRight: couponItemHeight + 'px',
|
||||
marginLeft: couponItemHeight + 'px'
|
||||
}" @tap.stop="couponAction(item, index)">
|
||||
}" @click="couponAction(item, index)">
|
||||
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
||||
v-if="!parseInt(item.discount)">
|
||||
<text class="font-size-tag coupon-sign">¥</text>
|
||||
@@ -124,7 +124,7 @@
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style4_bg.png') + ')',
|
||||
marginRight: couponItemHeight + 'px',
|
||||
marginLeft: couponItemHeight + 'px'
|
||||
}" @tap.stop="couponAction(item, index)">
|
||||
}" @click="couponAction(item, index)">
|
||||
<view class="coupon-info">
|
||||
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
||||
v-if="!parseInt(item.discount)">
|
||||
@@ -153,7 +153,7 @@
|
||||
<view class="coupon-all">
|
||||
<view class="coupon-box">
|
||||
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index"
|
||||
@tap.stop="couponAction(item, index)">
|
||||
@click="couponAction(item, index)">
|
||||
<image :src="$util.img('public/uniapp/coupon/style5_bg.png')"></image>
|
||||
<view class="coupon">
|
||||
<view class="coupon-info">
|
||||
@@ -199,7 +199,7 @@
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-1.png') + ')',
|
||||
marginRight: couponItemHeight + 'px',
|
||||
marginLeft: couponItemHeight + 'px'
|
||||
}" @tap.stop="couponAction(item, index)">
|
||||
}" @click="couponAction(item, index)">
|
||||
<view class="coupon-content">
|
||||
<view class="price-wrap">
|
||||
<text class="price" :style="{ color: value.moneyColor }">{{ (item.discount == '0.00'
|
||||
@@ -229,7 +229,7 @@
|
||||
<text class="limit" :style="{ color: value.limitColor }" v-else>无门槛使用</text>
|
||||
</view>
|
||||
|
||||
<div v-if="computedCouponList.length <= 2" @tap.stop="$util.redirectTo('/pages_goods/category')"
|
||||
<div v-if="computedCouponList.length <= 2" @click="$util.redirectTo('/pages_goods/category')"
|
||||
class="coupon coupon-null" :style="{
|
||||
color: value.moneyColor,
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-2.png') + ')',
|
||||
@@ -250,7 +250,7 @@
|
||||
<scroll-view class="coupon-style-seven" scroll-x="true">
|
||||
<view class="wrap">
|
||||
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index"
|
||||
@tap.stop="couponAction(item, index)">
|
||||
@click="couponAction(item, index)">
|
||||
<image :src="$util.img('public/uniapp/coupon/style7_bg.png')"></image>
|
||||
<view class="coupon">
|
||||
<view class="coupon-info">
|
||||
@@ -454,7 +454,7 @@ export default {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$refs.login.open(this.$util.INDEX_PAGE_URL);
|
||||
this.$refs.login.open('/pages/index/index');
|
||||
this.couponBtnSwitch = false;
|
||||
}
|
||||
},
|
||||
@@ -488,7 +488,7 @@ export default {
|
||||
}
|
||||
|
||||
// 风格一
|
||||
::v-deep .coupon-style-one {
|
||||
/deep/.coupon-style-one {
|
||||
height: 110rpx;
|
||||
|
||||
.coupon-item-box {
|
||||
@@ -534,7 +534,7 @@ export default {
|
||||
}
|
||||
|
||||
// 风格二
|
||||
::v-deep .coupon-style-two {
|
||||
/deep/.coupon-style-two {
|
||||
height: 96rpx;
|
||||
|
||||
.coupon-item-box {
|
||||
@@ -591,7 +591,7 @@ export default {
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
::v-deep .coupon-style-three {
|
||||
/deep/.coupon-style-three {
|
||||
height: 284rpx;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
@@ -638,7 +638,7 @@ export default {
|
||||
}
|
||||
|
||||
// 风格四
|
||||
::v-deep .coupon-style-four {
|
||||
/deep/.coupon-style-four {
|
||||
height: 108rpx;
|
||||
|
||||
.coupon-item-box {
|
||||
@@ -997,7 +997,7 @@ export default {
|
||||
}
|
||||
|
||||
//风格七
|
||||
::v-deep .coupon-style-seven {
|
||||
/deep/ .coupon-style-seven {
|
||||
.wrap {
|
||||
display: flex;
|
||||
}
|
||||
@@ -1075,7 +1075,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .uni-scroll-view ::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view ::-webkit-scrollbar {
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
display: none;
|
||||
width: 0;
|
||||
@@ -1084,7 +1084,7 @@ export default {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar {
|
||||
/deep/::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view :style="componentStyle" data-component-name="diy-digit">
|
||||
<view :style="componentStyle">
|
||||
<scroll-view :class="['graphic-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle]"
|
||||
:scroll-x="value.showStyle == 'singleSlide'">
|
||||
<view class="uni-scroll-view-content">
|
||||
@@ -38,10 +38,16 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uvCountTo from '@/components/uv-count-to/uv-count-to.vue'
|
||||
import nsLogin from '@/components/ns-login/ns-login.vue'
|
||||
import DiyMinx from './minx.js'
|
||||
// 自定义数字展示
|
||||
export default {
|
||||
name: 'diy-digit',
|
||||
components: {
|
||||
uvCountTo,
|
||||
nsLogin
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
@@ -90,7 +96,7 @@ export default {
|
||||
|
||||
// 页面跳转
|
||||
redirectTo(item) {
|
||||
if (!item.wap_url || this.$util.getCurrRoute() != this.$util.MEMBER_PAGE_URL || this.storeToken) {
|
||||
if (!item.wap_url || this.$util.getCurrRoute() != 'pages/member/index' || this.storeToken) {
|
||||
console.log(item);
|
||||
this.$util.diyRedirectTo(item);
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view data-component-name="diy-fenxiao-goods-list" class="diy-fenxiao" v-if="list.length"
|
||||
:class="['goods-list', value.template, value.style]" :style="goodsListWarpCss">
|
||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -32,14 +32,14 @@
|
||||
background: value.btnStyle.theme == 'diy' ? 'linear-gradient(to right,' + value.btnStyle.bgColorStart + ',' + value.btnStyle.bgColorEnd + ')' : '',
|
||||
color: value.btnStyle.theme == 'diy' ? value.btnStyle.textColor : '',
|
||||
borderRadius: value.btnStyle.aroundRadius * 2 + 'rpx'
|
||||
}" @tap.stop="followGoods(item, index)">
|
||||
}" @click.stop="followGoods(item, index)">
|
||||
关注
|
||||
</view>
|
||||
<view class="sale-btn" v-if="value.btnStyle.control && item.is_collect == 1" :style="{
|
||||
background: value.btnStyle.theme == 'diy' ? 'linear-gradient(to right,' + value.btnStyle.bgColorStart + ',' + value.btnStyle.bgColorEnd + ')' : '',
|
||||
color: value.btnStyle.theme == 'diy' ? value.btnStyle.textColor : '',
|
||||
borderRadius: value.btnStyle.aroundRadius * 2 + 'rpx'
|
||||
}" @tap.stop="delFollowTip(item, index)">
|
||||
}" @click.stop="delFollowTip(item, index)">
|
||||
取消关注
|
||||
</view>
|
||||
</view>
|
||||
@@ -75,7 +75,7 @@ export default {
|
||||
this.currentRoute = '/' + currentPage.route;
|
||||
if (!this.storeToken) {
|
||||
this.$util.redirectTo(
|
||||
this.$util.LOGIN_PAGE_URL,
|
||||
'/pages_tool/login/login',
|
||||
{
|
||||
back: this.currentRoute
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
:class="{ left_top: value.bottomPosition == 1, right_top: value.bottomPosition == 2, left_bottom: value.bottomPosition == 3, right_bottom: value.bottomPosition == 4 }"
|
||||
:style="style">
|
||||
<block v-for="(item, index) in value.list" :key="index">
|
||||
<view class="button-box" @tap.stop="$util.diyRedirectTo(item.link)"
|
||||
<view class="button-box" @click="$util.diyRedirectTo(item.link)"
|
||||
:style="{ width: value.imageSize + 'px', height: value.imageSize + 'px', fontSize: value.imageSize + 'px' }">
|
||||
<image v-if="!item.iconType || item.iconType == 'img'" :src="$util.img(item.imageUrl)" mode="aspectFit"
|
||||
:show-menu-by-longpress="true" />
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view @tap.stop="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
|
||||
<view @click="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<view class="ul-wrap">
|
||||
<view class="li-item" v-for="(item, index) in list" :key="index">
|
||||
<image class="brand-pic" :src="$util.img(item.image_url)" mode="aspectFit"
|
||||
@tap.stop="handlerClick(item)" @error="imgError(index)"
|
||||
@click="handlerClick(item)" @tap="handlerClick(item)" @error="imgError(index)"
|
||||
:style="itemCss" />
|
||||
</view>
|
||||
</view>
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
<script>
|
||||
// 商品品牌
|
||||
import uniGrid from '@/components/uni-grid/uni-grid.vue';
|
||||
import uniGridItem from '@/components/uni-grid-item/uni-grid-item.vue';
|
||||
|
||||
import DiyMinx from './minx.js'
|
||||
// 自定义商品品牌展示
|
||||
@@ -29,6 +31,10 @@ export default {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
components: {
|
||||
uniGrid,
|
||||
uniGridItem
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<x-skeleton data-component-name="diy-goods-list" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
||||
<view :class="['goods-list', goodsValue.template, goodsValue.style]" :style="goodsListWarpCss">
|
||||
<template v-if="goodsValue.template != 'horizontal-slide'">
|
||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
|
||||
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
|
||||
@tap="handlerClick(item)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-img-wrap">
|
||||
<image class="goods-img"
|
||||
:src="$util.img(item.goods_image, { size: goodsValue.template == 'large-mode' ? 'big' : 'mid' })"
|
||||
@@ -70,7 +70,7 @@
|
||||
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : '',
|
||||
borderColor: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : ''
|
||||
}" class="cart shopping-cart-btn iconfont icon-gouwuche click-wrap" :id="'goods-' + item.id"
|
||||
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : '',
|
||||
borderColor: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : ''
|
||||
}" class="cart plus-sign-btn iconfont icon-add1 click-wrap" :id="'goods-' + item.id"
|
||||
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
</view>
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
fontWeight: goodsValue.btnStyle.theme == 'diy' ? (goodsValue.btnStyle.fontWeight ? 'bold' : 'normal') : '',
|
||||
padding: goodsValue.btnStyle.theme == 'diy' ? '0 ' + goodsValue.btnStyle.padding * 2 + 'rpx' : ''
|
||||
}" class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
||||
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||
{{ goodsValue.btnStyle.text }}
|
||||
<view class="click-event"></view>
|
||||
<!-- <text class="cart-num" v-if="cartList['goods_' + item.goods_id]">{{ cartList['goods_' + item.goods_id].num }}</text> -->
|
||||
@@ -100,7 +100,7 @@
|
||||
<view v-else-if="goodsValue.btnStyle.style == 'icon-diy'" :style="{
|
||||
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : ''
|
||||
}" class="icon-diy click-wrap" :id="'goods-' + item.id"
|
||||
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||
<view class="click-event"></view>
|
||||
<diy-icon :icon="goodsValue.btnStyle.iconDiy.icon"
|
||||
:value="goodsValue.btnStyle.iconDiy.style ? goodsValue.btnStyle.iconDiy.style : null"></diy-icon>
|
||||
@@ -112,8 +112,8 @@
|
||||
</template>
|
||||
<scroll-view v-if="goodsValue.template == 'horizontal-slide' && goodsValue.slideMode == 'scroll'"
|
||||
class="scroll" :scroll-x="true">
|
||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
|
||||
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
|
||||
@tap="handlerClick(item)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-img-wrap">
|
||||
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)"
|
||||
@@ -179,7 +179,7 @@
|
||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||
<view class="goods-item" v-for="(dataItem, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||
@tap.stop="handlerClick(dataItem)"
|
||||
@click="handlerClick(dataItem)" @tap="handlerClick(dataItem)"
|
||||
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-img-wrap">
|
||||
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -253,12 +253,15 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nsGoodsSkuIndex from '@/components/ns-goods-sku/ns-goods-sku-index.vue';
|
||||
import DiyMinx from './minx.js'
|
||||
import util from '@/common/js/util.js'
|
||||
|
||||
// 自定义商品列表展示
|
||||
export default {
|
||||
name: 'diy-goods-list',
|
||||
components: {
|
||||
nsGoodsSkuIndex
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
@@ -328,7 +331,7 @@ export default {
|
||||
if (this.goodsValue.ornament.type == 'stroke') {
|
||||
obj += 'border:' + '2rpx solid ' + this.goodsValue.ornament.color + ';';
|
||||
}
|
||||
let screenWidth = util.getWindowInfo().windowWidth;
|
||||
const screenWidth = uni.getSystemInfoSync().windowWidth;
|
||||
if (this.value.template == 'horizontal-slide') {
|
||||
var width = '';
|
||||
if (this.value.slideMode == 'scroll' && this.value.goodsMarginType == 'diy') width = this.rpxUpPx(
|
||||
@@ -408,7 +411,7 @@ export default {
|
||||
}
|
||||
},
|
||||
rpxUpPx(res) {
|
||||
const screenWidth = util.getWindowInfo().windowWidth;
|
||||
const screenWidth = uni.getSystemInfoSync().windowWidth;
|
||||
var data = (screenWidth * parseInt(res)) / 750;
|
||||
return Math.floor(data);
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<swiper-item v-for="(item, index) in page" :key="index"
|
||||
:class="['swiper-item', [list[index].length / 3] >= 1 && 'flex-between']">
|
||||
<view class="goods-item" v-for="(dataItem, dataIndex) in list[index]" :key="dataIndex"
|
||||
@tap.stop="toDetail(dataItem)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
@click="toDetail(dataItem)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
<div class="goods-img-wrap">
|
||||
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
|
||||
:key="index"
|
||||
v-if="index >= [(numItem) * (value.pageCount * value.rowCount)] && index < [(numItem + 1) * (value.pageCount * value.rowCount)]"
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
|
||||
:key="index"
|
||||
v-if="index >= [(numItem - 1) * (value.pageCount * value.rowCount)] && index < [numItem * (value.pageCount * value.rowCount)]"
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
||||
<!-- #endif -->
|
||||
<view class="graphic-img" v-if="value.mode != 'text'"
|
||||
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
|
||||
@@ -62,7 +62,7 @@
|
||||
<!-- #endif -->
|
||||
|
||||
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list" :key="index"
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
||||
<view class="graphic-img" v-if="value.mode != 'text'"
|
||||
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
|
||||
<image v-if="item.iconType == 'img'"
|
||||
@@ -159,7 +159,7 @@ export default {
|
||||
redirectTo(link) {
|
||||
|
||||
if (link.wap_url) {
|
||||
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
|
||||
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
|
||||
this.$refs.login.open(link.wap_url);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -251,16 +251,6 @@
|
||||
<diy-icon :value="item"></diy-icon>
|
||||
</template>
|
||||
|
||||
<template v-if="item.componentName == 'Tab'">
|
||||
<!-- Tab 组件 -->
|
||||
<diy-tab :value="item" :diyGlobal="diyGlobalData"></diy-tab>
|
||||
</template>
|
||||
|
||||
<template v-if="['ChannelList', 'WechatChannel'].includes(item.componentName)">
|
||||
<!-- 视频号列表 -->
|
||||
<diy-channel-list :value="item"></diy-channel-list>
|
||||
</template>
|
||||
|
||||
<!-- 自定义扩展组件 -->
|
||||
<diy-comp-extend :value="item"></diy-comp-extend>
|
||||
</view>
|
||||
@@ -270,9 +260,8 @@
|
||||
<script>
|
||||
// 组件组展示
|
||||
import DiyMinx from './minx.js'
|
||||
|
||||
export default {
|
||||
name: 'diy-group',
|
||||
components: {},
|
||||
props: {
|
||||
diyData: {
|
||||
type: Object
|
||||
@@ -352,12 +341,6 @@ export default {
|
||||
}
|
||||
});
|
||||
} else data = this.setPagestyle;
|
||||
|
||||
console.log(`diy-group ['diyDataArray'] = `, {
|
||||
data: data,
|
||||
diyData: this.diyData,
|
||||
diyGlobalData: this.diyGlobalData,
|
||||
})
|
||||
return data;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<x-skeleton data-component-name="diy-groupbuy" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
||||
<view class="diy-groupbuy" :class="[value.template, value.style]" :style="warpCss">
|
||||
<template v-if="value.template == 'row1-of1'">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -39,7 +39,7 @@
|
||||
</template>
|
||||
<template v-if="value.template == 'horizontal-slide'">
|
||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -81,7 +81,7 @@
|
||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
@@ -274,7 +274,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
::v-deep .uni-scroll-view ::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view ::-webkit-scrollbar {
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
display: none;
|
||||
width: 0;
|
||||
@@ -283,7 +283,7 @@ export default {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar {
|
||||
/deep/::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
height: mapItem.height + '%',
|
||||
left: mapItem.left + '%',
|
||||
top: mapItem.top + '%'
|
||||
}" @tap.stop="$util.diyRedirectTo(mapItem.link)"></view>
|
||||
}" @click.stop="$util.diyRedirectTo(mapItem.link)"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
'width': (item.imgWidth / 2 + 'rpx') + ';',
|
||||
'height': (item.imgHeight / 2 + 'rpx') + ';'
|
||||
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
|
||||
:show-menu-by-longpress="true" @tap.stop="redirectTo(item.link)"></image>
|
||||
:show-menu-by-longpress="true" @tap="redirectTo(item.link)"></image>
|
||||
<image v-else :style="{
|
||||
'width': (item.imgWidth / 2 + 'rpx') + ';',
|
||||
'height': (item.imgHeight / 2 + 'rpx') + ';'
|
||||
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
|
||||
:show-menu-by-longpress="true" @tap.stop="previewImg(item.imageUrl)"></image>
|
||||
:show-menu-by-longpress="true" @tap="previewImg(item.imageUrl)"></image>
|
||||
</view>
|
||||
|
||||
<!-- 文字部分 -->
|
||||
@@ -38,11 +38,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import nsLogin from '@/components/ns-login/ns-login.vue'
|
||||
import DiyMinx from './minx.js'
|
||||
|
||||
export default {
|
||||
name: 'diy-image-nav',
|
||||
components: {
|
||||
nsLogin
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
@@ -103,9 +106,20 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 预览图片
|
||||
previewImg(imageUrl) {
|
||||
uni.previewImage({
|
||||
current: 0,
|
||||
urls: [this.$util.img(imageUrl)],
|
||||
success: (res) => { },
|
||||
fail: (res) => { },
|
||||
complete: (res) => { }
|
||||
});
|
||||
},
|
||||
|
||||
// 页面跳转
|
||||
redirectTo(link) {
|
||||
if (!link.wap_url || this.$util.getCurrRoute() != this.$util.MEMBER_PAGE_URL || this.storeToken) {
|
||||
if (!link.wap_url || this.$util.getCurrRoute() != 'pages/member/index' || this.storeToken) {
|
||||
this.$util.diyRedirectTo(link);
|
||||
} else {
|
||||
this.$refs.login.open(link.wap_url);
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<view data-component-name="diy-img-ads" class="single-graph">
|
||||
<view :style="imgAdsMarginWarp" class="swiper-box">
|
||||
<block v-if="imgAdsValue.list.length == 1">
|
||||
<view class="simple-graph-wrap" :style="imgAdsSwiper" @tap.stop="handlerClick(imgAdsValue.list[0].link)">
|
||||
<view class="simple-graph-wrap" :style="imgAdsSwiper" @click="handlerClick(imgAdsValue.list[0].link)"
|
||||
@tap="handlerClick(imgAdsValue.list[0].link)">
|
||||
<image :style="{ height: imgAdsValue.list[0].imgHeight }"
|
||||
:src="$util.img(imgAdsValue.list[0].imageUrl)" mode="widthFix" :show-menu-by-longpress="true" />
|
||||
</view>
|
||||
@@ -15,7 +16,7 @@
|
||||
indicator-color="rgba(130, 130, 130, .5)" :indicator-active-color="imgAdsValue.indicatorColor"
|
||||
@change="swiperChange">
|
||||
<swiper-item class="swiper-item" :style="imgAdsSwiper" v-for="(item, index) in imgAdsValue.list"
|
||||
:key="index" v-if="item.imageUrl" @tap.stop="handlerClick(item.link)">
|
||||
:key="index" v-if="item.imageUrl" @click="handlerClick(item.link)" @tap="handlerClick(item.link)">
|
||||
<view class="item" :style="imgAdsSwiper + 'height: ' + item.imgHeight">
|
||||
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
||||
:show-menu-by-longpress="true" />
|
||||
@@ -279,39 +280,39 @@ export default {
|
||||
}
|
||||
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
::v-deep .uni-scroll-view::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.swiper ::v-deep .uni-swiper-dots-horizontal {
|
||||
.swiper /deep/ .uni-swiper-dots-horizontal {
|
||||
bottom: 25rpx;
|
||||
}
|
||||
|
||||
.swiper-left ::v-deep .uni-swiper-dots-horizontal {
|
||||
.swiper-left /deep/ .uni-swiper-dots-horizontal {
|
||||
left: 40rpx;
|
||||
transform: translate(0);
|
||||
}
|
||||
|
||||
.swiper-right ::v-deep .uni-swiper-dots-horizontal {
|
||||
.swiper-right /deep/ .uni-swiper-dots-horizontal {
|
||||
right: 40rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
transform: translate(0);
|
||||
}
|
||||
|
||||
.carousel-angle ::v-deep .uni-swiper-dots-horizontal .uni-swiper-dot {
|
||||
.carousel-angle /deep/ .uni-swiper-dots-horizontal .uni-swiper-dot {
|
||||
width: 24rpx;
|
||||
border-radius: 0;
|
||||
height: 8rpx;
|
||||
}
|
||||
|
||||
.swiper.ns-indicator-dots ::v-deep .uni-swiper-dot {
|
||||
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot {
|
||||
width: 18rpx;
|
||||
height: 6rpx;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
|
||||
.swiper.ns-indicator-dots ::v-deep .uni-swiper-dot-active {
|
||||
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot-active {
|
||||
width: 36rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -8,7 +8,7 @@
|
||||
:style="{ background: value.backgroundColor ? value.backgroundColor : '', width: 'calc(100% - 48rpx)' }"
|
||||
@touchmove.stop>
|
||||
<view class="item" :id="'a' + index" v-for="(item, index) in cateList" :key="index"
|
||||
@tap.stop="changePageIndex(index)" :class="{ fill: value.styleType == 'fill' }"
|
||||
@click="changePageIndex(index)" :class="{ fill: value.styleType == 'fill' }"
|
||||
:style="{ background: index == pageIndex && value.styleType == 'fill' ? value.selectColor : '' }">
|
||||
<view class="text-con" :class="index == pageIndex ? 'active' : ''" :style="{
|
||||
color: index == pageIndex ? '' : value.noColor
|
||||
@@ -25,13 +25,13 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
<text class="iconfont icon-unfold unfold-arrows" :style="{ color: value.moreColor }"
|
||||
@tap.stop="unfoldMenu"></text>
|
||||
@click="unfoldMenu"></text>
|
||||
</view>
|
||||
<uni-popup ref="navTopCategoryPop" type="top" :top="uniPopTop">
|
||||
<view class="nav-topcategory-pop">
|
||||
<text v-for="(item, index) in cateList" :key="index"
|
||||
:class="['category-item', { 'color-base-text color-base-border active': pageIndex == index }]"
|
||||
@tap.stop="changePageIndex(index)">
|
||||
@click="changePageIndex(index)">
|
||||
{{ item.short_name ? item.short_name : item.category_name }}
|
||||
</text>
|
||||
</view>
|
||||
@@ -55,7 +55,7 @@
|
||||
<view class="twoCategory min" v-if="twoCategorylist.length <= 5">
|
||||
<view class="twoCategory-page">
|
||||
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
||||
:key="index" @tap.stop="toCateGoodsList(item.category_id_2, 2)">
|
||||
:key="index" @click="toCateGoodsList(item.category_id_2, 2)">
|
||||
<view class="item-box">
|
||||
<image :src="$util.img(item.image)" v-if="item.image"
|
||||
mode="aspectFill" />
|
||||
@@ -70,7 +70,7 @@
|
||||
v-if="twoCategorylist.length > 5 && twoCategorylist.length <= 10">
|
||||
<view class="twoCategory-page">
|
||||
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
||||
:key="index" @tap.stop="toCateGoodsList(item.category_id_2, 2)">
|
||||
:key="index" @click="toCateGoodsList(item.category_id_2, 2)">
|
||||
<view class="item-box">
|
||||
<image :src="$util.img(item.image)" v-if="item.image"
|
||||
mode="aspectFill" />
|
||||
@@ -86,7 +86,7 @@
|
||||
<swiper-item class="twoCategory-page" v-for="page in maxPage" :key="page">
|
||||
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
||||
:key="index" v-if="index >= (page - 1) * 10 && index < page * 10"
|
||||
@tap.stop="toCateGoodsList(item.category_id_2, 2)">
|
||||
@click="toCateGoodsList(item.category_id_2, 2)">
|
||||
<view class="item-box">
|
||||
<image :src="item.image" mode="aspectFill" />
|
||||
<view>{{ item.category_name }}</view>
|
||||
@@ -108,7 +108,7 @@
|
||||
|
||||
<view class="goods-list double-column" v-if="goodsList[pageIndex].list.length">
|
||||
<view class="goods-item" v-for="(item, index) in goodsList[pageIndex].list"
|
||||
:key="index" @tap.stop="toDetail(item)">
|
||||
:key="index" @click="toDetail(item)">
|
||||
<view class="goods-img">
|
||||
<image :src="goodsImg(item.goods_image)" mode="widthFix"
|
||||
@error="imgError(index)" />
|
||||
@@ -169,6 +169,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue';
|
||||
import DiyMinx from './minx.js'
|
||||
export default {
|
||||
name: 'diy-index-page',
|
||||
@@ -188,6 +189,9 @@ export default {
|
||||
}
|
||||
},
|
||||
mixins: [DiyMinx],
|
||||
components: {
|
||||
nsLoading
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageIndex: 0, //当前选中分类id
|
||||
@@ -732,7 +736,7 @@ export default {
|
||||
margin-top: 100rpx;
|
||||
}
|
||||
|
||||
::v-deep .uni-scroll-view::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view::-webkit-scrollbar {
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view data-component-name="diy-kefu" class="diy-kefu" :style="style">
|
||||
<view class="fui-list-group merchgroup" v-for="(item, index) in value.list" :key="index">
|
||||
<view class="fui-list-group merchgroup" v-for="(item, index) in value.list">
|
||||
<view class="fui-list jump" v-if="index == 0">
|
||||
<view class="fui-list-media">
|
||||
<image class="round" :src="$util.img(item.imageUrl)" style="border-radius:6rpx"></image>
|
||||
@@ -14,7 +14,7 @@
|
||||
</view>
|
||||
<view class="fui-remark jump" style="padding-right: 20rpx; text-align: center; line-height: 140rpx;">
|
||||
<span style="font-size:24rpx;padding: 14rpx 18rpx;border-radius:8rpx"
|
||||
:style="{ background: item.BtBgColor, color: item.BtColor }" @tap.stop="previewSqs()">立即添加</span>
|
||||
:style="{ background: item.BtBgColor, color: item.BtColor }" @click="previewSqs()">立即添加</span>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<view data-component-name="diy-listmenu" class="diy-listmenu" :style="style">
|
||||
<view data-component-name="diy-picture" class="diy-picture" :style="style">
|
||||
<view class="fui-cell-group">
|
||||
<!-- <image mode="widthFix" style="width: 100%;" :src="$util.img(item.imageUrl)"></image> -->
|
||||
|
||||
<view v-for="(item, index) in value.list" @tap.stop="redirectTo(item.link)" class="fui-cell"
|
||||
<view v-for="(item, index) in value.list" @click="redirectTo(item.link)" class="fui-cell"
|
||||
:class="item.iconType == 'img' ? 'img-cell' : ''">
|
||||
<view class="fui-cell-icon" :style="{ 'color': item.style ? item.style.iconColor : '#333' }">
|
||||
<diy-icon v-if="item.iconType == 'icon'" :icon="item.icon" :value="item.style ? item.style : null"
|
||||
@@ -62,8 +62,8 @@ export default {
|
||||
methods: {
|
||||
redirectTo(link) {
|
||||
if (link.wap_url) {
|
||||
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
|
||||
this.$refs?.login?.open(link.wap_url);
|
||||
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
|
||||
this.$refs.login.open(link.wap_url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<x-skeleton data-component-name="diy-live" type="banner" :loading="loading" :configs="skeletonConfig">
|
||||
<view class="live-wrap" @tap.stop="handlerClick(liveInfo.roomid)"
|
||||
<view class="live-wrap" @click="handlerClick(liveInfo.roomid)" @tap="handlerClick(liveInfo.roomid)"
|
||||
v-if="liveInfo">
|
||||
<view class="banner-wrap">
|
||||
<image
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<scroll-view scroll-x="true" class="many-goods-list-head" :scroll-into-view="'a' + cateIndex"
|
||||
:style="manyWrapCss">
|
||||
<view v-for="(item, index) in value.list" class="scroll-item" :class="{ active: index == cateIndex }"
|
||||
:id="'a' + index" :key="index" @tap.stop="handlerClick({ item, index })">
|
||||
:id="'a' + index" :key="index" @click="handlerClick({ item, index })" @tap="handlerClick({ item, index })">
|
||||
<view class="split-line" v-if="index > 0"></view>
|
||||
<view class="cate">
|
||||
<view class="name" :style="{ color: value.headStyle.titleColor }">{{ item.title }}</view>
|
||||
|
||||
@@ -3,18 +3,11 @@
|
||||
<view class="fui-list-group merchgroup" style="margin-top:0" v-for="(item, index) in value.list">
|
||||
<map id="map" style="width: 100%; height:600rpx" scale="12" :markers="markerst" bindupdated="bindupdated"
|
||||
:longitude="item.lng" :latitude="item.lat" show-location>
|
||||
<!-- <cover-view
|
||||
<cover-view
|
||||
style="position:absolute;right:10px;bottom:30rpx;z-index:99999;background:#4390FF;padding:5px 10px;wxcs_style_padding:10rpx 20rpx;border-radius:8rpx;color: #fff;"
|
||||
@tap.stop="handlerClick(item)" @tap="handlerClick(item)">
|
||||
@click="handlerClick(item)" @tap="handlerClick(item)">
|
||||
<cover-view style="font-size:24rpx">一键导航</cover-view>
|
||||
</cover-view> -->
|
||||
|
||||
<!-- 使用非原生cover-view, 解决原生cover-view组件渲染机制z-index失效的问题 -->
|
||||
<div
|
||||
style="position:absolute;right:12rpx;bottom:48rpx;z-index:1;background:#4390FF;padding:0rpx 20rpx;border-radius:8rpx;color: #fff;"
|
||||
@tap.stop="handlerClick(item)">
|
||||
<span style="font-size:24rpx;color: #fff;">一键导航</span>
|
||||
</div>
|
||||
</cover-view>
|
||||
</map>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<view class="common-wrap info-wrap" :class="[`data-style-${value.style}`]">
|
||||
<view class="member-info" :style="memberInfoStyle">
|
||||
<view class="info-wrap" :style="infoStyle" v-if="memberInfo">
|
||||
<view class="headimg" @tap.stop="getWxAuth">
|
||||
<view class="headimg" @click="getWxAuth">
|
||||
<image :src="memberInfo.headimg ? $util.img(memberInfo.headimg) : $util.getDefaultImage().head"
|
||||
mode="widthFix" @error="memberInfo.headimg = $util.getDefaultImage().head" />
|
||||
</view>
|
||||
@@ -12,10 +12,10 @@
|
||||
<!-- #ifdef MP -->
|
||||
<block
|
||||
v-if="(memberInfo.nickname.indexOf('u_') != -1 && memberInfo.nickname == memberInfo.username) || memberInfo.nickname == memberInfo.mobile">
|
||||
<view class="nickname"><text class="name" @tap.stop="getWxAuth">点击授权头像昵称</text></view>
|
||||
<view class="nickname"><text class="name" @click="getWxAuth">点击授权头像昵称</text></view>
|
||||
</block>
|
||||
<view class="nickname" v-else>
|
||||
<text class="name" @tap.stop="getWxAuth">{{ memberInfo.nickname }}</text>
|
||||
<text class="name" @click="getWxAuth">{{ memberInfo.nickname }}</text>
|
||||
<view class="member-level"
|
||||
v-if="(value.style == 1 || value.style == 2) && memberInfo.member_level">
|
||||
<!-- <text class="icondiy icon-system-huangguan"></text> -->
|
||||
@@ -36,10 +36,10 @@
|
||||
<!-- #ifdef H5 -->
|
||||
<block
|
||||
v-if="$util.isWeiXin() && ((memberInfo.nickname.indexOf('u_') != -1 && memberInfo.nickname == memberInfo.username) || memberInfo.nickname == memberInfo.mobile)">
|
||||
<view class="nickname"><text class="name" @tap.stop="getWxAuth">点击获取微信头像</text></view>
|
||||
<view class="nickname"><text class="name" @click="getWxAuth">点击获取微信头像</text></view>
|
||||
</block>
|
||||
<view class="nickname" v-else>
|
||||
<text class="name" @tap.stop="redirect('/pages_tool/member/info')">{{ memberInfo.nickname
|
||||
<text class="name" @click="redirect('/pages_tool/member/info')">{{ memberInfo.nickname
|
||||
}}</text>
|
||||
<view class="member-level"
|
||||
v-if="(value.style == 1 || value.style == 2) && memberInfo.member_level">
|
||||
@@ -61,10 +61,10 @@
|
||||
</view>
|
||||
<view v-if="ischina == 1"
|
||||
style="background: #fff;height: 60rpx;width: 60rpx;border-radius: 50rpx;line-height:65rpx;text-align: center;color:#000"
|
||||
@tap.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
|
||||
@click.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
|
||||
</view>
|
||||
|
||||
<view class="info-wrap" v-else :style="infoStyle" @tap.stop="redirect($util.MEMBER_PAGE_URL)">
|
||||
<view class="info-wrap" v-else :style="infoStyle" @click="redirect('/pages/member/index')">
|
||||
<view class="headimg">
|
||||
<image :src="$util.getDefaultImage().head" mode="widthFix"></image>
|
||||
</view>
|
||||
@@ -75,12 +75,12 @@
|
||||
|
||||
<view v-if="ischina == 1"
|
||||
style="background: #fff;height: 60rpx;width: 60rpx;border-radius: 50rpx;line-height:65rpx;text-align: center;color:#000"
|
||||
@tap.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
|
||||
@click.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
|
||||
</view>
|
||||
|
||||
<view class="account-info" v-show="value.style == 1"
|
||||
:style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/balance')">
|
||||
<view class="value price-font">
|
||||
{{ memberInfo ? (parseFloat(memberInfo.balance) +
|
||||
parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}
|
||||
@@ -88,12 +88,12 @@
|
||||
<view class="title">{{ $lang('balance') }}</view>
|
||||
</view>
|
||||
<view class="solid"></view>
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
|
||||
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}</view>
|
||||
<view class="title">{{ $lang('point') }}</view>
|
||||
</view>
|
||||
<view class="solid"></view>
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
|
||||
<view class="value price-font">
|
||||
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
||||
</view>
|
||||
@@ -110,8 +110,8 @@
|
||||
<text>超级会员</text>
|
||||
</view>
|
||||
<view class="super-text">
|
||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
|
||||
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">会员可享更多权益</text>
|
||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
|
||||
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">会员可享更多权益</text>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
</block>
|
||||
@@ -121,8 +121,8 @@
|
||||
<view class="desc">开通可享更多权益</view>
|
||||
</view>
|
||||
<view class="super-text">
|
||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
|
||||
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
|
||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
|
||||
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
@@ -134,25 +134,25 @@
|
||||
<view class="desc">开通可享更多权益</view>
|
||||
</view>
|
||||
<view class="super-text" :class="{ 'more' : memberInfo && memberInfo.member_level_type }">
|
||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看更多权益</text>
|
||||
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
|
||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看更多权益</text>
|
||||
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="account-info" :style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance_detail')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/balance_detail')">
|
||||
<view class="value price-font">
|
||||
{{ memberInfo ? (parseFloat(memberInfo.balance) + parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}
|
||||
</view>
|
||||
<view class="title">余额</view>
|
||||
</view>
|
||||
<view class="solid"></view>
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
|
||||
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}
|
||||
</view>
|
||||
<view class="title">积分</view>
|
||||
</view>
|
||||
<view class="solid"></view>
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
|
||||
<view class="value price-font">
|
||||
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
||||
</view>
|
||||
@@ -161,7 +161,7 @@
|
||||
</view>
|
||||
<view class="style4-other">
|
||||
<view class="style4-btn-wrap">
|
||||
<view @tap.stop="redirect('/pages_tool/recharge/list')" class="recharge-btn">余额充值</view>
|
||||
<view @click="redirect('/pages_tool/recharge/list')" class="recharge-btn">余额充值</view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
@@ -169,18 +169,18 @@
|
||||
|
||||
<view class="account-info" v-show="value.style == 2"
|
||||
:style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/balance')">
|
||||
<view class="value price-font">{{ memberInfo ? (parseFloat(memberInfo.balance) +
|
||||
parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}</view>
|
||||
<view class="title">{{ $lang('balance') }}</view>
|
||||
</view>
|
||||
<view class="solid"></view>
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
|
||||
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}</view>
|
||||
<view class="title">{{ $lang('point') }}</view>
|
||||
</view>
|
||||
<view class="solid"></view>
|
||||
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
|
||||
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
|
||||
<view class="value price-font">
|
||||
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
||||
</view>
|
||||
@@ -196,7 +196,7 @@
|
||||
<view class="head">
|
||||
<text class="title">获取您的昵称、头像</text>
|
||||
<text class="color-tip tips">获取用户头像、昵称完善个人资料,主要用于向用户提供具有辨识度的用户中心界面</text>
|
||||
<text class="iconfont icon-close color-tip" @tap.stop="cancelCompleteInfo"></text>
|
||||
<text class="iconfont icon-close color-tip" @click="cancelCompleteInfo"></text>
|
||||
</view>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view class="item-wrap">
|
||||
@@ -227,7 +227,7 @@
|
||||
<input type="nickname" placeholder="请输入昵称" v-model="nickName" @blur="blurNickName" />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<button type="default" class="save-btn" @tap.stop="saveCompleteInfo" :disabled="isDisabled">保存</button>
|
||||
<button type="default" class="save-btn" @click="saveCompleteInfo" :disabled="isDisabled">保存</button>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
@@ -243,7 +243,7 @@ let menuButtonInfo = {};
|
||||
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
|
||||
// #endif
|
||||
// 自定义会员中心——会员信息展示
|
||||
|
||||
import nsContact from '@/components/ns-contact/ns-contact.vue';
|
||||
import DiyMinx from './minx.js'
|
||||
export default {
|
||||
name: 'diy-member-info',
|
||||
@@ -259,6 +259,9 @@ export default {
|
||||
}
|
||||
},
|
||||
mixins: [DiyMinx],
|
||||
components: {
|
||||
nsContact
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
info: null,
|
||||
@@ -545,7 +548,7 @@ export default {
|
||||
*/
|
||||
redirectBeforeAuth(url) {
|
||||
if (!this.storeToken) {
|
||||
this.$refs.login.open(this.$util.MEMBER_PAGE_URL);
|
||||
this.$refs.login.open('/pages/member/index');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -583,7 +586,7 @@ export default {
|
||||
url: '/wechat/api/wechat/authcode',
|
||||
data: {
|
||||
scopes: 'snsapi_userinfo',
|
||||
redirect_url: this.$config.h5Domain + this.$util.MEMBER_PAGE_URL
|
||||
redirect_url: this.$config.h5Domain + '/pages/member/index'
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
@@ -1380,11 +1383,11 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
::v-deep .member-info-style4 .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
/deep/ .member-info-style4 .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
@@ -1484,8 +1487,8 @@ export default {
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
.member-complete-info-popup ::v-deep .uni-popup__wrapper.bottom,
|
||||
.member-complete-info-popup ::v-deep .uni-popup__wrapper.bottom .uni-popup__wrapper-box {
|
||||
.member-complete-info-popup /deep/ .uni-popup__wrapper.bottom,
|
||||
.member-complete-info-popup /deep/ .uni-popup__wrapper.bottom .uni-popup__wrapper-box {
|
||||
border-top-left-radius: 30rpx !important;
|
||||
border-top-right-radius: 30rpx !important;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<view data-component-name="diy-member-my-order" class="common-wrap" :style="warpCss">
|
||||
<view class="order-wrap">
|
||||
<view class="status-wrap">
|
||||
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitpay')"
|
||||
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitpay')"
|
||||
style="margin-right: 10rpx;">
|
||||
<view class="icon-block">
|
||||
<template v-if="value.style == 3">
|
||||
@@ -21,7 +21,7 @@
|
||||
</view>
|
||||
<view class="title">{{ $lang('waitpay') }}</view>
|
||||
</view>
|
||||
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitsend')"
|
||||
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitsend')"
|
||||
style="margin-right: 10rpx;">
|
||||
<view class="icon-block">
|
||||
<template v-if="value.style == 3">
|
||||
@@ -40,7 +40,7 @@
|
||||
</view>
|
||||
<view class="title">{{ $lang('waitsend') }}</view>
|
||||
</view>
|
||||
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitconfirm')"
|
||||
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitconfirm')"
|
||||
style="margin-right: 10rpx;">
|
||||
<view class="icon-block">
|
||||
<template v-if="value.style == 3">
|
||||
@@ -59,7 +59,7 @@
|
||||
</view>
|
||||
<view class="title">{{ $lang('waitconfirm') }}</view>
|
||||
</view>
|
||||
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitrate')"
|
||||
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitrate')"
|
||||
style="margin-right: 10rpx;">
|
||||
<view class="icon-block">
|
||||
<template v-if="value.style == 3">
|
||||
@@ -76,7 +76,7 @@
|
||||
</view>
|
||||
<view class="title">{{ $lang('completed') }}</view>
|
||||
</view>
|
||||
<view class="item-wrap" @tap.stop="redirect('/pages_tool/order/activist')">
|
||||
<view class="item-wrap" @click="redirect('/pages_tool/order/activist')">
|
||||
<view class="icon-block">
|
||||
<template v-if="value.style == 3">
|
||||
<image :src="$util.img('public/uniapp/member/order/refunding.png')" mode="widthFix" />
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<view class="merch-wrap" :style="warpCss">
|
||||
<view :class="['list-wrap', value.style]" :style="warpCss">
|
||||
<view :class="['item', value.ornament.type]" v-for="(item, index) in list" :key="index"
|
||||
:style="itemCss" @tap.stop="handlerClick(item)">
|
||||
:style="itemCss" @click="handlerClick(item)" @tap="handlerClick(item)">
|
||||
<view class="merch-img">
|
||||
<image class="cover-img" :src="$util.img(item.merch_image)" mode="widthFix"
|
||||
@error="imgError(index)" />
|
||||
@@ -25,7 +25,7 @@
|
||||
<!-- #endif -->
|
||||
|
||||
<view class="merch-nav-item graphic" v-for="(item, index) in list" :key="index"
|
||||
:style="{ width: 100 / 4 + '%' }" @tap.stop="handlerClick(item)">
|
||||
:style="{ width: 100 / 4 + '%' }" @click="handlerClick(item)" @tap="handlerClick(item)">
|
||||
<view class="graphic-img" v-if="value.mode != 'text'"
|
||||
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
|
||||
<image
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
<view class="diy-notes" :style="{ backgroundColor: value.componentBgColor }">
|
||||
<view class="diy-notes-top">
|
||||
<view class="notes-title" :style="{ color: value.titleTextColor }">{{ value.title }}</view>
|
||||
<view class="notes-more" @tap.stop="toMore()" :style="{ color: value.moreTextColor }">{{ value.more }}
|
||||
<view class="notes-more" @click="toMore()" :style="{ color: value.moreTextColor }">{{ value.more }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="diy-notes-box" scroll-x="true" show-scrollbar="true">
|
||||
<view class="notes-box-item" v-for="(item, i) in dataList" :key="i" @tap.stop="handlerClick(item)" :style="notesItemStyle">
|
||||
<view class="notes-box-item" v-for="(item, i) in dataList" :key="i" @click="handlerClick(item)"
|
||||
@tap="handlerClick(item)" :style="notesItemStyle">
|
||||
<view class="notes-item" v-if="item.status == 1">
|
||||
<view class="notes-item-con">
|
||||
<view class="notes-title">{{ item.note_title }}</view>
|
||||
@@ -156,7 +157,7 @@ export default {
|
||||
/* 点赞 */
|
||||
giveLike(noteId, index) {
|
||||
if (!this.storeToken) {
|
||||
this.$refs.login.open(this.$util.INDEX_PAGE_URL);
|
||||
this.$refs.login.open('/pages/index/index');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
<view @touchmove.prevent.stop>
|
||||
<uni-popup ref="noticePopup" type="center">
|
||||
<view class="notice-popup">
|
||||
<view class="head-wrap" @tap.stop="closeNoticePopup">
|
||||
<view class="head-wrap" @click="closeNoticePopup">
|
||||
<text>公告</text>
|
||||
<text class="iconfont icon-close"></text>
|
||||
</view>
|
||||
<view class="content-wrap">{{ notice }}</view>
|
||||
<button type="primary" @tap.stop="closeNoticePopup">我知道了</button>
|
||||
<button type="primary" @click="closeNoticePopup">我知道了</button>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
<!-- <text class="iconfont icon-shuaxin"></text> -->
|
||||
</view>
|
||||
<view class="qrocde-action">
|
||||
<button type="primary" @tap.stop="toLink">
|
||||
<button type="primary" @click="toLink">
|
||||
<text class="iconfont icon-fukuanma"></text>
|
||||
<text class="action-name">付款码</text>
|
||||
</button>
|
||||
<button type="primary" @tap.stop="openPaymentPopup">
|
||||
<button type="primary" @click="openPaymentPopup">
|
||||
<text class="iconfont icon-saomafu"></text>
|
||||
<text class="action-name">扫码付</text>
|
||||
</button>
|
||||
@@ -26,12 +26,12 @@
|
||||
<view @touchmove.prevent.stop>
|
||||
<uni-popup ref="paymentPopup" type="center">
|
||||
<view class="payment-popup">
|
||||
<view class="head-wrap" @tap.stop="closePaymentPopup">
|
||||
<view class="head-wrap" @click="closePaymentPopup">
|
||||
<text>提示</text>
|
||||
<text class="iconfont icon-close"></text>
|
||||
</view>
|
||||
<view class="content-wrap">扫码付请退出程序后直接使用微信扫一扫或返回上一页使用付款码进行支付</view>
|
||||
<button type="primary" @tap.stop="closePaymentPopup">我知道了</button>
|
||||
<button type="primary" @click="closePaymentPopup">我知道了</button>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
<view class="fui-picture">
|
||||
<view v-for="(item, index) in value.list" style="line-height: 0;">
|
||||
<image mode="widthFix" style="width: 100%;height:auto" :src="$util.img(item.imageUrl)"
|
||||
v-if="item.link.wap_url" @tap.stop="handlerClick(item)"></image>
|
||||
v-if="item.link.wap_url" @click="handlerClick(item)" @tap="handlerClick(item)"></image>
|
||||
<image mode="widthFix" style="width: 100%;height:auto" :src="$util.img(item.imageUrl)" v-else
|
||||
@tap.stop="handlerClick(item)"></image>
|
||||
@click="handlerClick(item)" @tap="handlerClick(item)"></image>
|
||||
</view>
|
||||
<!-- <view wx:if="{{!childitem.linkurl}}" bindtap="previewImg" data-src="{{childitem.imgurl}}" style="padding:{{diyitem.style.paddingtop==0?0:diyitem.style.paddingtop+'rpx'}} {{diyitem.style.paddingleft==0?0:diyitem.style.paddingleft+'rpx'}}" wx:for="{{diyitem.data}}" wx:for-index="childid" wx:for-item="childitem" wx:key="{{childid}}">
|
||||
<image mode="widthFix" src="{{childitem.imgurl}}" style="{{bannerheight?'height:'+bannerheight+'px':'height:auto'}}"></image>
|
||||
@@ -52,9 +52,20 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
previewImg(img) {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.previewImage({
|
||||
current: 0,
|
||||
urls: [this.$util.img(img)],
|
||||
success: function (res) { },
|
||||
fail: function (res) { },
|
||||
complete: function (res) { },
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
redirectTo(link) {
|
||||
if (link.wap_url) {
|
||||
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
|
||||
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
|
||||
this.$refs.login.open(link.wap_url);
|
||||
return;
|
||||
}
|
||||
@@ -66,9 +77,7 @@ export default {
|
||||
await this.__$emitEvent({
|
||||
eventName: 'picture-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
|
||||
if (!awaitedResult) return;
|
||||
|
||||
const link = item.link;
|
||||
if (link?.name || link?.wap_url || link?.appid) {
|
||||
if (item.link.wap_url) {
|
||||
this.redirectTo(item.link);
|
||||
} else {
|
||||
this.previewImg(item.imageUrl);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<x-skeleton data-component-name="diy-pinfan" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
||||
<view class="diy-pinfan" :class="[value.template, value.style]" :style="warpCss">
|
||||
<template v-if="value.template == 'row1-of1'">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
<template v-if="value.template == 'horizontal-slide'">
|
||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -113,7 +113,7 @@
|
||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
@@ -319,7 +319,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
::v-deep .uni-scroll-view ::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view ::-webkit-scrollbar {
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
display: none;
|
||||
width: 0;
|
||||
@@ -328,7 +328,7 @@ export default {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar {
|
||||
/deep/::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
@@ -31,14 +31,14 @@
|
||||
</view>
|
||||
<view class="head-right"
|
||||
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
||||
@tap.stop="$util.redirectTo('/pages_promotion/pintuan/list')">
|
||||
@click="$util.redirectTo('/pages_promotion/pintuan/list')">
|
||||
<text>{{ value.titleStyle.more }}</text>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<template v-if="value.template == 'row1-of1'">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
<template v-if="value.template == 'horizontal-slide'">
|
||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -161,7 +161,7 @@
|
||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
@@ -391,7 +391,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
::v-deep .uni-scroll-view ::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view ::-webkit-scrollbar {
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
display: none;
|
||||
width: 0;
|
||||
@@ -400,7 +400,7 @@ export default {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar {
|
||||
/deep/::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<x-skeleton data-component-name="diy-presale" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
||||
<view class="diy-presale" v-if="list.length" :class="[value.template, value.style]" :style="warpCss">
|
||||
<template v-if="value.template == 'row1-of1'">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
|
||||
@tap="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
@@ -40,8 +40,8 @@
|
||||
</template>
|
||||
<template v-if="value.template == 'horizontal-slide'">
|
||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
|
||||
@tap="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
@@ -75,7 +75,8 @@
|
||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||
@tap.stop="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
@click="handlerClick(item)" @tap="handlerClick(item)" :class="[value.ornament.type]"
|
||||
:style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
@@ -275,7 +276,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
::v-deep .uni-scroll-view ::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view ::-webkit-scrollbar {
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
display: none;
|
||||
width: 0;
|
||||
@@ -284,7 +285,7 @@ export default {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar {
|
||||
/deep/::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<view class="uni-scroll-view-content">
|
||||
<!-- #endif -->
|
||||
<view class="quick-nav-item" v-for="(item, index) in value.list" :key="index"
|
||||
@tap.stop="handlerClick(item)"
|
||||
@click="handlerClick(item)" @tap="handlerClick(item)"
|
||||
:style="{ background: 'linear-gradient(to right,' + item.bgColorStart ? item.bgColorStart : '' + ',' + item.bgColorEnd ? item.bgColorEnd : '' + ')' }">
|
||||
<view class="quick-img" v-if="item.imageUrl || item.icon">
|
||||
<image v-if="item.iconType == 'img'"
|
||||
@@ -61,7 +61,7 @@ export default {
|
||||
methods: {
|
||||
redirectTo(link) {
|
||||
if (link.wap_url) {
|
||||
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
|
||||
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
|
||||
this.$refs.login.open(link.wap_url);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view data-component-name="diy-rich-text" class="rich-text-box" :style="richTextWarpCss">
|
||||
<rich-text :nodes="html" @tap.stop="handlerClick"></rich-text>
|
||||
<rich-text :nodes="html" @click="handlerClick" @tap="handlerClick"></rich-text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
<!-- 1左2右 -->
|
||||
<template v-if="value.mode == 'row1-lt-of2-rt'">
|
||||
<view class="template-left">
|
||||
<view :class="['item', value.mode]" @tap.stop="handlerClick(value.list[0].link, value.list[0].imageUrl)"
|
||||
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }">
|
||||
<view :class="['item', value.mode]" @click="handlerClick(value.list[0].link)"
|
||||
@tap="handlerClick(value.list[0].link)"
|
||||
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }">
|
||||
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
|
||||
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
|
||||
</view>
|
||||
@@ -18,8 +19,9 @@
|
||||
<view class="template-right">
|
||||
<template v-for="(item, index) in list">
|
||||
<template v-if="index > 0">
|
||||
<view :key="index" :class="['item', value.mode]" @tap.stop="handlerClick(item.link, item.imageUrl)"
|
||||
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: item.imgWidth, height: item.imgHeight + 'px' }">
|
||||
<view :key="index" :class="['item', value.mode]" @click="handlerClick(item.link)"
|
||||
@tap="handlerClick(item.link)"
|
||||
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: item.imgWidth, height: item.imgHeight + 'px' }">
|
||||
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
||||
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
||||
</view>
|
||||
@@ -32,8 +34,8 @@
|
||||
<template v-else-if="value.mode == 'row1-lt-of1-tp-of2-bm'">
|
||||
<view class="template-left">
|
||||
<view :class="['item', value.mode]"
|
||||
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }"
|
||||
@tap.stop="handlerClick(value.list[0].link, value.list[0].imageUrl)">
|
||||
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }"
|
||||
@click="handlerClick(value.list[0].link)" @tap="handlerClick(value.list[0].link)">
|
||||
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
|
||||
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
|
||||
</view>
|
||||
@@ -41,19 +43,20 @@
|
||||
|
||||
<view class="template-right">
|
||||
<view :class="['item', value.mode]"
|
||||
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: list[1].imgWidth, height: list[1].imgHeight + 'px' }"
|
||||
@tap.stop="handlerClick(value.list[1].link, value.list[1].imageUrl)">
|
||||
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: list[1].imgWidth, height: list[1].imgHeight + 'px' }"
|
||||
@click="handlerClick(value.list[1].link)" @tap="handlerClick(value.list[1].link)">
|
||||
<image :src="$util.img(value.list[1].imageUrl)" :mode="list[1].imageMode || 'scaleToFill'"
|
||||
:style="list[1].pageItemStyle" :show-menu-by-longpress="true" />
|
||||
</view>
|
||||
<view class="template-bottom">
|
||||
<template v-for="(item, index) in list">
|
||||
<template v-if="index > 1">
|
||||
<view :key="index" :class="['item', value.mode]" @tap.stop="handlerClick(item.link, item.imageUrl)" :style="{
|
||||
marginRight: value.imageGap * 2 + 'rpx',
|
||||
width: item.imgWidth,
|
||||
height: item.imgHeight + 'px'
|
||||
}">
|
||||
<view :key="index" :class="['item', value.mode]" @click="handlerClick(item.link)"
|
||||
@tap="handlerClick(item.link)" :style="{
|
||||
marginRight: value.imageGap * 2 + 'rpx',
|
||||
width: item.imgWidth,
|
||||
height: item.imgHeight + 'px'
|
||||
}">
|
||||
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
||||
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
||||
</view>
|
||||
@@ -65,8 +68,8 @@
|
||||
|
||||
<template v-else>
|
||||
<view :class="['item', value.mode]" v-for="(item, index) in list" :key="index"
|
||||
@tap.stop="handlerClick(item.link, item.imageUrl)"
|
||||
:style="{ marginRight: value.imageGap * 2 + 'rpx', marginBottom: value.imageGap * 2 + 'rpx', width: item.widthStyle, height: item.imgHeight + 'px' }">
|
||||
@click="handlerClick(item.link)" @tap="handlerClick(item.link)"
|
||||
:style="{ marginRight: value.imageGap * 2 + 'rpx', marginBottom: value.imageGap * 2 + 'rpx', width: item.widthStyle, height: item.imgHeight + 'px' }">
|
||||
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
||||
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
||||
</view>
|
||||
@@ -371,16 +374,11 @@ export default {
|
||||
return obj;
|
||||
},
|
||||
|
||||
async handlerClick(link, imageUrl) {
|
||||
async handlerClick(link) {
|
||||
await this.__$emitEvent({
|
||||
eventName: 'rubik-cube-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
|
||||
if (!awaitedResult) return;
|
||||
|
||||
if (link?.name || link?.wap_url || link?.appid) {
|
||||
this.$util.diyRedirectTo(link);
|
||||
} else if (imageUrl){
|
||||
this.previewImg(imageUrl);
|
||||
}
|
||||
this.$util.diyRedirectTo(link);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<view data-component-name="diy-search" class="diy-search">
|
||||
<view class="diy-search-wrap" :class="value.positionWay" :style="fixedCss">
|
||||
<view :class="['search-box', 'search-box-' + value.searchStyle]" :style="searchWrapCss"
|
||||
@tap.stop="handlerSearchClick">
|
||||
@click="handlerSearchClick" @tap="handlerSearchClick">
|
||||
<block v-if="[1, 2].includes(value.searchStyle)">
|
||||
<view class="img" v-if="value.searchStyle == 2 && value.iconType == 'img'">
|
||||
<image :src="$util.img(value.imageUrl)" mode="heightFix" />
|
||||
@@ -14,30 +14,32 @@
|
||||
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title"
|
||||
v-model="searchText" @confirm="handlerSearchClick" disabled="true"
|
||||
:placeholderStyle="placeholderStyle" />
|
||||
<text class="iconfont icon-sousuo3" @tap.stop="handlerSearchClick"
|
||||
<text class="iconfont icon-sousuo3" @click.stop="handlerSearchClick" @tap="handlerSearchClick"
|
||||
:style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-if="value.searchStyle == 3">
|
||||
<view class="search-content" :style="inputStyle"
|
||||
@tap.stop="handlerSearchClick">
|
||||
<view class="search-content" :style="inputStyle" @click.stop="handlerSearchClick"
|
||||
@tap="handlerSearchClick">
|
||||
<text class="iconfont icon-sousuo3"
|
||||
:style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
|
||||
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title"
|
||||
v-model="searchText" @confirm="handlerSearchClick" disabled="true"
|
||||
@tap.stop="handlerSearchClick"
|
||||
@click.stop="handlerSearchClick" @tap="handlerSearchClick"
|
||||
:placeholderStyle="placeholderStyle" />
|
||||
<text class="search-content-btn" @tap.stop="handlerSearchClick"
|
||||
<text class="search-content-btn" @click.stop="handlerSearchClick" @tap="handlerSearchClick"
|
||||
:style="{ 'backgroundColor': value.pageBgColor ? value.pageBgColor : 'rgba(0,0,0,0)' }">搜索</text>
|
||||
</view>
|
||||
<view class="img" v-if="value.iconType == 'img'"
|
||||
@tap.stop="handlerRedirectToClick(value.searchLink)">
|
||||
@click.stop="handlerRedirectToClick(value.searchLink)"
|
||||
@tap="handlerRedirectToClick(value.searchLink)">
|
||||
<image :src="$util.img(value.imageUrl)" mode="heightFix" />
|
||||
</view>
|
||||
<diy-icon class="icon" v-if="value.iconType == 'icon'" :icon="value.icon"
|
||||
:value="value.style ? value.style : 'null'"
|
||||
:style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }"
|
||||
@tap.stop="handlerRedirectToClick(value.searchLink)"></diy-icon>
|
||||
@click.stop="handlerRedirectToClick(value.searchLink)"
|
||||
@tap="handlerRedirectToClick(value.searchLink)"></diy-icon>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
@@ -196,7 +198,7 @@ export default {
|
||||
},
|
||||
redirectTo(link) {
|
||||
if (link.wap_url) {
|
||||
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
|
||||
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
|
||||
this.$refs.login.open(link.wap_url);
|
||||
return;
|
||||
}
|
||||
@@ -255,7 +257,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
::v-deep .uni-input-placeholder {
|
||||
/deep/ .uni-input-placeholder {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</view>
|
||||
<view class="marketimg-box-title-right" v-if="value.titleStyle.moreSupport"
|
||||
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
||||
@tap.stop="toMore">
|
||||
@click="toMore">
|
||||
<text>{{ value.titleStyle.more }}</text>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<view class="content-wrap">
|
||||
<template v-if="value.template == 'row1-of1'">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -105,7 +105,7 @@
|
||||
</template>
|
||||
|
||||
<template v-if="value.template == 'row1-of2'">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -150,7 +150,7 @@
|
||||
<template v-if="value.template == 'horizontal-slide'">
|
||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true"
|
||||
:show-scrollbar="false">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
|
||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
@@ -190,7 +190,7 @@
|
||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||
:class="['swiper-item', dataList[pageIndex] && [dataList[pageIndex].length / 3].length >= 1 && 'flex-between']">
|
||||
<view class="item" v-for="(item, dataIndex) in dataList[pageIndex]" :key="dataIndex"
|
||||
@tap.stop="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
@click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
@@ -536,7 +536,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
::v-deep .uni-scroll-view ::-webkit-scrollbar {
|
||||
/deep/.uni-scroll-view ::-webkit-scrollbar {
|
||||
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
|
||||
display: none;
|
||||
width: 0;
|
||||
@@ -545,7 +545,7 @@ scroll-view ::-webkit-scrollbar {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar {
|
||||
/deep/::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
@@ -140,7 +140,7 @@ export default {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
::v-deep .uni-scroll-view-content {
|
||||
/deep/ .uni-scroll-view-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -148,7 +148,7 @@ export default {
|
||||
&.between {
|
||||
justify-content: space-between;
|
||||
|
||||
::v-deep .uni-scroll-view-content {
|
||||
/deep/.uni-scroll-view-content {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<block v-if="value.style == 1">
|
||||
<view class="store-box store-one">
|
||||
<view class="store-info">
|
||||
<view class="info-box" :style="{ color: value.textColor }" @tap.stop="toStoreList()">
|
||||
<view class="info-box" :style="{ color: value.textColor }" @click="toStoreList()">
|
||||
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
|
||||
<text class="title">{{ globalStoreInfo.store_name }}</text>
|
||||
<text>
|
||||
@@ -15,12 +15,12 @@
|
||||
</view>
|
||||
<view class="address-wrap" :style="{ color: value.textColor }">
|
||||
<text class="iconfont icon-dizhi"></text>
|
||||
<text v-if="globalStoreInfo && globalStoreInfo.store_id" @tap.stop="mapRoute" class="address">{{
|
||||
<text v-if="globalStoreInfo && globalStoreInfo.store_id" @click="mapRoute" class="address">{{
|
||||
globalStoreInfo.show_address }}</text>
|
||||
<text v-else>获取当前位置...</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="store-image" @tap.stop="selectStore()">
|
||||
<view class="store-image" @click="selectStore()">
|
||||
<image :src="$util.img(globalStoreInfo.store_image)"
|
||||
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill"></image>
|
||||
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill"></image>
|
||||
@@ -29,9 +29,9 @@
|
||||
</block>
|
||||
|
||||
<block v-if="value.style == 2">
|
||||
<view class="store-box store-three" @tap.stop="toStoreList()">
|
||||
<view class="store-box store-three" @click="toStoreList()">
|
||||
<view class="store-info">
|
||||
<view class="store-image" @tap.stop="selectStore()">
|
||||
<view class="store-image" @click="selectStore()">
|
||||
<image :src="$util.img(globalStoreInfo.store_image)"
|
||||
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill"></image>
|
||||
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill"></image>
|
||||
@@ -47,13 +47,13 @@
|
||||
<text class="title" v-else>定位中...</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="store-icon" @tap.stop="search()"><text class="iconfont icon-sousuo3"
|
||||
<view class="store-icon" @click.stop="search()"><text class="iconfont icon-sousuo3"
|
||||
:style="{ color: value.textColor }"></text></view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<block v-if="value.style == 3">
|
||||
<view class="store-box store-four" @tap.stop="toStoreList()">
|
||||
<view class="store-box store-four" @click="toStoreList()">
|
||||
<view class="store-left-wrap">
|
||||
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
|
||||
<text class="iconfont icon-weizhi" :style="{ color: value.textColor }"></text>
|
||||
@@ -64,8 +64,8 @@
|
||||
</view>
|
||||
<view class="store-right-search">
|
||||
<input type="text" class="uni-input font-size-tag" disabled placeholder="商品搜索"
|
||||
@tap.stop="search()" />
|
||||
<text class="iconfont icon-sousuo3" @tap.stop="search()"></text>
|
||||
@click.stop="search()" />
|
||||
<text class="iconfont icon-sousuo3" @click.stop="search()"></text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
@@ -1,834 +0,0 @@
|
||||
<template>
|
||||
<!-- DIY 标签页组件 - 支持多种样式和位置的标签页切换 -->
|
||||
<view data-component-name="diy-tab" class="diy-tab" :class="'tab-position-' + mergedValue.tabPosition"
|
||||
:style="[getCustomStyle('container')]">
|
||||
<!-- 标签导航栏 -->
|
||||
<view class="tab-nav" :style="[tabNavStyle, getCustomStyle('nav')]">
|
||||
<!-- 标签项循环渲染 -->
|
||||
<view v-for="(tab, index) in mergedValue.tabs" :key="tab.id || index"
|
||||
:class="['tab-item', mergedValue.tabStyle, { active: activeTab === index }]" @tap="switchTab(index)"
|
||||
:style="[tabItemStyle(index), getCustomStyle('tabItem'), activeTab === index ? getCustomStyle('tabItemActive') : {}]">
|
||||
<!-- 标签文本 -->
|
||||
<text
|
||||
:style="[tabTextStyle(index), getCustomStyle('tabText'), activeTab === index ? getCustomStyle('tabTextActive') : {}]">{{
|
||||
getTabTitle(tab.title) }}</text>
|
||||
<!-- 标签指示器(底部线条) -->
|
||||
<view v-if="mergedValue.showIndicator" class="tab-indicator"
|
||||
:style="[tabIndicatorStyle(index), getCustomStyle('indicator')]"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 标签内容区域 -->
|
||||
<view class="tab-content" :style="[tabContentStyle, getCustomStyle('content')]">
|
||||
<!-- 标签面板循环渲染 -->
|
||||
<view v-for="(tab, index) in mergedValue.tabs" :key="index"
|
||||
:class="['tab-panel', { active: activeTab === index }]"
|
||||
:style="[tabPanelStyle(index), getCustomStyle('panel'), activeTab === index ? getCustomStyle('panelActive') : {}]">
|
||||
<!-- 渲染每个标签下的组件 -->
|
||||
<diy-group v-if="tab.components" :diyData="{ value: tab.components, global: diyGlobal }"
|
||||
:scrollTop="tab.scrollTop || 0" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 导入 DIY 混入
|
||||
import DiyMinx from './minx.js'
|
||||
|
||||
export default {
|
||||
name: 'diy-tab',
|
||||
|
||||
// 组件注册 - 使用懒加载解决循环依赖
|
||||
components: {
|
||||
diyGroup: () => import('./diy-group.vue')
|
||||
},
|
||||
|
||||
// 组件属性定义
|
||||
props: {
|
||||
// 标签页配置对象
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
// 全局配置对象
|
||||
diyGlobal: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
|
||||
// 混入
|
||||
mixins: [DiyMinx],
|
||||
|
||||
// 组件数据
|
||||
data() {
|
||||
return {
|
||||
activeTab: this.value?.activeTabIndex ?? 0, // 设置当前激活的标签索引
|
||||
};
|
||||
},
|
||||
|
||||
// 组件创建钩子
|
||||
created() {
|
||||
console.log(`diy-tab-create`, {
|
||||
value: this.mergedValue,
|
||||
tabs: this.mergedValue.tabs
|
||||
});
|
||||
},
|
||||
|
||||
// 计算属性
|
||||
computed: {
|
||||
// 合并默认值和传入值
|
||||
mergedValue() {
|
||||
// 标签页数据配置
|
||||
const tabsConfig = {
|
||||
/**
|
||||
* 标签页数据配置
|
||||
* @type {Array<{title: string|Object, scrollTop: number, components: Array}>}
|
||||
* @property {string} id 标签唯一标识
|
||||
* @property {string|Object} title - 标签标题
|
||||
* • 字符串: 普通文本或国际化键(如 'tab.home')
|
||||
* • 对象: 多语言映射(如 { 'zh-cn': '首页', 'en-us': 'Home' })
|
||||
* @property {number} scrollTop - 标签滚动位置
|
||||
* @property {Array} components - 标签下的组件列表
|
||||
*/
|
||||
tabs: []
|
||||
};
|
||||
|
||||
// 基础配置
|
||||
const baseConfig = {
|
||||
/**
|
||||
* 是否显示指示器
|
||||
* @type {boolean}
|
||||
* @default true
|
||||
*/
|
||||
showIndicator: true,
|
||||
|
||||
/**
|
||||
* 激活的标签索引
|
||||
* @type {number}
|
||||
* @default 0
|
||||
*/
|
||||
activeTabIndex: 0,
|
||||
|
||||
/**
|
||||
* 标签样式
|
||||
* @type {string}
|
||||
* @default 'default'
|
||||
* @values 'default', 'underline', 'card'
|
||||
*/
|
||||
tabStyle: 'default',
|
||||
|
||||
/**
|
||||
* 标签位置
|
||||
* @type {string}
|
||||
* @default 'top'
|
||||
* @values 'top', 'bottom', 'left', 'right'
|
||||
*/
|
||||
tabPosition: 'top'
|
||||
};
|
||||
|
||||
// 导航栏样式
|
||||
const navConfig = {
|
||||
/**
|
||||
* 标签栏高度
|
||||
* @type {number|string}
|
||||
* @default 24
|
||||
* @unit 像素(当为数字时)
|
||||
* @range 建议值:20-80
|
||||
* @format
|
||||
* • 数字: 像素值(如 24)
|
||||
* • 字符串: CSS长度值(如 '24px', '3rem', '4em')
|
||||
* • CSS变量: 'var(--tab-height)'
|
||||
* • 百分比: '10%' (相对父元素高度)
|
||||
*/
|
||||
tabHeight: 24,
|
||||
|
||||
/**
|
||||
* 标签栏背景色
|
||||
* @type {string}
|
||||
* @default '#ffffff'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
tabBgColor: '#ffffff',
|
||||
|
||||
/**
|
||||
* 标签栏内边距
|
||||
* @type {string}
|
||||
* @default '0'
|
||||
* @format CSS padding值
|
||||
* @examples
|
||||
* • 单个值: '0', '10px', '1rem' (四向相同)
|
||||
* • 两个值: '10px 20px' (上下 左右)
|
||||
* • 三个值: '10px 20px 30px' (上 左右 下)
|
||||
* • 四个值: '10px 20px 30px 40px' (上 右 下 左)
|
||||
* • CSS变量: 'var(--tab-padding)'
|
||||
* • 百分比: '5% 10%' (相对父元素宽度)
|
||||
* @note 卡片样式下会忽略此配置,自动使用基于 tabGap 的内边距
|
||||
*/
|
||||
tabPadding: '0'
|
||||
};
|
||||
|
||||
// 标签项样式
|
||||
const tabItemConfig = {
|
||||
/**
|
||||
* 标签间距
|
||||
* @type {number|string}
|
||||
* @default 10
|
||||
* @unit 像素(当为数字时)
|
||||
* @range 建议值:0-30
|
||||
* @format
|
||||
* • 数字: 像素值(如 10)
|
||||
* • 字符串: CSS长度值(如 '10px', '0.5rem', '1em')
|
||||
* • CSS变量: 'var(--tab-gap)'
|
||||
* • 百分比: '5%' (相对父元素宽度)
|
||||
*/
|
||||
tabGap: 10,
|
||||
|
||||
/**
|
||||
* 字体大小
|
||||
* @type {number|string}
|
||||
* @default 14
|
||||
* @unit 像素(当为数字时)
|
||||
* @range 建议值:10-20
|
||||
* @format
|
||||
* • 数字: 像素值(如 14)
|
||||
* • 字符串: CSS长度值(如 '14px', '0.875rem', '1.4em')
|
||||
* • CSS变量: 'var(--font-size)'
|
||||
*/
|
||||
fontSize: 14,
|
||||
|
||||
/**
|
||||
* 激活状态颜色
|
||||
* @type {string}
|
||||
* @default '#ff4444'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
activeColor: '#ff4444',
|
||||
|
||||
/**
|
||||
* 非激活状态颜色
|
||||
* @type {string}
|
||||
* @default '#666666'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
inactiveColor: '#666666'
|
||||
};
|
||||
|
||||
// 卡片样式
|
||||
const cardConfig = {
|
||||
/**
|
||||
* 卡片默认背景色
|
||||
* @type {string}
|
||||
* @default '#f5f5f5'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
cardBgColor: '#f5f5f5',
|
||||
|
||||
/**
|
||||
* 卡片激活背景色
|
||||
* @type {string}
|
||||
* @default '#ff4444'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
cardActiveBgColor: '#ff4444',
|
||||
|
||||
/**
|
||||
* 卡片默认文字颜色
|
||||
* @type {string}
|
||||
* @default '#666666'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
cardTextColor: '#666666',
|
||||
|
||||
/**
|
||||
* 卡片激活文字颜色
|
||||
* @type {string}
|
||||
* @default '#ffffff'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
cardActiveTextColor: '#ffffff',
|
||||
|
||||
/**
|
||||
* 卡片圆角大小
|
||||
* @type {string}
|
||||
* @default '16px'
|
||||
* @format CSS长度值
|
||||
*/
|
||||
cardBorderRadius: '16px',
|
||||
|
||||
/**
|
||||
* 卡片外边距
|
||||
* @type {string}
|
||||
* @default '0 5px'
|
||||
* @format CSS margin值
|
||||
*/
|
||||
cardMargin: '0 5px',
|
||||
|
||||
/**
|
||||
* 卡片内边距
|
||||
* @type {string}
|
||||
* @default '0 10px'
|
||||
* @format CSS padding值
|
||||
*/
|
||||
cardPadding: '0 10px'
|
||||
};
|
||||
|
||||
// 下划线样式
|
||||
const underlineConfig = {
|
||||
/**
|
||||
* 下划线颜色
|
||||
* @type {string}
|
||||
* @default '#ff4444'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
underlineColor: '#ff4444',
|
||||
|
||||
/**
|
||||
* 下划线高度
|
||||
* @type {number}
|
||||
* @default 2
|
||||
* @unit 像素
|
||||
*/
|
||||
underlineHeight: 2,
|
||||
|
||||
/**
|
||||
* 下划线圆角大小
|
||||
* @type {string}
|
||||
* @default '1px'
|
||||
* @format CSS长度值
|
||||
*/
|
||||
underlineBorderRadius: '1px',
|
||||
|
||||
/**
|
||||
* 下划线左右边距
|
||||
* @type {number}
|
||||
* @default 10
|
||||
* @unit 像素
|
||||
*/
|
||||
underlineMargin: 10
|
||||
};
|
||||
|
||||
// 指示器样式
|
||||
const indicatorConfig = {
|
||||
/**
|
||||
* 指示器颜色
|
||||
* @type {string}
|
||||
* @default '#ff4444'
|
||||
* @format CSS颜色值
|
||||
*/
|
||||
indicatorColor: '#ff4444',
|
||||
|
||||
/**
|
||||
* 指示器高度
|
||||
* @type {number}
|
||||
* @default 2
|
||||
* @unit 像素
|
||||
*/
|
||||
indicatorHeight: 2
|
||||
};
|
||||
|
||||
// 内容区域样式
|
||||
const contentConfig = {
|
||||
/**
|
||||
* 内容区内边距
|
||||
* @type {number|string}
|
||||
* @default 10
|
||||
* @unit 像素(当为数字时)
|
||||
* @range 建议值:0-50
|
||||
* @format
|
||||
* • 数字: 像素值(如 10)
|
||||
* • 字符串: CSS长度值(如 '10px', '1rem', '2em')
|
||||
* • CSS变量: 'var(--content-padding)'
|
||||
* • 百分比: '5%' (相对父元素宽度)
|
||||
*/
|
||||
contentPadding: 10,
|
||||
|
||||
/**
|
||||
* 内容区背景色
|
||||
* @type {string}
|
||||
* @default '#f5f5f5'
|
||||
* @format CSS颜色值
|
||||
* @examples
|
||||
* • 十六进制: '#ffffff', '#f5f5f5'
|
||||
* • RGB: 'rgb(255, 255, 255)'
|
||||
* • RGBA: 'rgba(255, 255, 255, 0.5)'
|
||||
* • HSL: 'hsl(0, 0%, 100%)'
|
||||
* • CSS变量: 'var(--content-bg-color)'
|
||||
* • 预定义颜色: 'white', 'black', 'gray'
|
||||
*/
|
||||
contentBgColor: '#f5f5f5',
|
||||
|
||||
/**
|
||||
* 内容区最小高度
|
||||
* @type {number|string}
|
||||
* @default 200
|
||||
* @unit 像素(当为数字时)
|
||||
* @range 建议值:50-1000
|
||||
* @format
|
||||
* • 数字: 像素值(如 200)
|
||||
* • 字符串: CSS长度值(如 '200px', '20vh', '5rem')
|
||||
* • CSS变量: 'var(--content-min-height)'
|
||||
* • 百分比: '50%' (相对父元素高度)
|
||||
*/
|
||||
contentMinHeight: 200
|
||||
};
|
||||
|
||||
// 自定义样式配置
|
||||
const customStylesConfig = {
|
||||
/**
|
||||
* 自定义样式配置
|
||||
* @type {Object}
|
||||
* @description 允许外部通过完整的 CSS 样式对象完全覆盖各个部分的样式
|
||||
* @property {Object} container - 容器样式
|
||||
* @example { width: '100%', height: '500px', backgroundColor: '#f0f0f0' }
|
||||
* @property {Object} nav - 导航栏样式
|
||||
* @example { backgroundColor: '#ffffff', borderBottom: '1px solid #e0e0e0' }
|
||||
* @property {Object} tabItem - 标签项样式(非激活状态)
|
||||
* @example { padding: '10px 20px', borderRadius: '4px' }
|
||||
* @property {Object} tabItemActive - 标签项激活样式
|
||||
* @example { backgroundColor: '#ff4444', color: '#ffffff' }
|
||||
* @property {Object} tabText - 标签文本样式(非激活状态)
|
||||
* @example { fontSize: '14px', color: '#666666' }
|
||||
* @property {Object} tabTextActive - 标签文本激活样式
|
||||
* @example { fontSize: '16px', color: '#ffffff', fontWeight: 'bold' }
|
||||
* @property {Object} indicator - 指示器样式
|
||||
* @example { backgroundColor: '#ff4444', height: '3px' }
|
||||
* @property {Object} content - 内容区域样式
|
||||
* @example { padding: '20px', backgroundColor: '#f9f9f9' }
|
||||
* @property {Object} panel - 标签面板样式(非激活状态)
|
||||
* @example { opacity: 0.5, transform: 'translateY(10px)' }
|
||||
* @property {Object} panelActive - 标签面板激活样式
|
||||
* @example { opacity: 1, transform: 'translateY(0)' }
|
||||
*/
|
||||
customStyles: {
|
||||
container: {},
|
||||
nav: {},
|
||||
tabItem: {},
|
||||
tabItemActive: {},
|
||||
tabText: {},
|
||||
tabTextActive: {},
|
||||
indicator: {},
|
||||
content: {},
|
||||
panel: {},
|
||||
panelActive: {}
|
||||
}
|
||||
};
|
||||
|
||||
// 合并所有配置
|
||||
const defaults = {
|
||||
...tabsConfig,
|
||||
...baseConfig,
|
||||
...navConfig,
|
||||
...tabItemConfig,
|
||||
...cardConfig,
|
||||
...underlineConfig,
|
||||
...indicatorConfig,
|
||||
...contentConfig,
|
||||
...customStylesConfig
|
||||
};
|
||||
|
||||
// 使用展开运算符合并默认值和传入值
|
||||
return { ...defaults, ...this.value };
|
||||
},
|
||||
|
||||
// 判断是否为水平布局(顶部或底部)
|
||||
isHorizontal() {
|
||||
return ['top', 'bottom'].includes(this.mergedValue.tabPosition);
|
||||
},
|
||||
|
||||
// 判断是否为垂直布局(左侧或右侧)
|
||||
isVertical() {
|
||||
return ['left', 'right'].includes(this.mergedValue.tabPosition);
|
||||
},
|
||||
|
||||
// 判断是否为卡片样式
|
||||
isCardStyle() {
|
||||
return this.mergedValue.tabStyle === 'card';
|
||||
},
|
||||
|
||||
// 判断是否为下划线样式
|
||||
isUnderlineStyle() {
|
||||
return this.mergedValue.tabStyle === 'underline';
|
||||
},
|
||||
|
||||
// 计算标签导航栏样式
|
||||
tabNavStyle() {
|
||||
const style = {
|
||||
backgroundColor: this.mergedValue.tabBgColor || '#ffffff'
|
||||
};
|
||||
|
||||
// 根据布局方向设置尺寸
|
||||
if (this.isHorizontal) {
|
||||
// 水平布局:设置高度
|
||||
style.height = this.mergedValue.tabHeight + 'px';
|
||||
} else {
|
||||
// 垂直布局:设置宽度和高度
|
||||
style.width = this.mergedValue.tabHeight + 'px';
|
||||
style.height = '100%';
|
||||
style.flexDirection = 'column';
|
||||
}
|
||||
|
||||
// 设置导航栏内边距
|
||||
if (this.mergedValue.tabPadding) {
|
||||
style.padding = this.mergedValue.tabPadding;
|
||||
}
|
||||
|
||||
// 卡片样式下使用标签间距作为内边距
|
||||
if (this.isCardStyle) {
|
||||
style.padding = this.getPadding(this.mergedValue.tabGap);
|
||||
}
|
||||
|
||||
return style;
|
||||
},
|
||||
|
||||
// 计算标签项样式(返回函数)
|
||||
tabItemStyle() {
|
||||
return (index) => {
|
||||
const style = {};
|
||||
|
||||
if (!this.isCardStyle) {
|
||||
// 非卡片样式:设置内边距
|
||||
style.padding = this.getPadding(this.mergedValue.tabGap);
|
||||
} else {
|
||||
// 卡片样式:设置外边距、内边距、圆角和背景色
|
||||
style.margin = this.getCardMargin();
|
||||
style.padding = this.getCardPadding();
|
||||
style.borderRadius = this.mergedValue.cardBorderRadius || '16px';
|
||||
// 根据激活状态设置不同的背景色
|
||||
style.backgroundColor = index === this.activeTab
|
||||
? (this.mergedValue.cardActiveBgColor || this.mergedValue.activeColor)
|
||||
: (this.mergedValue.cardBgColor || '#f5f5f5');
|
||||
}
|
||||
|
||||
return style;
|
||||
};
|
||||
},
|
||||
|
||||
// 计算标签内容区域样式
|
||||
tabContentStyle() {
|
||||
return {
|
||||
padding: this.mergedValue.contentPadding + 'px',
|
||||
backgroundColor: this.mergedValue.contentBgColor || '#f5f5f5',
|
||||
minHeight: (this.mergedValue.contentMinHeight || 200) + 'px'
|
||||
};
|
||||
},
|
||||
|
||||
// 计算标签文本样式(返回函数)
|
||||
tabTextStyle() {
|
||||
return (index) => ({
|
||||
color: this.activeColor(index),
|
||||
fontSize: (this.mergedValue.fontSize || 14) + 'px'
|
||||
});
|
||||
},
|
||||
|
||||
// 计算标签指示器样式(返回函数)
|
||||
tabIndicatorStyle() {
|
||||
return (index) => {
|
||||
const style = {
|
||||
backgroundColor: this.mergedValue.indicatorColor || this.mergedValue.activeColor,
|
||||
transform: index === this.activeTab ? 'scaleX(1)' : 'scaleX(0)',
|
||||
opacity: index === this.activeTab ? 1 : 0
|
||||
};
|
||||
|
||||
// 卡片样式下隐藏指示器
|
||||
if (this.isCardStyle) {
|
||||
style.display = 'none';
|
||||
} else if (this.isUnderlineStyle) {
|
||||
// 下划线样式使用下划线颜色
|
||||
style.backgroundColor = this.mergedValue.underlineColor || this.mergedValue.activeColor;
|
||||
}
|
||||
|
||||
// 根据样式类型选择指示器尺寸
|
||||
const indicatorSize = (this.isUnderlineStyle ? this.mergedValue.underlineHeight : this.mergedValue.indicatorHeight) || 2;
|
||||
|
||||
// 根据布局方向设置指示器样式
|
||||
if (this.isHorizontal) {
|
||||
// 水平布局:设置高度,使用 scaleX 动画
|
||||
style.height = indicatorSize + 'px';
|
||||
style.transform = index === this.activeTab ? 'scaleX(1)' : 'scaleX(0)';
|
||||
} else {
|
||||
// 垂直布局:设置宽度,使用 scaleY 动画
|
||||
style.width = indicatorSize + 'px';
|
||||
style.height = 'auto';
|
||||
style.transform = index === this.activeTab ? 'scaleY(1)' : 'scaleY(0)';
|
||||
}
|
||||
|
||||
return style;
|
||||
};
|
||||
},
|
||||
|
||||
// 计算标签面板样式(返回函数)
|
||||
tabPanelStyle() {
|
||||
return (index) => {
|
||||
const isActive = index === this.activeTab;
|
||||
const style = {
|
||||
display: isActive ? 'block' : 'none',
|
||||
opacity: isActive ? 1 : 0
|
||||
};
|
||||
|
||||
// 根据标签位置定义不同的动画效果
|
||||
const transformMap = {
|
||||
top: ['translateY(0)', 'translateY(10px)'], // 顶部:从下往上滑入
|
||||
bottom: ['translateY(0)', 'translateY(-10px)'], // 底部:从上往下滑入
|
||||
left: ['translateX(0)', 'translateX(10px)'], // 左侧:从右往左滑入
|
||||
right: ['translateX(0)', 'translateX(-10px)'] // 右侧:从左往右滑入
|
||||
};
|
||||
|
||||
// 获取对应的变换值,默认使用无变换
|
||||
const transforms = transformMap[this.mergedValue.tabPosition] || ['translate(0)', 'translate(0)'];
|
||||
// 根据激活状态应用不同的变换
|
||||
style.transform = isActive ? transforms[0] : transforms[1];
|
||||
|
||||
return style;
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// 组件方法
|
||||
methods: {
|
||||
// 获取自定义样式
|
||||
getCustomStyle(type) {
|
||||
const customStyles = this.mergedValue.customStyles || {};
|
||||
return customStyles[type] || {};
|
||||
},
|
||||
|
||||
// 获取标签文字颜色
|
||||
activeColor(index) {
|
||||
if (this.isCardStyle) {
|
||||
// 卡片样式:使用卡片文字颜色
|
||||
return index === this.activeTab
|
||||
? (this.mergedValue.cardActiveTextColor || '#ffffff')
|
||||
: (this.mergedValue.cardTextColor || this.mergedValue.inactiveColor);
|
||||
}
|
||||
// 其他样式:使用通用文字颜色
|
||||
return index === this.activeTab ? this.mergedValue.activeColor : this.mergedValue.inactiveColor;
|
||||
},
|
||||
|
||||
// 根据布局方向获取内边距
|
||||
getPadding(gap) {
|
||||
return this.isHorizontal ? `0 ${gap}px` : `${gap}px 0`;
|
||||
},
|
||||
|
||||
// 根据布局方向获取外边距
|
||||
getMargin(gap) {
|
||||
return this.isHorizontal ? `0 ${gap}px` : `${gap}px 0`;
|
||||
},
|
||||
|
||||
// 获取卡片外边距
|
||||
getCardMargin() {
|
||||
return this.mergedValue.cardMargin || this.getMargin(this.mergedValue.tabGap / 2);
|
||||
},
|
||||
|
||||
// 获取卡片内边距
|
||||
getCardPadding() {
|
||||
return this.mergedValue.cardPadding || (this.isHorizontal ? '0 10px' : '10px 0');
|
||||
},
|
||||
|
||||
// 切换标签
|
||||
switchTab(index) {
|
||||
this.activeTab = index;
|
||||
},
|
||||
|
||||
// 国际化方法:获取标签标题
|
||||
getTabTitle(title) {
|
||||
const locale = this.$langConfig.getCurrentLocale();
|
||||
|
||||
// 如果 title 是对象,根据当前语言返回对应值
|
||||
if (typeof title === 'object' && title !== null) {
|
||||
return title[locale] || title['zh-cn'] || Object.values(title)[0] || '';
|
||||
}
|
||||
|
||||
// 如果 title 是字符串,保持原有逻辑
|
||||
if (typeof title === 'string' && title.includes('.')) {
|
||||
// 包含点号的标题视为国际化键,使用全局挂载的 $lang 方法翻译
|
||||
return this.$lang ? this.$lang(title) : title;
|
||||
}
|
||||
|
||||
// 不包含点号的标题直接返回
|
||||
return title;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// ===== 标签布局 Mixin =====
|
||||
// 用于定义不同位置标签的布局方式
|
||||
@mixin tab-layout($direction, $nav-order, $content-order) {
|
||||
flex-direction: $direction;
|
||||
|
||||
.tab-nav {
|
||||
order: $nav-order;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
order: $content-order;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 指示器位置 Mixin =====
|
||||
// 用于定义不同位置指示器的定位
|
||||
@mixin indicator-position($position, $start, $end) {
|
||||
#{$position}: 0;
|
||||
#{$start}: 0;
|
||||
#{$end}: 0;
|
||||
width: 2px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// ===== 主容器样式 =====
|
||||
.diy-tab {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
// 默认顶部布局
|
||||
@include tab-layout(column, 1, 2);
|
||||
|
||||
// 底部布局
|
||||
&.tab-position-bottom {
|
||||
@include tab-layout(column, 2, 1);
|
||||
}
|
||||
|
||||
// 左侧布局
|
||||
&.tab-position-left {
|
||||
@include tab-layout(row, 1, 2);
|
||||
}
|
||||
|
||||
// 右侧布局
|
||||
&.tab-position-right {
|
||||
@include tab-layout(row, 2, 1);
|
||||
}
|
||||
|
||||
// ===== 标签导航栏样式 =====
|
||||
.tab-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
overflow-x: auto; // 水平滚动
|
||||
overflow-y: hidden; // 禁止垂直滚动
|
||||
white-space: nowrap; // 不换行
|
||||
position: relative;
|
||||
|
||||
// 隐藏滚动条(Webkit 浏览器)
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// 隐藏滚动条(IE/Edge)
|
||||
-ms-overflow-style: none;
|
||||
// 隐藏滚动条(Firefox)
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
// ===== 标签项样式 =====
|
||||
.tab-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
padding: 0 16px;
|
||||
height: 100%;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
// 激活状态
|
||||
&.active {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
// 减少动画效果(针对偏好减少动画的用户)
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 左右布局下的标签项样式
|
||||
&.tab-position-left .tab-item,
|
||||
&.tab-position-right .tab-item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding: 10px 0;
|
||||
white-space: normal; // 允许换行
|
||||
}
|
||||
|
||||
// ===== 标签文本样式 =====
|
||||
.tab-text {
|
||||
font-size: 14px;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
// ===== 标签指示器样式 =====
|
||||
.tab-indicator {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
transition: all 0.3s ease;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
// 左侧布局的指示器
|
||||
&.tab-position-left .tab-indicator {
|
||||
@include indicator-position(left, top, bottom);
|
||||
}
|
||||
|
||||
// 右侧布局的指示器
|
||||
&.tab-position-right .tab-indicator {
|
||||
@include indicator-position(right, top, bottom);
|
||||
}
|
||||
|
||||
// ===== 标签内容区域样式 =====
|
||||
.tab-content {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
// ===== 标签面板样式 =====
|
||||
.tab-panel {
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
// 减少动画效果
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 默认和下划线样式 =====
|
||||
.tab-item.default,
|
||||
.tab-item.underline {
|
||||
padding: 0 10px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.active {
|
||||
color: #ff4444;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
// 下划线样式的伪元素
|
||||
.tab-item.underline.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
// ===== 卡片样式 =====
|
||||
.tab-item.card {
|
||||
border-radius: 16px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.active {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<view data-component-name="diy-text" class="diy-text" @tap="handlerClick(value.link)" :style="warpCss">
|
||||
<view data-component-name="diy-text" class="diy-text" @click="handlerClick(value.link)"
|
||||
@tap="handlerClick(value.link)" :style="warpCss">
|
||||
<view :class="value.style == 'style-8' ? 'title2' : 'title'"
|
||||
:style="{ fontSize: value.fontSize * 2 + 'rpx', color: value.textColor }">
|
||||
<block v-if="value.style == 'style-0'" style="height: 40rpx; line-height: 40rpx;">
|
||||
@@ -99,13 +100,13 @@
|
||||
<image :src="$util.img('public/uniapp/diy/style9-2.png')" />
|
||||
</view>
|
||||
<view class="style9-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||
@tap.stop="handlerClick(value.more.link)">
|
||||
@click.stop="handlerClick(value.more.link)" @tap="handlerClick(value.more.link)">
|
||||
{{ value.more.text }}
|
||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
@@ -131,13 +132,13 @@
|
||||
<image :src="$util.img('public/uniapp/diy/style10-2.png')"></image>
|
||||
</view>
|
||||
<view class="style10-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||
@tap.stop="handlerClick(value.more.link)">
|
||||
@click.stop="handlerClick(value.more.link)" @tap="handlerClick(value.more.link)">
|
||||
{{ value.more.text }}
|
||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
@@ -158,7 +159,7 @@
|
||||
value.subTitle.text }}</view>
|
||||
</view>
|
||||
<view class="style11-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||
@tap.stop="$util.diyRedirectTo(value.more.link)">
|
||||
@click.stop="$util.diyRedirectTo(value.more.link)">
|
||||
{{ value.more.text }}
|
||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||
</view>
|
||||
@@ -182,9 +183,9 @@
|
||||
{{ value.text }}
|
||||
</view>
|
||||
<text class="style12-sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
|
||||
}}</text>
|
||||
}}</text>
|
||||
<view class="style12-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||
@tap.stop="$util.diyRedirectTo(value.more.link)">
|
||||
@click.stop="$util.diyRedirectTo(value.more.link)">
|
||||
<text>{{ value.more.text }}</text>
|
||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||
</view>
|
||||
@@ -277,7 +278,7 @@
|
||||
<text :style="{ fontWeight: value.subTitle.fontWeight }">{{ value.subTitle.text }}</text>
|
||||
</view>
|
||||
<view class="style16-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||
@tap.stop="$util.diyRedirectTo(value.more.link)">
|
||||
@click.stop="$util.diyRedirectTo(value.more.link)">
|
||||
<text>{{ value.more.text }}</text>
|
||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||
</view>
|
||||
@@ -323,7 +324,7 @@ export default {
|
||||
await this.__$emitEvent({
|
||||
eventName: 'text-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
|
||||
if (!awaitedResult) return;
|
||||
this.$util.diyRedirectTo(link);
|
||||
$util.diyRedirectTo(link);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -62,10 +62,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import uniPopup from '@/components/uni-popup/uni-popup.vue'
|
||||
import DiyMinx from './minx.js'
|
||||
export default {
|
||||
name: 'diy-video-list',
|
||||
components: {
|
||||
uniPopup
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<video data-component-name="diy-video" class="diy-video" :src="$util.img(value.videoUrl)"
|
||||
:poster="$util.img(value.imageUrl)" :style="videoWarpCss" objectFit="cover"
|
||||
@tap="handlerClick(value.videoUrl)"></video>
|
||||
@click="handlerClick(value.videoUrl)" @tap="handlerClick(value.videoUrl)"></video>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
// 微信视频号组件配置
|
||||
export const wechatChannelConfig = {
|
||||
// 图标相关
|
||||
icon: {
|
||||
defaultSize: 80, // 默认图标尺寸(rpx)
|
||||
smallSize: 60, // 小图标尺寸(rpx)
|
||||
channelArrowSize: 24, // 频道箭头图标尺寸(rpx)
|
||||
channelArrow: 'addon/personnel/shop/view/enterprise/arrow.png', // 频道箭头图标路径
|
||||
},
|
||||
|
||||
|
||||
// 视频相关配置
|
||||
video: {
|
||||
defaultHeight: 320, // 默认视频高度(rpx)
|
||||
minHeight: 200, // 最小视频高度(rpx)
|
||||
maxHeight: 500, // 最大视频高度(rpx)
|
||||
defaultCoverUrl: 'addon/personnel/shop/view/enterprise/default-video-cover.png', // 默认视频封面
|
||||
},
|
||||
|
||||
// 播放按钮配置
|
||||
playButton: {
|
||||
size: 80, // 标准尺寸(rpx)
|
||||
smallSize: 60, // 小尺寸(rpx)
|
||||
iconSize: 40, // 标准图标尺寸(rpx)
|
||||
smallIconSize: 30, // 小图标尺寸(rpx)
|
||||
background: 'rgba(0, 0, 0, 0.4)', // 背景颜色
|
||||
},
|
||||
|
||||
// 布局配置
|
||||
layout: {
|
||||
borderRadius: 12, // 圆角(rpx)
|
||||
padding: 16, // 内边距(rpx)
|
||||
margin: 10, // 外边距(rpx)
|
||||
},
|
||||
|
||||
// 字体配置
|
||||
font: {
|
||||
channelNameSize: 28, // 频道名称字体大小(rpx)
|
||||
videoTitleSize: 28, // 视频标题字体大小(rpx)
|
||||
statsSize: 24, // 统计信息字体大小(rpx)
|
||||
},
|
||||
|
||||
// 颜色配置
|
||||
color: {
|
||||
channelName: '#333', // 频道名称颜色
|
||||
videoTitle: '#333', // 视频标题颜色
|
||||
stats: '#999', // 统计信息颜色
|
||||
border: '#f0f0f0', // 边框颜色
|
||||
},
|
||||
|
||||
// 微信相关配置
|
||||
wechat: {
|
||||
minSdkVersion: '2.19.2', // 最小微信基础库版本
|
||||
embedComponent: 'channel-video', // 嵌入式视频组件名称
|
||||
},
|
||||
|
||||
// 错误提示配置
|
||||
error: {
|
||||
notWechat: '当前环境不是微信小程序',
|
||||
lowVersion: '当前微信基础库版本过低,需要 2.19.2 或以上版本',
|
||||
notSupported: '当前环境不支持微信视频号',
|
||||
missingFields: '缺少必要字段: {field}',
|
||||
},
|
||||
};
|
||||
|
||||
// 获取配置项的辅助函数
|
||||
export const getwechatChannelConfig = (key, defaultValue = null) => {
|
||||
const keys = key.split('.');
|
||||
let config = wechatChannelConfig;
|
||||
|
||||
for (const k of keys) {
|
||||
if (config[k] === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
config = config[k];
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
// 微信视频号工具函数
|
||||
export const wechatChannelUtil = {
|
||||
// 版本比较
|
||||
versionCompare(v1, v2) {
|
||||
const arr1 = v1.split('.');
|
||||
const arr2 = v2.split('.');
|
||||
for (let i = 0; i < Math.max(arr1.length, arr2.length); i++) {
|
||||
const num1 = parseInt(arr1[i] || 0);
|
||||
const num2 = parseInt(arr2[i] || 0);
|
||||
if (num1 > num2) return 1;
|
||||
if (num1 < num2) return -1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
// 检查是否支持嵌入式播放
|
||||
isEmbedModeSupported() {
|
||||
return typeof wx !== 'undefined' && wx.canIUse(wechatChannelConfig.wechat.embedComponent);
|
||||
},
|
||||
|
||||
// 获取默认视频封面
|
||||
getDefaultCoverUrl() {
|
||||
return wechatChannelConfig.video.defaultCoverUrl;
|
||||
},
|
||||
|
||||
// 数据校验
|
||||
validateVideoData(item) {
|
||||
const requiredFields = ['feedId', 'finderUserName'];
|
||||
for (const field of requiredFields) {
|
||||
if (!item[field]) {
|
||||
throw new Error(`缺少必要字段: ${field}`);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// 播放视频
|
||||
playVideo(item) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
// 数据校验
|
||||
this.validateVideoData(item);
|
||||
} catch (err) {
|
||||
this.handleError(err, item);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查微信环境
|
||||
if (typeof wx === 'undefined') {
|
||||
const err = new Error(wechatChannelConfig.error.notWechat);
|
||||
this.handleError(err, item);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查基础库版本
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
const SDKVersion = systemInfo.SDKVersion;
|
||||
if (this.versionCompare(SDKVersion, wechatChannelConfig.wechat.minSdkVersion) < 0) {
|
||||
const err = new Error(wechatChannelConfig.error.lowVersion);
|
||||
this.handleError(err, item);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用微信视频号播放API
|
||||
if (wx.openChannelsActivity) {
|
||||
wx.openChannelsActivity({
|
||||
feedId: item.feedId,
|
||||
finderUserName: item.finderUserName,
|
||||
success: (res) => {
|
||||
console.log('打开视频号成功', res);
|
||||
resolve(res);
|
||||
},
|
||||
fail: (err) => {
|
||||
this.handleError(err, item);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const err = new Error(wechatChannelConfig.error.notSupported);
|
||||
this.handleError(err, item);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 统一错误处理
|
||||
handleError(err, item) {
|
||||
console.error('微信视频号错误:', err);
|
||||
const { message = '', errMsg = '微信视频播放失败!', errCode = -1 } = err;
|
||||
|
||||
// 错误码5: 表示用户点击了取消. openChannelsActivity:fail cancel
|
||||
if ([5].includes(errCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const showErrorToast = (otherMsgs = []) => {
|
||||
uni.showToast({
|
||||
title: [errMsg, message,...otherMsgs].join('\n'),
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
showErrorToast();
|
||||
}
|
||||
};
|
||||
@@ -5,18 +5,5 @@ export default {
|
||||
// console.log('__$emitEvent', payload)
|
||||
await this.$eventBus.emit(payload.eventName, payload.data, payload.promiseCallback)
|
||||
},
|
||||
|
||||
// 预览图片
|
||||
previewImg(img) {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.previewImage({
|
||||
current: 0,
|
||||
urls: [this.$util.img(img)],
|
||||
success: function (res) { },
|
||||
fail: function (res) { },
|
||||
complete: function (res) { },
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
}
|
||||
}
|
||||
6
components/ai-chat-message/ai-chat-message.json
Normal file
6
components/ai-chat-message/ai-chat-message.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"ns-loading": "../ns-loading/ns-loading"
|
||||
}
|
||||
}
|
||||
@@ -357,10 +357,14 @@
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue'
|
||||
import aiService from '@/common/js/ai-service.js'
|
||||
|
||||
export default {
|
||||
name: 'ai-chat-message',
|
||||
components: {
|
||||
nsLoading
|
||||
},
|
||||
props: {
|
||||
// 初始消息列表
|
||||
initialMessages: {
|
||||
@@ -441,14 +445,6 @@ export default {
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
// 如果不是 AI 客服,立即退出并跳转
|
||||
if (customerServiceType !== 'ai') {
|
||||
uni.showToast({ title: '当前客服类型不支持此页面', icon: 'none' });
|
||||
setTimeout(() => {
|
||||
uni.navigateBack({ delta: 1 }); // 或 redirectTo 首页
|
||||
}, 1000);
|
||||
return; // ⚠️ 关键:阻止后续初始化
|
||||
}
|
||||
// 优先读取本地缓存的会话 ID
|
||||
const localConvId = this.getConversationIdFromLocal();
|
||||
if (localConvId) {
|
||||
@@ -818,121 +814,65 @@ export default {
|
||||
},
|
||||
|
||||
// 发送流式消息
|
||||
// 发送流式消息(自动适配 H5 / 微信小程序)
|
||||
async sendStreamMessage(userMessage) {
|
||||
// 创建流式消息对象
|
||||
const streamMessage = {
|
||||
id: ++this.messageId,
|
||||
role: 'ai',
|
||||
type: 'text',
|
||||
content: '',
|
||||
timestamp: Date.now(),
|
||||
isStreaming: true
|
||||
};
|
||||
|
||||
// 移除加载状态,添加流式消息
|
||||
this.messages = this.messages.filter(msg => msg.type !== 'loading');
|
||||
this.shouldScrollToBottom = true;
|
||||
this.messages.push(streamMessage);
|
||||
|
||||
try {
|
||||
// #ifdef H5
|
||||
// ===== H5: 使用 POST + 流式 (fetch readable stream) =====
|
||||
await aiService.sendHttpStream(
|
||||
async sendStreamMessage(userMessage) {
|
||||
// 创建流式消息对象
|
||||
const streamMessage = {
|
||||
id: ++this.messageId,
|
||||
role: 'ai',
|
||||
type: 'text',
|
||||
content: '',
|
||||
timestamp: Date.now(),
|
||||
isStreaming: true
|
||||
}
|
||||
|
||||
// 移除加载状态,添加流式消息
|
||||
this.messages = this.messages.filter(msg => msg.type !== 'loading')
|
||||
this.shouldScrollToBottom = true
|
||||
this.messages.push(streamMessage)
|
||||
|
||||
// 开始流式响应
|
||||
await aiService.sendStreamMessage(
|
||||
userMessage,
|
||||
// 流式数据回调
|
||||
(chunk) => {
|
||||
// 实时更新内容
|
||||
streamMessage.content += chunk;
|
||||
this.$forceUpdate(); // 强制更新视图
|
||||
streamMessage.content += chunk
|
||||
this.$forceUpdate() // 或 this.$nextTick()
|
||||
},
|
||||
// 完成回调:处理对象或字符串
|
||||
(completeResult) => {
|
||||
// 流结束回调
|
||||
let finalContent = '';
|
||||
let convId = '';
|
||||
|
||||
|
||||
// 判断是对象还是字符串
|
||||
if (typeof completeResult === 'string') {
|
||||
finalContent = completeResult;
|
||||
} else {
|
||||
finalContent = completeResult.content || '';
|
||||
convId = completeResult.conversation_id || '';
|
||||
convId = completeResult.conversation_id || ''; // 👈 关键:提取 conversation_id
|
||||
}
|
||||
|
||||
// 更新最终内容
|
||||
|
||||
// 更新消息状态
|
||||
streamMessage.isStreaming = false;
|
||||
streamMessage.content = finalContent;
|
||||
|
||||
|
||||
// 添加操作按钮
|
||||
streamMessage.actions = [
|
||||
{ id: 1, text: '有帮助', type: 'like' },
|
||||
{ id: 2, text: '没帮助', type: 'dislike' }
|
||||
];
|
||||
|
||||
// 保存会话 ID
|
||||
|
||||
// 保存 conversation_id 到本地
|
||||
if (convId) {
|
||||
this.currentConversationId = convId;
|
||||
aiService.setConversationId(convId);
|
||||
this.saveConversationIdToLocal(convId);
|
||||
}
|
||||
|
||||
|
||||
// 触发事件
|
||||
this.$emit('ai-response', streamMessage);
|
||||
this.saveConversationIdToLocal(convId);
|
||||
this.currentConversationId = convId;
|
||||
}
|
||||
);
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// ===== 微信小程序: 使用 WebSocket =====
|
||||
await aiService.sendStreamMessage(
|
||||
userMessage,
|
||||
(chunk) => {
|
||||
// 实时更新内容
|
||||
streamMessage.content += chunk;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
(completeResult) => {
|
||||
// 流结束回调
|
||||
let finalContent = completeResult?.content || '';
|
||||
let convId = completeResult?.conversation_id || '';
|
||||
|
||||
// 更新最终内容
|
||||
streamMessage.isStreaming = false;
|
||||
streamMessage.content = finalContent;
|
||||
|
||||
// 添加操作按钮
|
||||
streamMessage.actions = [
|
||||
{ id: 1, text: '有帮助', type: 'like' },
|
||||
{ id: 2, text: '没帮助', type: 'dislike' }
|
||||
];
|
||||
|
||||
// 保存会话 ID
|
||||
if (convId) {
|
||||
this.currentConversationId = convId;
|
||||
aiService.setConversationId(convId);
|
||||
this.saveConversationIdToLocal(convId);
|
||||
}
|
||||
|
||||
// 触发事件
|
||||
this.$emit('ai-response', streamMessage);
|
||||
}
|
||||
);
|
||||
// #endif
|
||||
} catch (error) {
|
||||
console.error('流式请求失败:', error);
|
||||
// 移除流式消息
|
||||
this.messages = this.messages.filter(msg => msg.id !== streamMessage.id);
|
||||
// 显示错误
|
||||
const errorMsg = {
|
||||
id: ++this.messageId,
|
||||
role: 'ai',
|
||||
type: 'text',
|
||||
content: '抱歉,服务暂时不可用,请稍后重试。',
|
||||
timestamp: Date.now(),
|
||||
actions: [{ id: 1, text: '重试', type: 'retry' }]
|
||||
};
|
||||
this.messages.push(errorMsg);
|
||||
this.$emit('ai-response', errorMsg);
|
||||
}
|
||||
},
|
||||
},
|
||||
generateAIResponse(userMessage) {
|
||||
const responses = {
|
||||
'你好': '您好!我是AI智能客服,很高兴为您服务!有什么可以帮助您的吗?',
|
||||
@@ -1452,7 +1392,7 @@ $radius-lg: 36rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* 仅新增:科技感粉蓝渐变背景 + 流动动画 */
|
||||
background: white; /* 白色 */
|
||||
background: linear-gradient(135deg, #fde6f7 0%, #f8b7e8 20%, #c4e0ff 50%, #8cb4ff 80%, #ffffff 100%);
|
||||
background-size: 200% 200%;
|
||||
animation: gradient-flow 15s ease infinite;
|
||||
/* 原有样式保持不变 */
|
||||
@@ -1514,6 +1454,25 @@ $radius-lg: 36rpx;
|
||||
min-width: 0;
|
||||
width: 0; /* 添加这个属性防止flex元素溢出 */
|
||||
|
||||
.message-nickname {
|
||||
font-size: 24rpx;
|
||||
color: $color-text-light;
|
||||
margin-bottom: 8rpx;
|
||||
letter-spacing: 0.5rpx;
|
||||
// 用户昵称右对齐,AI昵称左对齐
|
||||
&:not(.ai-message .message-nickname) {
|
||||
text-align: right;
|
||||
}
|
||||
// AI昵称专属样式 - 左移到气泡上方
|
||||
&.ai-nickname {
|
||||
text-align: left;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
align-self: flex-start;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.message-bubble {
|
||||
padding: 24rpx 32rpx;
|
||||
max-width: 100%;
|
||||
@@ -1933,28 +1892,6 @@ $radius-lg: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== 关键修复:拆分 .message-nickname 样式 ========== */
|
||||
.message-nickname {
|
||||
font-size: 24rpx;
|
||||
color: $color-text-light;
|
||||
margin-bottom: 8rpx;
|
||||
letter-spacing: 0.5rpx;
|
||||
}
|
||||
|
||||
/* 用户昵称:右对齐 */
|
||||
.user-message .message-nickname {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* AI 昵称:使用 .ai-nickname 类控制 */
|
||||
.ai-nickname {
|
||||
text-align: left;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
align-self: flex-start;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
/* 用户消息特有样式 */
|
||||
.user-message {
|
||||
flex-direction: row-reverse;
|
||||
@@ -1965,20 +1902,20 @@ $radius-lg: 36rpx;
|
||||
text-align: right;
|
||||
|
||||
.message-bubble {
|
||||
background: #c4e0ff !important; /* 浅蓝色 */
|
||||
color: black !important;
|
||||
border-radius: 16rpx 16rpx 4rpx 16rpx; /* 右对齐气泡尖角适配 */
|
||||
box-shadow: 0 8rpx 20rpx rgba(196, 224, 255, 0.3) !important;
|
||||
border: none !important;
|
||||
/* ✅ 关键:允许内容撑开高度 */
|
||||
min-height: auto;
|
||||
height: auto;
|
||||
padding: 24rpx 32rpx; /* 保留内边距 */
|
||||
display: inline-block; /* 让宽度也随内容收缩(可选) */
|
||||
max-width: 80%; /* 防止过宽 */
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap; /* 保留用户输入的换行符 */
|
||||
line-height: 1.6;
|
||||
background: linear-gradient(135deg, #ffadd2, #f783ac) !important; /* 粉色渐变 */
|
||||
color: white !important;
|
||||
border-radius: 16rpx 16rpx 4rpx 16rpx; /* 右对齐气泡尖角适配 */
|
||||
box-shadow: 0 8rpx 20rpx rgba(247, 131, 172, 0.3) !important;
|
||||
border: none !important;
|
||||
/* ✅ 关键:允许内容撑开高度 */
|
||||
min-height: auto;
|
||||
height: auto;
|
||||
padding: 24rpx 32rpx; /* 保留内边距 */
|
||||
display: inline-block; /* 让宽度也随内容收缩(可选) */
|
||||
max-width: 80%; /* 防止过宽 */
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap; /* 保留用户输入的换行符 */
|
||||
line-height: 1.6;
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@@ -2019,19 +1956,19 @@ $radius-lg: 36rpx;
|
||||
align-items: flex-start;
|
||||
|
||||
.message-bubble {
|
||||
background: white !important; /* 白色 */
|
||||
color: black !important;
|
||||
border-radius: 16rpx 16rpx 16rpx 4rpx; /* 左对齐气泡尖角适配 */
|
||||
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.1) !important;
|
||||
border: 1rpx solid #e0e0e0 !important;
|
||||
background: linear-gradient(135deg, #dbeafe, #bfdbfe) !important; /* 蓝色浅渐变 */
|
||||
color: #2c3e50 !important;
|
||||
border-radius: 16rpx 16rpx 16rpx 4rpx; /* 左对齐气泡尖角适配 */
|
||||
box-shadow: 0 8rpx 20rpx rgba(191, 219, 254, 0.4) !important;
|
||||
border: 1rpx solid #dbeafe !important;
|
||||
min-height: auto;
|
||||
height: auto;
|
||||
padding: 24rpx 32rpx;
|
||||
display: inline-block;
|
||||
max-width: 80%;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
line-height: 1.6;
|
||||
height: auto;
|
||||
padding: 24rpx 32rpx;
|
||||
display: inline-block;
|
||||
max-width: 80%;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
line-height: 1.6;
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@@ -2055,7 +1992,7 @@ $radius-lg: 36rpx;
|
||||
|
||||
/* 输入区域 */
|
||||
.input-area {
|
||||
background: #c4e0ff; /* 浅蓝色 */
|
||||
background: linear-gradient(135deg, #fde6f7 0%, #f8b7e8 20%, #c4e0ff 50%, #8cb4ff 80%, #ffffff 100%);
|
||||
border-top: 2rpx solid #f0f4f8;
|
||||
padding: 24rpx 32rpx;
|
||||
/* 确保在微信小程序中紧贴底部 */
|
||||
@@ -2139,10 +2076,10 @@ $radius-lg: 36rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
text-align: center; /* 兼容多端文字居中 */
|
||||
white-space: nowrap; /* 强制文字单行横向显示 */
|
||||
line-height: 1; /* 重置行高,避免文字垂直偏移 */
|
||||
top: -10px;
|
||||
text-align: center; /* 兼容多端文字居中 */
|
||||
white-space: nowrap; /* 强制文字单行横向显示 */
|
||||
line-height: 1; /* 重置行高,避免文字垂直偏移 */
|
||||
top:-10px;
|
||||
|
||||
&.disabled {
|
||||
background-color: $color-primary-light;
|
||||
@@ -2826,4 +2763,4 @@ $radius-lg: 36rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@@ -635,6 +635,7 @@
|
||||
|
||||
<script>
|
||||
import payment from './payment.js';
|
||||
|
||||
export default {
|
||||
name: 'common-payment',
|
||||
data() {
|
||||
@@ -270,7 +270,7 @@ export default {
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
@@ -3,21 +3,16 @@
|
||||
<view scroll-y="true" class="goods-detail" :class="isIphoneX ? 'active' : ''">
|
||||
<view class="goods-container">
|
||||
<!-- 弹幕 -->
|
||||
<pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai"
|
||||
:duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true"
|
||||
:info="goodsSkuDetail.barrageData" />
|
||||
<pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai" :duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true" :info="goodsSkuDetail.barrageData"/>
|
||||
|
||||
<!-- 商品媒体信息 -->
|
||||
<view class="goods-media" :style="{ height: goodsSkuDetail.swiperHeight }">
|
||||
<view class="goods-media" :style="{height: goodsSkuDetail.swiperHeight}">
|
||||
<!-- 商品图片 -->
|
||||
<view class="goods-img" :class="{ show: switchMedia == 'img' }">
|
||||
<swiper class="swiper" @change="swiperChange" :interval="swiperInterval"
|
||||
:autoplay="swiperAutoplay" autoplay="true" interval="4000" circular="true">
|
||||
<swiper-item v-for="(item, index) in goodsSkuDetail.sku_images" :key="index"
|
||||
:item-id="'goods_id_' + index">
|
||||
<swiper class="swiper" @change="swiperChange" :interval="swiperInterval" :autoplay="swiperAutoplay" autoplay="true" interval="4000" circular="true">
|
||||
<swiper-item v-for="(item, index) in goodsSkuDetail.sku_images" :key="index" :item-id="'goods_id_' + index">
|
||||
<view class="item" @click="previewMedia(index)">
|
||||
<image :src="$util.img(item, { size: 'big' })" @error="swiperImageError(index)"
|
||||
mode="aspectFit" />
|
||||
<image :src="$util.img(item, { size: 'big' })" @error="swiperImageError(index)" mode="aspectFit" />
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
@@ -29,16 +24,13 @@
|
||||
|
||||
<!-- 商品视频 -->
|
||||
<view class="goods-video" :class="{ show: switchMedia == 'video' }">
|
||||
<video id="goodsVideo" :src="$util.img(goodsSkuDetail.video_url)"
|
||||
:poster="$util.img(goodsSkuDetail.sku_image, { size: 'big' })" objectFit="cover"></video>
|
||||
<video id="goodsVideo" :src="$util.img(goodsSkuDetail.video_url)" :poster="$util.img(goodsSkuDetail.sku_image, { size: 'big' })" objectFit="cover"></video>
|
||||
</view>
|
||||
|
||||
<!-- 切换视频、图片 -->
|
||||
<view class="media-mode" v-if="goodsSkuDetail.video_url != ''">
|
||||
<text :class="{ 'color-base-bg': switchMedia == 'video' }" @click="switchMedia = 'video'">{{
|
||||
$lang('video') }}</text>
|
||||
<text :class="{ 'color-base-bg': switchMedia == 'img' }"
|
||||
@click="(switchMedia = 'img'), videoContext.pause()">{{ $lang('image') }}</text>
|
||||
<text :class="{ 'color-base-bg': switchMedia == 'video' }" @click="switchMedia = 'video'">{{ $lang('video') }}</text>
|
||||
<text :class="{ 'color-base-bg': switchMedia == 'img' }" @click="(switchMedia = 'img'), videoContext.pause()">{{ $lang('image') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -48,20 +40,19 @@
|
||||
</view>
|
||||
|
||||
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.isinformation == 0">
|
||||
|
||||
|
||||
<!-- 入口区域 -->
|
||||
<slot name="entrance"></slot>
|
||||
|
||||
<!-- 配送 -->
|
||||
<!-- @click="$refs.deliveryType.open()" -->
|
||||
<view class="item delivery-type" v-if="goodsSkuDetail.is_virtual == 0">
|
||||
<view class="label">{{ $lang('send') }}</view>
|
||||
<!-- @click="$refs.deliveryType.open()" -->
|
||||
<view class="item delivery-type" v-if="goodsSkuDetail.is_virtual == 0" >
|
||||
<view class="label">{{$lang('send')}}</view>
|
||||
<block v-if="deliveryType">
|
||||
<view class="box">
|
||||
<block v-for="(item, index) in deliveryType" :key="index">
|
||||
<text
|
||||
v-if="goodsSkuDetail.support_trade_type.indexOf(index) != -1">{{ $lang('express') }}</text>
|
||||
<!-- {{ item.name }} -->
|
||||
<text v-if="goodsSkuDetail.support_trade_type.indexOf(index) != -1">{{$lang('express')}}</text>
|
||||
<!-- {{ item.name }} -->
|
||||
</block>
|
||||
</view>
|
||||
<text class="iconfont icon-right"></text>
|
||||
@@ -72,7 +63,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 门店 -->
|
||||
<!-- <view class="item store-wrap" @click="openStoreListPopup()" v-if="addonIsExist.store && globalStoreInfo && isShowStore">
|
||||
<!-- <view class="item store-wrap" @click="openStoreListPopup()" v-if="addonIsExist.store && globalStoreInfo && isShowStore">
|
||||
<view class="label">门店</view>
|
||||
<view class="list-wrap">
|
||||
<view class="name-wrap">
|
||||
@@ -89,21 +80,15 @@
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view> -->
|
||||
|
||||
<view class="item service" @click="openMerchantsServicePopup()"
|
||||
v-if="goodsSkuDetail.goods_service.length">
|
||||
<view class="item service" @click="openMerchantsServicePopup()" v-if="goodsSkuDetail.goods_service.length">
|
||||
<view class="label">服务</view>
|
||||
<view class="list-wrap">
|
||||
<view class="item-wrap" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index"
|
||||
v-if="index < 3">
|
||||
<view class="item-wrap" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index" v-if="index < 3">
|
||||
<view class="item-wrap-box">
|
||||
<view class="item-wrap-icon">
|
||||
<text class="iconfont icon-dui"
|
||||
v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
|
||||
<image class="icon-img" v-else-if="item.icon.iconType == 'img'"
|
||||
:src="$util.img(item.icon.imageUrl)" />
|
||||
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'"
|
||||
:icon="item.icon.icon"
|
||||
:value="item.icon.style ? item.icon.style : null"></diy-icon>
|
||||
<text class="iconfont icon-dui" v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
|
||||
<image class="icon-img" v-else-if="item.icon.iconType == 'img'" :src=" $util.img(item.icon.imageUrl)" />
|
||||
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'" :icon="item.icon.icon" :value="item.icon.style ? item.icon.style : null"></diy-icon>
|
||||
</view>
|
||||
<text>{{ item.service_name }}</text>
|
||||
</view>
|
||||
@@ -111,32 +96,30 @@
|
||||
</view>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
|
||||
<!--多规格区域-->
|
||||
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.sku_spec_format">
|
||||
<!-- 入口区域 -->
|
||||
<slot name="skuspec"></slot>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.merch_id > 0">
|
||||
|
||||
<!--多规格区域-->
|
||||
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.sku_spec_format">
|
||||
<!-- 入口区域 -->
|
||||
<slot name="skuspec"></slot>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.merch_id > 0">
|
||||
<!-- 入口区域 -->
|
||||
<slot name="entrance"></slot>
|
||||
<!-- 商家 -->
|
||||
<view class="item store-wrap"
|
||||
@click="$util.redirectTo('/pages_promotion/merch/detail', { merch_id: goodsSkuDetail.merch_id })">
|
||||
<view class="item store-wrap" @click="$util.redirectTo('/pages_promotion/merch/detail', { merch_id: goodsSkuDetail.merch_id })">
|
||||
<view class="list-wrap" style="display: flex;">
|
||||
<view class="name-wrap">
|
||||
<image :src="$util.img(goodsSkuDetail.merchinfo.merch_image)" mode="widthFix"
|
||||
style="width: 100rpx;height: 100rpx;border-radius: 50rpx;"></image>
|
||||
<image :src="$util.img(goodsSkuDetail.merchinfo.merch_image)" mode="widthFix" style="width: 100rpx;height: 100rpx;border-radius: 50rpx;"></image>
|
||||
</view>
|
||||
<view class="other-wrap">
|
||||
<view class="address" style="margin-left: 30rpx;">
|
||||
<view>{{ goodsSkuDetail.merchinfo.merch_name }}</view>
|
||||
<view style="font-size: 24rpx;color: #888;">官方认证商家,值得信赖!</view>
|
||||
</view>
|
||||
<view class="other-wrap">
|
||||
<view class="address" style="margin-left: 30rpx;">
|
||||
<view>{{goodsSkuDetail.merchinfo.merch_name}}</view>
|
||||
<view style="font-size: 24rpx;color: #888;">官方认证商家,值得信赖!</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="iconfont icon-right"></text>
|
||||
@@ -153,8 +136,7 @@
|
||||
</view>
|
||||
<scroll-view scroll-y class="type-body">
|
||||
<block v-for="(item, index) in deliveryType" :key="index">
|
||||
<view class="type-item"
|
||||
:class="{ 'not-support': goodsSkuDetail.support_trade_type.indexOf(index) == -1 }">
|
||||
<view class="type-item" :class="{ 'not-support': goodsSkuDetail.support_trade_type.indexOf(index) == -1 }">
|
||||
<text class="iconfont" :class="item.icon"></text>
|
||||
<view class="content">
|
||||
<view class="title">{{ item.name }}</view>
|
||||
@@ -176,16 +158,11 @@
|
||||
<text class="iconfont icon-close"></text>
|
||||
</view>
|
||||
<scroll-view scroll-y>
|
||||
<view class="item" :class="{ 'empty-desc': !item.desc }"
|
||||
v-for="(item, index) in goodsSkuDetail.goods_service" :key="index">
|
||||
<view class="item-icon" :class="{ 'empty-desc': !item.desc }">
|
||||
<text class="iconfont icon-dui color-base-text"
|
||||
v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
|
||||
<image class="icon-img" v-else-if="item.icon.iconType == 'img'"
|
||||
:src="$util.img(item.icon.imageUrl)" />
|
||||
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'"
|
||||
:icon="item.icon.icon"
|
||||
:value="item.icon.style ? item.icon.style : null"></diy-icon>
|
||||
<view class="item" :class="{ 'empty-desc': !item.desc }" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index">
|
||||
<view class="item-icon" :class="{'empty-desc':!item.desc}">
|
||||
<text class="iconfont icon-dui color-base-text" v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
|
||||
<image class="icon-img" v-else-if="item.icon.iconType == 'img'" :src=" $util.img(item.icon.imageUrl)" />
|
||||
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'" :icon="item.icon.icon" :value="item.icon.style ? item.icon.style : null"></diy-icon>
|
||||
</view>
|
||||
<view class="info-wrap">
|
||||
<text class="title">{{ item.service_name }}</text>
|
||||
@@ -210,19 +187,17 @@
|
||||
</view>
|
||||
<scroll-view scroll-y>
|
||||
<view class="store-list-content">
|
||||
<view class="list-item" v-for="(item, index) in storeList.data" :key="index"
|
||||
@click="selectStore(item)">
|
||||
<view class="list-item" v-for="(item, index) in storeList.data" :key="index" @click="selectStore(item)">
|
||||
<view class="item-box">
|
||||
<view class="item-image">
|
||||
<image :src="$util.img(item.store_image)" v-if="item.store_image" />
|
||||
<image :src="$util.getDefaultImage().store" v-else />
|
||||
<image :src="$util.img(item.store_image)" v-if="item.store_image"/>
|
||||
<image :src="$util.getDefaultImage().store" v-else/>
|
||||
</view>
|
||||
<view class="item-info">
|
||||
<view class="item-title">
|
||||
<text class="title">{{ item.store_name }}</text>
|
||||
<text class="distance color-base-text" v-if="item.distance">
|
||||
距离{{ item.distance > 1 ? item.distance + 'km' : item.distance *
|
||||
1000 + 'm' }}
|
||||
距离{{ item.distance > 1 ? item.distance + 'km' : item.distance * 1000 + 'm' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="item-time" v-if="item.open_date">营业时间:{{ item.open_date }}
|
||||
@@ -253,7 +228,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 促销 -->
|
||||
<!-- <view class="community-model" @touchmove.prevent.stop @click.stop="onCloseCommunity()" v-show="isCommunity">
|
||||
<!-- <view class="community-model" @touchmove.prevent.stop @click.stop="onCloseCommunity()" v-show="isCommunity">
|
||||
<view class="community-model-content" @click.stop>
|
||||
<view class="community-model-content-radius">
|
||||
<view>添加社群</view>
|
||||
@@ -272,8 +247,7 @@
|
||||
<slot name="articipation"></slot>
|
||||
|
||||
<!-- 商品评价 -->
|
||||
<view class="group-wrap" v-if="evaluateConfig.evaluate_show == 1 && goodsSkuDetail.isinformation == 0"
|
||||
style="display: none;">
|
||||
<view class="group-wrap" v-if="evaluateConfig.evaluate_show == 1 && goodsSkuDetail.isinformation == 0" style="display: none;">
|
||||
<view class="goods-evaluate" @click="toEvaluateDetail(goodsSkuDetail.goods_id)">
|
||||
<view class="tit">
|
||||
<!-- <view class="tit" :class="{ active: goodsEvaluate.content }"> -->
|
||||
@@ -294,18 +268,12 @@
|
||||
<view class="evaluator">
|
||||
<view class="evaluator-info">
|
||||
<view class="evaluator-face">
|
||||
<image v-if="item.member_headimg" :src="$util.img(item.member_headimg)"
|
||||
@error="item.member_headimg = $util.getDefaultImage().head"
|
||||
mode="aspectFill" />
|
||||
<image v-else :src="$util.getDefaultImage().head"
|
||||
@error="item.member_headimg = $util.getDefaultImage().head"
|
||||
mode="aspectFill" />
|
||||
<image v-if="item.member_headimg" :src="$util.img(item.member_headimg)" @error="item.member_headimg = $util.getDefaultImage().head" mode="aspectFill" />
|
||||
<image v-else :src="$util.getDefaultImage().head" @error="item.member_headimg = $util.getDefaultImage().head" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="evaluator-name-wrap">
|
||||
<text class="evaluator-name using-hidden"
|
||||
v-if="item.member_name.length > 2 && item.is_anonymous == 1">
|
||||
{{ item.member_name[0] }}***{{ item.member_name[item.member_name.length - 1]
|
||||
}}
|
||||
<text class="evaluator-name using-hidden" v-if="item.member_name.length > 2 && item.is_anonymous == 1">
|
||||
{{ item.member_name[0] }}***{{ item.member_name[item.member_name.length - 1] }}
|
||||
</text>
|
||||
<text class="evaluator-name using-hidden" v-else>{{ item.member_name }}</text>
|
||||
<view v-if="item.scores" class="evaluator-xing">
|
||||
@@ -318,8 +286,7 @@
|
||||
<view class="cont margin-top">{{ item.content }}</view>
|
||||
<scroll-view scroll-x="true">
|
||||
<view class="evaluate-img" v-if="item.images">
|
||||
<view class="img-box" v-for="(img, img_index) in item.images" :key="img_index"
|
||||
@click="previewEvaluate(index, img_index, 'images')">
|
||||
<view class="img-box" v-for="(img, img_index) in item.images" :key="img_index" @click="previewEvaluate(index, img_index, 'images')">
|
||||
<image :src="$util.img(img)" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
@@ -327,9 +294,8 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="goods-attr"
|
||||
v-if="goodsSkuDetail.goods_attr_format && goodsSkuDetail.goods_attr_format.length > 0">
|
||||
|
||||
<view class="goods-attr" v-if="goodsSkuDetail.goods_attr_format && goodsSkuDetail.goods_attr_format.length > 0">
|
||||
<view class="title">规格属性</view>
|
||||
<view class="attr-wrap">
|
||||
<block v-for="(item, index) in goodsSkuDetail.goods_attr_format" :key="index">
|
||||
@@ -338,8 +304,7 @@
|
||||
<text class="value-name">{{ item.attr_value_name }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<view class="attr-action" v-if="goodsSkuDetail.goods_attr_format.length > 4"
|
||||
@click="switchGoodsAttr">
|
||||
<view class="attr-action" v-if="goodsSkuDetail.goods_attr_format.length > 4" @click="switchGoodsAttr">
|
||||
<block v-if="!goodsAttrShow">
|
||||
展开<text class="iconfont icon-iconangledown"></text>
|
||||
</block>
|
||||
@@ -350,25 +315,24 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 详情 -->
|
||||
<view class="goods-detail-tab">
|
||||
<view class="detail-tab">
|
||||
<view class="tab-item">{{ $lang('details') }}</view>
|
||||
<view class="tab-item">{{$lang('details')}}</view>
|
||||
</view>
|
||||
<view class="detail-content active">
|
||||
<view class="detail-content-item">
|
||||
<view class="goods-details" v-if="goodsSkuDetail.goods_content">
|
||||
<!-- <rich-text :nodes="goodsSkuDetail.goods_content" @click="showImg($event)" :data-nodes="goodsSkuDetail.goods_content"></rich-text> -->
|
||||
<!-- {{goodsSkuDetail.goods_content}} -->
|
||||
<mp-html :content="goodsSkuDetail.goods_content" />
|
||||
<!-- :loading="loading" @preview="preview" @navigate="navigate" -->
|
||||
<!-- <rich-text :nodes="goodsSkuDetail.goods_content" @click="showImg($event)" :data-nodes="goodsSkuDetail.goods_content"></rich-text> -->
|
||||
<!-- {{goodsSkuDetail.goods_content}} -->
|
||||
<mp-html :content="goodsSkuDetail.goods_content" />
|
||||
<!-- :loading="loading" @preview="preview" @navigate="navigate" -->
|
||||
</view>
|
||||
<view class="goods-details active" v-else></view>
|
||||
<view class="goods-details" v-if="service && service.is_display == 1 && service.content">
|
||||
<rich-text :nodes="service.content" @click="showImg($event)"
|
||||
:data-nodes="service.content"></rich-text>
|
||||
<rich-text :nodes="service.content" @click="showImg($event)" :data-nodes="service.content"></rich-text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -455,30 +419,37 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 商品详情视图
|
||||
import scroll from '@/common/js/scroll-view.js';
|
||||
import detail from './detail.js';
|
||||
// 商品详情视图
|
||||
import uniPopup from '@/components/uni-popup/uni-popup.vue';
|
||||
import nsGoodsRecommend from '@/components/ns-goods-recommend/ns-goods-recommend.vue';
|
||||
import pengpaiFadeinOut from '@/components/pengpai-fadein-out/pengpai-fadein-out.vue';
|
||||
import xiaoStarComponent from '@/components/xiao-star-component/xiao-star-component.vue';
|
||||
import scroll from '@/common/js/scroll-view.js';
|
||||
import toTop from '@/components/toTop/toTop.vue';
|
||||
import detail from './detail.js';
|
||||
|
||||
import pengpaiFadeinOut from '../pengpai-fadein-out/pengpai-fadein-out.vue';
|
||||
|
||||
export default {
|
||||
name: 'goods-detail-view',
|
||||
props: {
|
||||
goodsSkuDetail: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
export default {
|
||||
name: 'goods-detail-view',
|
||||
props: {
|
||||
goodsSkuDetail: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
pengpaiFadeinOut
|
||||
},
|
||||
mixins: [scroll, detail]
|
||||
};
|
||||
},
|
||||
components: {
|
||||
uniPopup,
|
||||
nsGoodsRecommend,
|
||||
pengpaiFadeinOut,
|
||||
toTop,
|
||||
xiaoStarComponent
|
||||
},
|
||||
mixins: [scroll, detail]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/common/css/goods_detail.scss';
|
||||
@import '@/common/css/goods_detail.scss';
|
||||
</style>
|
||||
<style scoped></style>
|
||||
@@ -1,398 +1,246 @@
|
||||
<template>
|
||||
<view v-if="pageCount == 1 || need" class="fixed-box"
|
||||
:style="[customContainerStyle, {
|
||||
height: containerHeight,
|
||||
backgroundImage: bgUrl ? `url( $ {bgUrl})` : '',
|
||||
backgroundSize: 'cover'
|
||||
}]">
|
||||
<!-- 悬浮按钮 -->
|
||||
<view v-if="pageCount == 1 || need" class="fixed-box"
|
||||
:style="[{ height: fixBtnShow ? '400rpx' : '320rpx' }, customContainerStyle]">
|
||||
<!-- <view class="btn-item" v-if="fixBtnShow" @click="$util.redirectTo('/pages/index/index')"> -->
|
||||
<!-- 切换语言按钮 -->
|
||||
<button class="btn-item" v-if="fixBtnShow && isLanguageSwitchEnabled" @click="toggleLanguage()"
|
||||
:style="[{ backgroundSize: '100% 100%' }, customButtonStyle]">
|
||||
<text :style="customTextStyle">{{ currentLangDisplayName }}</text>
|
||||
</button>
|
||||
<!-- 客服按钮 -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<button class="btn-item" v-if="fixBtnShow" hoverClass="none" openType="contact" sessionFrom="weapp"
|
||||
showMessageCard="true"
|
||||
:style="[{ backgroundImage: 'url(' + (kefuimg ? kefuimg : '') + ')', backgroundSize: '100% 100%' }, customButtonStyle]">
|
||||
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
||||
<!-- <view>首页</view> -->
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<view class="btn-item" v-if="fixBtnShow" @click="call()"
|
||||
:style="[{ backgroundImage: 'url(' + (phoneimg ? phoneimg : '') + ')', backgroundSize: '100% 100%' }, customButtonStyle]">
|
||||
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
|
||||
<!-- <view>我的</view> -->
|
||||
</view>
|
||||
|
||||
<!-- ✅ 统一客服入口(根据后台配置自动适配 AI / 企业微信 / 第三方等) -->
|
||||
<!-- 微信官方客服需要使用 button open-type="contact" -->
|
||||
<button
|
||||
v-if="fixBtnShow && isWeappOfficialKefu"
|
||||
class="btn-item common-bg"
|
||||
open-type="contact"
|
||||
:style="{ backgroundImage: currentKefuImg ? `url( $ {currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||||
>
|
||||
<text class="ai-icon" v-if="!currentKefuImg">🤖</text>
|
||||
</button>
|
||||
<!-- 其他类型客服使用普通 view -->
|
||||
<view
|
||||
v-else-if="fixBtnShow"
|
||||
class="btn-item common-bg"
|
||||
@click="handleUnifiedKefuClick"
|
||||
:style="{ backgroundImage: currentKefuImg ? `url( $ {currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||||
>
|
||||
<text class="ai-icon" v-if="!currentKefuImg">🤖</text>
|
||||
</view>
|
||||
|
||||
<!-- ✅ 新增:小程序系统客服按钮(当附加设置开启时显示) -->
|
||||
<button
|
||||
v-if="fixBtnShow && showWeappSystemKefu"
|
||||
class="btn-item common-bg"
|
||||
open-type="contact"
|
||||
:style="{ backgroundImage: currentKefuImg ? `url( $ {currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||||
>
|
||||
<text class="ai-icon" v-if="!currentKefuImg">💬</text>
|
||||
</button>
|
||||
|
||||
<!-- 中英文切换按钮 -->
|
||||
<view
|
||||
v-if="isLanguageSwitchEnabled && fixBtnShow"
|
||||
class="btn-item common-bg"
|
||||
@click="toggleLanguage"
|
||||
>
|
||||
<text>{{ currentLangDisplayName }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 电话按钮(始终显示) -->
|
||||
<view
|
||||
v-if="fixBtnShow"
|
||||
class="btn-item common-bg"
|
||||
@click="call()"
|
||||
:style="[{ backgroundImage: phoneimg ? `url( $ {phoneimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]"
|
||||
>
|
||||
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<!-- <view class="btn-item icon-xiala" v-if="fixBtnShow" @click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
|
||||
<text class="iconfont icon-unfold"></text>
|
||||
</view>
|
||||
<view class="btn-item switch" v-else :class="{ show: fixBtnShow }"
|
||||
@click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
|
||||
<view class="">快捷</view>
|
||||
<view>导航</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createCustomerService } from '@/common/js/customer-service.js';
|
||||
|
||||
export default {
|
||||
name: 'hover-nav',
|
||||
props: {
|
||||
need: { type: Boolean, default: false }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageCount: 0,
|
||||
fixBtnShow: true,
|
||||
shopInfo: null,
|
||||
currentLangIndex: 0,
|
||||
langIndexMap: {},
|
||||
kefuList: [
|
||||
{ id: 'weixin-official', name: '微信官方客服', isOfficial: true, type: 'weapp' },
|
||||
{ id: 'custom-kefu', name: '自定义在线客服', isOfficial: false, type: 'custom' },
|
||||
{ id: 'qyweixin-kefu', name: '企业微信客服', isOfficial: false, type: 'qyweixin' }
|
||||
],
|
||||
selectedKefu: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
bgUrl() {
|
||||
return this.shopInfo?.bgUrl || '';
|
||||
},
|
||||
aiAgentimg() {
|
||||
return this.shopInfo?.aiAgentimg || '';
|
||||
},
|
||||
kefuimg() {
|
||||
return this.shopInfo?.kefuimg || this. $util.getDefaultImage().kefu;
|
||||
},
|
||||
phoneimg() {
|
||||
return this.shopInfo?.phoneimg || this. $util.getDefaultImage().phone;
|
||||
},
|
||||
tel() {
|
||||
return this.shopInfo?.mobile || '';
|
||||
},
|
||||
isLanguageSwitchEnabled() {
|
||||
return !!this.shopInfo?.ischina;
|
||||
},
|
||||
currentLangDisplayName() {
|
||||
const lang = this.langIndexMap[this.currentLangIndex];
|
||||
return lang === 'zh-cn' ? 'EN' : 'CN';
|
||||
},
|
||||
customContainerStyle() {
|
||||
return this.shopInfo?.floatingButton?.container || {};
|
||||
},
|
||||
customButtonStyle() {
|
||||
return this.shopInfo?.floatingButton?.button || {};
|
||||
},
|
||||
unreadCount() {
|
||||
return this. $store.state.aiUnreadCount || 0;
|
||||
},
|
||||
name: 'hover-nav',
|
||||
props: {
|
||||
need: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageCount: 0,
|
||||
fixBtnShow: true,
|
||||
tel: '',
|
||||
kefuimg: '',
|
||||
phoneimg: '',
|
||||
shopInfo: null, // 店铺信息对象
|
||||
|
||||
// ✅ 新增:根据当前客服类型动态返回图标
|
||||
currentKefuImg() {
|
||||
if (!this.shopInfo) return '';
|
||||
// --- 语言切换相关 ---
|
||||
currentLangIndex: 0, // 当前选中的语言索引
|
||||
langIndexMap: {}, // 语言索引到语言值的映射
|
||||
isLanguageSwitchEnabled: false, // 是否启用语言切换
|
||||
|
||||
const customerService = createCustomerService(this);
|
||||
const config = customerService.getPlatformConfig();
|
||||
// --- 其他 ---
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// 初始化语言设置
|
||||
this.initLanguage();
|
||||
|
||||
if (config?.type === 'aikefu') {
|
||||
return this.aiAgentimg;
|
||||
} else if (config?.type === 'wxwork' || config?.type === 'qyweixin') {
|
||||
// 企业微信客服专用图标
|
||||
return this.aiAgentimg;
|
||||
}
|
||||
// 默认客服图标
|
||||
return this.kefuimg;
|
||||
},
|
||||
// ✅ 新增:判断是否为微信官方客服
|
||||
isWeappOfficialKefu() {
|
||||
if (!this.shopInfo) return false;
|
||||
const customerService = createCustomerService(this);
|
||||
const config = customerService.getPlatformConfig();
|
||||
return config?.type === 'weapp';
|
||||
},
|
||||
// ✅ 新增:判断是否需要同时显示小程序系统客服
|
||||
showWeappSystemKefu() {
|
||||
if (!this.shopInfo) return false;
|
||||
const customerService = createCustomerService(this);
|
||||
const config = customerService.getPlatformConfig();
|
||||
// 检查附加设置是否开启了同时显示小程序系统客服,且当前客服类型不是小程序系统客服
|
||||
return (config?.show_system_service === true || config?.show_system_service === '1') && config?.type !== 'weapp';
|
||||
},
|
||||
//根据显示的按钮数量动态计算容器高度
|
||||
containerHeight() {
|
||||
if (!this.fixBtnShow) return '320rpx';
|
||||
|
||||
let buttonCount = 1;
|
||||
if (this.isLanguageSwitchEnabled) buttonCount++;
|
||||
if (this.showWeappSystemKefu) buttonCount++;
|
||||
buttonCount++;
|
||||
const totalRpx = 94 * buttonCount - 14;
|
||||
const pxValue = Math.round(totalRpx * 0.5);
|
||||
|
||||
return ` $ {pxValue}px`;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
shopInfo: {
|
||||
handler(newVal) {
|
||||
// 可在此添加额外逻辑(如埋点、通知等),当前无需操作
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initLanguage();
|
||||
this.pageCount = getCurrentPages().length;
|
||||
this.kefuimg = this.$util.getDefaultImage().kefu
|
||||
this.phoneimg = this.$util.getDefaultImage().phone
|
||||
this.pageCount = getCurrentPages().length;
|
||||
|
||||
uni.getStorage({
|
||||
key: 'shopInfo',
|
||||
success: (e) => {
|
||||
console.log('【调试】当前 shopInfo:', e.data);
|
||||
this.shopInfo = e.data;
|
||||
},
|
||||
fail: () => {
|
||||
console.warn('未获取到 shopInfo,使用默认设置');
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
initLanguage() {
|
||||
this.langList = this. $langConfig.list();
|
||||
this.langIndexMap = {};
|
||||
for (let i = 0; i < this.langList.length; i++) {
|
||||
this.langIndexMap[i] = this.langList[i].value;
|
||||
}
|
||||
const savedLang = uni.getStorageSync('lang');
|
||||
if (savedLang) {
|
||||
for (let i = 0; i < this.langList.length; i++) {
|
||||
if (this.langList[i].value === savedLang) {
|
||||
this.currentLangIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.currentLangIndex = 0;
|
||||
}
|
||||
},
|
||||
call() {
|
||||
if (this.tel) {
|
||||
uni.makePhoneCall({ phoneNumber: this.tel + '' });
|
||||
} else {
|
||||
uni.showToast({ title: '暂无联系电话', icon: 'none' });
|
||||
}
|
||||
},
|
||||
toggleLanguage() {
|
||||
this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
|
||||
const targetLang = this.langIndexMap[this.currentLangIndex];
|
||||
this. $langConfig.change(targetLang);
|
||||
// 从店铺信息中获取相关信息
|
||||
uni.getStorage({
|
||||
key: 'shopInfo',
|
||||
success: (e) => {
|
||||
console.log(`获取到的shopInfo:${JSON.stringify(e.data)}`)
|
||||
this.shopInfo = e.data;
|
||||
|
||||
if (uni.getSystemInfoSync().platform === 'browser') {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
// 从店铺信息中获取手机号
|
||||
this.tel = e.data.mobile
|
||||
// 从店铺信息中获取是否启用语言切换
|
||||
this.isLanguageSwitchEnabled = e.data.ischina;
|
||||
}
|
||||
})
|
||||
|
||||
// ✅ 核心方法:统一客服入口
|
||||
handleUnifiedKefuClick() {
|
||||
const customerService = createCustomerService(this);
|
||||
const validation = customerService.validateConfig();
|
||||
},
|
||||
computed: {
|
||||
currentLangDisplayName() {
|
||||
// 语言切换按钮显示名称,当前语言为中文时显示EN,否则显示CN
|
||||
// 根据 langIndexMap 获取当前语言值
|
||||
const lang = this.langIndexMap[this.currentLangIndex];
|
||||
return lang == 'zh-cn' ? 'EN' : 'CN';
|
||||
},
|
||||
|
||||
console.log('【客服配置验证】', validation);
|
||||
// 获取容器的自定义样式
|
||||
customContainerStyle() {
|
||||
// 只返回非空的样式属性,确保不覆盖原有的默认样式
|
||||
return this.shopInfo?.floatingButton?.container || {};
|
||||
},
|
||||
|
||||
if (!validation.isValid) {
|
||||
console.error('客服配置无效:', validation.errors);
|
||||
uni.showToast({ title: '客服暂不可用', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
// 获取按钮的自定义样式
|
||||
customButtonStyle() {
|
||||
// 只返回非空的样式属性,确保不覆盖原有的默认样式
|
||||
return this.shopInfo?.floatingButton?.button || {};
|
||||
},
|
||||
|
||||
if (validation.warnings.length > 0) {
|
||||
console.warn('客服配置警告:', validation.warnings);
|
||||
}
|
||||
// 获取文本的自定义样式
|
||||
customTextStyle() {
|
||||
// 只返回非空的样式属性,确保不覆盖原有的默认样式
|
||||
return this.shopInfo?.floatingButton?.text || {};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initLanguage() {
|
||||
// 初始化语言列表
|
||||
this.langList = this.$langConfig.list();
|
||||
|
||||
const platformConfig = customerService.getPlatformConfig();
|
||||
console.log('【当前客服配置】', platformConfig);
|
||||
// 初始化语言索引映射
|
||||
for (let i = 0; i < this.langList.length; i++) {
|
||||
this.langIndexMap[i] = this.langList[i].value;
|
||||
}
|
||||
|
||||
// 检查企业微信配置
|
||||
if (platformConfig.type === 'wxwork') {
|
||||
const wxworkConfig = customerService.getWxworkConfig();
|
||||
console.log('【企业微信配置】', wxworkConfig);
|
||||
// 获取存储的语言设置
|
||||
const savedLang = uni.getStorageSync('lang');
|
||||
if (savedLang) {
|
||||
for (let i = 0; i < this.langList.length; i++) {
|
||||
if (this.langList[i].value == savedLang) {
|
||||
this.currentLangIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.currentLangIndex = 0;
|
||||
}
|
||||
},
|
||||
//拨打电话
|
||||
call() {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: this.tel + ''
|
||||
})
|
||||
},
|
||||
toggleLanguage() {
|
||||
// 切换语言索引
|
||||
this.currentLangIndex = this.currentLangIndex == 0 ? 1 : 0;
|
||||
const targetLang = this.langIndexMap[this.currentLangIndex];
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
if (!wxworkConfig?.enable || !wxworkConfig?.contact_url) {
|
||||
console.warn('企业微信配置不完整,使用原生客服');
|
||||
uni.showToast({ title: '企业微信配置不完整', icon: 'none' });
|
||||
}
|
||||
// #endif
|
||||
// 获取当前页面路由
|
||||
let currentRoute = this.$util.getCurrentRoute().path;
|
||||
// 切换语言并重新加载当前页面
|
||||
this.$langConfig.change(targetLang, currentRoute);
|
||||
|
||||
// #ifdef H5
|
||||
if (!wxworkConfig?.contact_url && !platformConfig.wxwork_url) {
|
||||
console.error('企业微信链接未配置');
|
||||
uni.showToast({ title: '企业微信链接未配置', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 直接调用统一处理方法,由 CustomerService 内部根据配置路由
|
||||
try {
|
||||
customerService.handleCustomerClick({
|
||||
sendMessageTitle: '来自悬浮按钮的咨询',
|
||||
sendMessagePath: '/pages/index/index'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('客服处理失败:', error);
|
||||
uni.showToast({ title: '打开客服失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 以下方法保留用于 actionSheet(如仍需手动选择)
|
||||
openKefuSelectPopup() {
|
||||
const kefuNames = this.kefuList.map(item => item.name);
|
||||
uni.showActionSheet({
|
||||
itemList: kefuNames,
|
||||
success: (res) => {
|
||||
this.selectedKefu = this.kefuList[res.tapIndex];
|
||||
const cs = createCustomerService(this, this.selectedKefu);
|
||||
if (this.selectedKefu.isOfficial) {
|
||||
uni.openCustomerServiceConversation({
|
||||
sessionFrom: 'weapp',
|
||||
showMessageCard: true
|
||||
});
|
||||
} else if (this.selectedKefu.id === 'qyweixin-kefu') {
|
||||
// 处理企业微信客服
|
||||
if (uni.getSystemInfoSync().platform === 'wechat') {
|
||||
// 小程序端:跳转到企业微信客服
|
||||
uni.navigateTo({
|
||||
url: '/pages_tool/qyweixin-kefu/index'
|
||||
});
|
||||
} else {
|
||||
// H5端:跳转到企业微信链接
|
||||
const qyweixinUrl = this.shopInfo.qyweixinUrl; // 后端返回的企业微信链接
|
||||
if (qyweixinUrl) {
|
||||
window.location.href = qyweixinUrl;
|
||||
} else {
|
||||
uni.showToast({ title: '企业微信客服未配置', icon: 'none' });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cs.handleCustomerClick();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss">
|
||||
.container-box {
|
||||
width: 100%;
|
||||
|
||||
.item-wrap {
|
||||
border-radius: 10rpx;
|
||||
|
||||
.image-box {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10rpx;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//悬浮按钮
|
||||
.fixed-box {
|
||||
position: fixed;
|
||||
right: 0rpx;
|
||||
bottom: 240rpx;
|
||||
/* #ifdef H5 */
|
||||
bottom: 320rpx;
|
||||
/* #endif */
|
||||
z-index: 10;
|
||||
border-radius: 120rpx;
|
||||
padding: 20rpx 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 100rpx;
|
||||
box-sizing: border-box;
|
||||
transition: 0.3s;
|
||||
overflow: hidden;
|
||||
}
|
||||
position: fixed;
|
||||
right: 0rpx;
|
||||
bottom: 240rpx;
|
||||
// #ifdef H5
|
||||
bottom: 320rpx;
|
||||
// #endif
|
||||
z-index: 10;
|
||||
// background: #fff;
|
||||
// box-shadow: 2rpx 2rpx 22rpx rgba(0, 0, 0, 0.3);
|
||||
border-radius: 120rpx;
|
||||
padding: 20rpx 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 100rpx;
|
||||
box-sizing: border-box;
|
||||
transition: 0.3s;
|
||||
overflow: hidden;
|
||||
|
||||
.btn-item {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 14rpx 0;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.1);
|
||||
}
|
||||
.btn-item text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.btn-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
flex-direction: column;
|
||||
line-height: 1;
|
||||
margin: 14rpx 0;
|
||||
transition: 0.1s;
|
||||
background: #c6251b;
|
||||
color: #fff;
|
||||
border-radius: 40rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
|
||||
.iconfont,
|
||||
.icox {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 14rpx 0;
|
||||
background: #fff;
|
||||
border-radius: 50rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.iconfont,
|
||||
.icox {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 40rpx;
|
||||
/* 确保图标本身也是圆形 */
|
||||
}
|
||||
|
||||
.iconfont text,
|
||||
.icox text {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
view {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.unread-badge {
|
||||
position: absolute;
|
||||
top: -5rpx;
|
||||
right: -5rpx;
|
||||
background-color: #ff4544;
|
||||
color: white;
|
||||
border-radius: 20rpx;
|
||||
min-width: 30rpx;
|
||||
height: 30rpx;
|
||||
font-size: 20rpx;
|
||||
line-height: 30rpx;
|
||||
text-align: center;
|
||||
padding: 0 8rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(255, 69, 68, 0.3);
|
||||
}
|
||||
&.show {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.ai-icon {
|
||||
font-size: 40rpx;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&.switch {}
|
||||
|
||||
&.icon-xiala {
|
||||
margin: 0;
|
||||
margin-top: 0.1rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -62,6 +62,8 @@
|
||||
// 引入回到顶部组件
|
||||
import MescrollTop from './components/mescroll-top.vue';
|
||||
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue';
|
||||
|
||||
export default {
|
||||
name: 'mescroll-uni',
|
||||
components: {
|
||||
|
||||
@@ -1,120 +1,120 @@
|
||||
<template>
|
||||
<view v-if="advList.length" :class="['container-box',className]">
|
||||
<swiper :indicator-dots="advList.length > 1" indicator-active-color="#ffffff" :autoplay="true" :interval="3000" :duration="1000" v-if="advList.length > 1" @change="changeSwiper" :current="currentIndex" :style="{ height: swiperHeight + 'px' }" class="item-wrap">
|
||||
<swiper-item v-for="(item, index) in advList" :key="index" @click="jumppage(item.adv_url)">
|
||||
<view class="image-box">
|
||||
<image :src="$util.img(item.adv_image)" mode="widthFix" :id="'content-wrap' + index"/>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-else class="container-box item-wrap">
|
||||
<image :src="$util.img(advList[0]['adv_image'])" mode="widthFix" lazy-load="true" @load="imageLoad" @click="jumppage(advList[0].adv_url)"/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-advert',
|
||||
props: {
|
||||
keyword: {
|
||||
type: String
|
||||
},
|
||||
className: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
advList: [],
|
||||
isImage: false,
|
||||
//滑块的高度(单位px)
|
||||
swiperHeight: 150,
|
||||
//当前索引
|
||||
currentIndex: 0,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getAdvList();
|
||||
},
|
||||
methods: {
|
||||
//获取广告位
|
||||
getAdvList() {
|
||||
var item = {
|
||||
adv_image: '',
|
||||
adv_url: ''
|
||||
};
|
||||
this.$api.sendRequest({
|
||||
url: '/api/adv/detail',
|
||||
data: {
|
||||
keyword: this.keyword
|
||||
},
|
||||
success: res => {
|
||||
if (res.code == 0) {
|
||||
var data = res.data.adv_list;
|
||||
for (var index in data) {
|
||||
if (data[index].adv_url) data[index].adv_url = JSON.parse(data[index].adv_url);
|
||||
}
|
||||
this.advList = res.data.adv_list;
|
||||
|
||||
//动态设置swiper的高度
|
||||
this.$nextTick(() => {
|
||||
this.setSwiperHeight();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
jumppage(e) {
|
||||
this.$util.diyRedirectTo(e);
|
||||
},
|
||||
imageLoad(data) {
|
||||
this.isImage = true;
|
||||
},
|
||||
//手动切换题目
|
||||
changeSwiper(e) {
|
||||
this.currentIndex = e.detail.current;
|
||||
//动态设置swiper的高度,使用nextTick延时设置
|
||||
this.$nextTick(() => {
|
||||
this.setSwiperHeight();
|
||||
});
|
||||
},
|
||||
//动态设置swiper的高度
|
||||
setSwiperHeight() {
|
||||
if (this.advList.length > 1) {
|
||||
setTimeout(() => {
|
||||
let element = "#content-wrap" + this.currentIndex;
|
||||
let query = uni.createSelectorQuery().in(this);
|
||||
query.select(element).boundingClientRect();
|
||||
query.exec((res) => {
|
||||
if (res && res[0]) {
|
||||
this.swiperHeight = res[0].height;
|
||||
}
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container-box {
|
||||
width: 100%;
|
||||
|
||||
.item-wrap {
|
||||
border-radius: 10rpx;
|
||||
|
||||
.image-box {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10rpx;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view v-if="advList.length" :class="['container-box',className]">
|
||||
<swiper :indicator-dots="advList.length > 1" indicator-active-color="#ffffff" :autoplay="true" :interval="3000" :duration="1000" v-if="advList.length > 1" @change="changeSwiper" :current="currentIndex" :style="{ height: swiperHeight + 'px' }" class="item-wrap">
|
||||
<swiper-item v-for="(item, index) in advList" :key="index" @click="jumppage(item.adv_url)">
|
||||
<view class="image-box">
|
||||
<image :src="$util.img(item.adv_image)" mode="widthFix" :id="'content-wrap' + index"/>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-else class="container-box item-wrap">
|
||||
<image :src="$util.img(advList[0]['adv_image'])" mode="widthFix" lazy-load="true" @load="imageLoad" @click="jumppage(advList[0].adv_url)"/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-advert',
|
||||
props: {
|
||||
keyword: {
|
||||
type: String
|
||||
},
|
||||
className: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
advList: [],
|
||||
isImage: false,
|
||||
//滑块的高度(单位px)
|
||||
swiperHeight: 150,
|
||||
//当前索引
|
||||
currentIndex: 0,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getAdvList();
|
||||
},
|
||||
methods: {
|
||||
//获取广告位
|
||||
getAdvList() {
|
||||
var item = {
|
||||
adv_image: '',
|
||||
adv_url: ''
|
||||
};
|
||||
this.$api.sendRequest({
|
||||
url: '/api/adv/detail',
|
||||
data: {
|
||||
keyword: this.keyword
|
||||
},
|
||||
success: res => {
|
||||
if (res.code == 0) {
|
||||
var data = res.data.adv_list;
|
||||
for (var index in data) {
|
||||
if (data[index].adv_url) data[index].adv_url = JSON.parse(data[index].adv_url);
|
||||
}
|
||||
this.advList = res.data.adv_list;
|
||||
|
||||
//动态设置swiper的高度
|
||||
this.$nextTick(() => {
|
||||
this.setSwiperHeight();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
jumppage(e) {
|
||||
this.$util.diyRedirectTo(e);
|
||||
},
|
||||
imageLoad(data) {
|
||||
this.isImage = true;
|
||||
},
|
||||
//手动切换题目
|
||||
changeSwiper(e) {
|
||||
this.currentIndex = e.detail.current;
|
||||
//动态设置swiper的高度,使用nextTick延时设置
|
||||
this.$nextTick(() => {
|
||||
this.setSwiperHeight();
|
||||
});
|
||||
},
|
||||
//动态设置swiper的高度
|
||||
setSwiperHeight() {
|
||||
if (this.advList.length > 1) {
|
||||
setTimeout(() => {
|
||||
let element = "#content-wrap" + this.currentIndex;
|
||||
let query = uni.createSelectorQuery().in(this);
|
||||
query.select(element).boundingClientRect();
|
||||
query.exec((res) => {
|
||||
if (res && res[0]) {
|
||||
this.swiperHeight = res[0].height;
|
||||
}
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container-box {
|
||||
width: 100%;
|
||||
|
||||
.item-wrap {
|
||||
border-radius: 10rpx;
|
||||
|
||||
.image-box {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10rpx;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -80,10 +80,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '../uni-popup/uni-popup.vue';
|
||||
|
||||
// 注册奖励弹出层
|
||||
export default {
|
||||
name: 'ns-birthday-gift',
|
||||
components: {
|
||||
uniPopup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
birthday: {
|
||||
@@ -161,7 +165,7 @@
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.register-box ::v-deep .uni-scroll-view {
|
||||
.register-box /deep/ .uni-scroll-view {
|
||||
background: unset !important;
|
||||
}
|
||||
|
||||
@@ -171,11 +175,11 @@
|
||||
/* margin-top:350rpx; */
|
||||
}
|
||||
|
||||
::v-deep .uni-popup__wrapper-box {
|
||||
/deep/ .uni-popup__wrapper-box {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
::v-deep .birthday-title-hint uni-image {
|
||||
/deep/ .birthday-title-hint uni-image {
|
||||
width: 113rpx !important;
|
||||
height: 24rpx !important;
|
||||
}
|
||||
@@ -1,170 +1,171 @@
|
||||
<template>
|
||||
<view class="contact-wrap">
|
||||
<slot></slot>
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<view class="contact-button" @click="contactServicer">
|
||||
<contact-button :tnt-inst-id="config.instid" :scene="config.scene" size="1000rpx"
|
||||
v-if="config.type == 'aliapp'" />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<!-- 微信小程序官方客服按钮 -->
|
||||
<button v-if="useOfficialService" type="default" hover-class="none" open-type="contact"
|
||||
class="contact-button" sessionFrom="weapp" showMessageCard="true"
|
||||
:send-message-title="sendMessageTitle" :send-message-path="sendMessagePath"
|
||||
:send-message-img="sendMessageImg"></button>
|
||||
|
||||
<!-- 微信小程序自定义客服按钮 -->
|
||||
<button v-else type="default" hover-class="none" class="contact-button" @click="contactServicer"></button>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifndef MP-WEIXIN && MP-ALIPAY -->
|
||||
<!-- 其他平台保持原逻辑 -->
|
||||
<button type="default" hover-class="none" :open-type="openType" class="contact-button" @click="contactServicer"
|
||||
:send-message-title="sendMessageTitle" :send-message-path="sendMessagePath"
|
||||
:send-message-img="sendMessageImg" :show-message-card="true"></button>
|
||||
<!-- #endif -->
|
||||
|
||||
<uni-popup ref="servicePopup" type="center">
|
||||
<view class="service-popup-wrap">
|
||||
<view class="head-wrap" @click="$refs.servicePopup.close()">
|
||||
<text>联系客服</text>
|
||||
<text class="iconfont icon-close"></text>
|
||||
</view>
|
||||
<view class="body-wrap">{{ siteInfo.site_tel ? '请联系客服,客服电话是' + siteInfo.site_tel : '抱歉,商家暂无客服,请线下联系' }}
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 客服组件 -->
|
||||
<script>
|
||||
import { createCustomerService } from '@/common/js/customer-service.js';
|
||||
|
||||
export default {
|
||||
name: 'ns-contact',
|
||||
props: {
|
||||
niushop: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
sendMessageTitle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
sendMessagePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
sendMessageImg: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
customerService: null,
|
||||
buttonConfig: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* 是否使用官方客服
|
||||
*/
|
||||
useOfficialService() {
|
||||
if (!this.buttonConfig) return true;
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 如果是微信小程序,检查配置
|
||||
if (this.buttonConfig.type === 'weapp') {
|
||||
// 默认使用官方客服,除非明确设置为false
|
||||
return this.buttonConfig.useOfficial !== false;
|
||||
}
|
||||
// #endif
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* 客服配置
|
||||
*/
|
||||
config() {
|
||||
return this.customerService?.getPlatformConfig() || {};
|
||||
},
|
||||
|
||||
/**
|
||||
* 打开类型
|
||||
*/
|
||||
openType() {
|
||||
return this.buttonConfig?.openType || '';
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 初始化客服服务
|
||||
this.customerService = createCustomerService(this);
|
||||
this.buttonConfig = this.customerService.getButtonConfig();
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 联系客服
|
||||
*/
|
||||
contactServicer() {
|
||||
// 如果是微信/支付宝小程序客服,由系统自动处理
|
||||
if (this.buttonConfig.openType === 'contact') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用统一客服处理
|
||||
this.customerService.handleCustomerClick({
|
||||
niushop: this.niushop,
|
||||
sendMessageTitle: this.sendMessageTitle,
|
||||
sendMessagePath: this.sendMessagePath,
|
||||
sendMessageImg: this.sendMessageImg
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.contact-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
.contact-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.service-popup-wrap {
|
||||
width: 600rpx;
|
||||
|
||||
.head-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 30rpx;
|
||||
height: 90rpx;
|
||||
}
|
||||
|
||||
.body-wrap {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
height: 100rpx;
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view class="contact-wrap">
|
||||
<slot></slot>
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<view class="contact-button" @click="contactServicer">
|
||||
<contact-button :tnt-inst-id="config.instid" :scene="config.scene" size="1000rpx" v-if="config.type == 'aliapp'"/>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-ALIPAY -->
|
||||
<button
|
||||
type="default"
|
||||
hover-class="none"
|
||||
:open-type="openType"
|
||||
class="contact-button"
|
||||
@click="contactServicer"
|
||||
:send-message-title="sendMessageTitle"
|
||||
:send-message-path="sendMessagePath"
|
||||
:send-message-img="sendMessageImg"
|
||||
:show-message-card="true"></button>
|
||||
<!-- #endif -->
|
||||
<uni-popup ref="servicePopup" type="center">
|
||||
<view class="service-popup-wrap">
|
||||
<view class="head-wrap" @click="$refs.servicePopup.close()">
|
||||
<text>联系客服</text>
|
||||
<text class="iconfont icon-close"></text>
|
||||
</view>
|
||||
<view class="body-wrap">{{ siteInfo.site_tel ? '请联系客服,客服电话是' + siteInfo.site_tel : '抱歉,商家暂无客服,请线下联系' }}</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 客服组件 -->
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-contact',
|
||||
props: {
|
||||
niushop: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
sendMessageTitle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
sendMessagePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
sendMessageImg: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
config: null,
|
||||
openType: ''
|
||||
};
|
||||
},
|
||||
created() {
|
||||
if (this.servicerConfig) {
|
||||
// #ifdef H5
|
||||
this.config = this.servicerConfig.h5;
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
this.config = this.servicerConfig.weapp;
|
||||
if (this.config.type == 'weapp') this.openType = 'contact';
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-ALIPAY
|
||||
this.config = this.servicerConfig.aliapp;
|
||||
if (this.config.type == 'aliapp') this.openType = 'contact';
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 联系客服
|
||||
*/
|
||||
contactServicer() {
|
||||
if (this.config.type == 'none') {
|
||||
this.$refs.servicePopup.open();
|
||||
}
|
||||
if (this.openType == 'contact') return;
|
||||
|
||||
switch (this.config.type) {
|
||||
case 'wxwork':
|
||||
// #ifdef H5
|
||||
location.href = this.config.wxwork_url;
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.openCustomerServiceChat({
|
||||
extInfo: { url: this.config.wxwork_url },
|
||||
corpId: this.config.corpid,
|
||||
showMessageCard: true,
|
||||
sendMessageTitle: this.sendMessageTitle,
|
||||
sendMessagePath: this.sendMessagePath,
|
||||
sendMessageImg: this.sendMessageImg
|
||||
});
|
||||
// #endif
|
||||
break;
|
||||
case 'third':
|
||||
location.href = this.config.third_url;
|
||||
break;
|
||||
case 'niushop':
|
||||
this.$util.redirectTo('/pages_tool/chat/room', this.niushop);
|
||||
break;
|
||||
default:
|
||||
this.makePhoneCall();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 店铺联系方式
|
||||
*/
|
||||
makePhoneCall() {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/site/shopcontact',
|
||||
success: res => {
|
||||
if (res.code == 0 && res.data.mobile) uni.makePhoneCall({
|
||||
phoneNumber: res.data
|
||||
.mobile
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.contact-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
.contact-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.service-popup-wrap {
|
||||
width: 600rpx;
|
||||
|
||||
.head-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 30rpx;
|
||||
height: 90rpx;
|
||||
}
|
||||
|
||||
.body-wrap {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
height: 100rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -45,7 +45,7 @@ export default {
|
||||
if (this.emptyBtn.url) {
|
||||
this.$util.redirectTo(this.emptyBtn.url, {}, 'redirectTo');
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
},
|
||||
re(text) {
|
||||
|
||||
@@ -200,8 +200,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pickRegions from '@/components/pick-regions/pick-regions.vue';
|
||||
export default {
|
||||
name: 'ns-form',
|
||||
components: {
|
||||
pickRegions
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
|
||||
@@ -1,96 +1,96 @@
|
||||
<template>
|
||||
<view class="action-buttom-wrap disabled" v-if="disabled" @click="clickEvent">{{ disabledText }}</view>
|
||||
<view class="action-buttom-wrap"
|
||||
:class="[backgroundClass, textPrice ? 'has-second' : '', background ? 'color-join-cart' : 'color-base-bg']"
|
||||
:style="{background:backgroundColor+'!important', 'color':textColor ? textColor : '#ffffff'}" v-else
|
||||
@click="clickEvent">
|
||||
<text class="price-font">{{ textPrice }}</text>
|
||||
<text>{{ text }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-goods-action-button',
|
||||
props: {
|
||||
// 商品底部按钮文字
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 商品底部按钮价格文字
|
||||
textPrice: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 背景色
|
||||
background: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 背景色样式
|
||||
backgroundClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 是否禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 禁用文字提示
|
||||
disabledText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 文字颜色
|
||||
textColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.action-buttom-wrap {
|
||||
flex: 1;
|
||||
height: 70rpx;
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
line-height: 70rpx;
|
||||
border: none;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.has-second {
|
||||
line-height: 50rpx;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.has-second text {
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.action-buttom-wrap:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.disabled {
|
||||
background: $color-disabled;
|
||||
}
|
||||
<template>
|
||||
<view class="action-buttom-wrap disabled" v-if="disabled" @click="clickEvent">{{ disabledText }}</view>
|
||||
<view class="action-buttom-wrap"
|
||||
:class="[backgroundClass, textPrice ? 'has-second' : '', background ? 'color-join-cart' : 'color-base-bg']"
|
||||
:style="{background:backgroundColor+'!important', 'color':textColor ? textColor : '#ffffff'}" v-else
|
||||
@click="clickEvent">
|
||||
<text class="price-font">{{ textPrice }}</text>
|
||||
<text>{{ text }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-goods-action-button',
|
||||
props: {
|
||||
// 商品底部按钮文字
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 商品底部按钮价格文字
|
||||
textPrice: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 背景色
|
||||
background: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 背景色样式
|
||||
backgroundClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 是否禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 禁用文字提示
|
||||
disabledText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 文字颜色
|
||||
textColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.action-buttom-wrap {
|
||||
flex: 1;
|
||||
height: 70rpx;
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
line-height: 70rpx;
|
||||
border: none;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.has-second {
|
||||
line-height: 50rpx;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.has-second text {
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.action-buttom-wrap:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.action-buttom-wrap.disabled {
|
||||
background: $color-disabled;
|
||||
}
|
||||
</style>
|
||||
@@ -20,6 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nsContact from '@/components/ns-contact/ns-contact.vue';
|
||||
export default {
|
||||
name: 'ns-goods-action-icon',
|
||||
props: {
|
||||
@@ -71,6 +72,9 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
components:{
|
||||
nsContact
|
||||
},
|
||||
methods: {
|
||||
clickEvent() {
|
||||
this.$emit('click');
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue';
|
||||
import nsGoodsSkuIndex from '@/components/ns-goods-sku/ns-goods-sku-index.vue';
|
||||
|
||||
// 商品推荐
|
||||
export default {
|
||||
name: 'ns-goods-recommend',
|
||||
components: {
|
||||
nsLoading,
|
||||
nsGoodsSkuIndex
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,233 +2,235 @@
|
||||
<view class="goods-sku">
|
||||
<ns-login ref="login"></ns-login>
|
||||
<!-- sku选择 -->
|
||||
<ns-goods-sku v-if="goodsDetail.goods_id" ref="goodsSku" :goods-id="goodsDetail.goods_id"
|
||||
:goods-detail="goodsDetail" :max-buy="goodsDetail.max_buy" :min-buy="goodsDetail.min_buy"
|
||||
@refresh="refreshGoodsSkuDetail"></ns-goods-sku>
|
||||
<ns-goods-sku v-if="goodsDetail.goods_id" ref="goodsSku" :goods-id="goodsDetail.goods_id" :goods-detail="goodsDetail" :max-buy="goodsDetail.max_buy" :min-buy="goodsDetail.min_buy" @refresh="refreshGoodsSkuDetail"></ns-goods-sku>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 商品SKU
|
||||
export default {
|
||||
name: 'ns-goods-sku-index',
|
||||
data() {
|
||||
return {
|
||||
timeout: {},
|
||||
isRepeat: false,
|
||||
goodsDetail: {}
|
||||
};
|
||||
},
|
||||
created() { },
|
||||
methods: {
|
||||
/**
|
||||
* 添加购物车
|
||||
* @param {Object} config 购物车事件(detail-详情,cart-加入购物车)
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
addCart(config, data, event) {
|
||||
if (!this.storeToken) {
|
||||
this.$refs.login.open(this.$util.INDEX_PAGE_URL);
|
||||
return;
|
||||
}
|
||||
if (config == "detail" || data.is_virtual) {
|
||||
this.$util.redirectTo('/pages_goods/detail', {
|
||||
goods_id: data.goods_id
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// 多规格
|
||||
if (data.goods_spec_format) {
|
||||
this.multiSpecificationGoods(data);
|
||||
} else {
|
||||
this.singleSpecificationGoods(data, event);
|
||||
}
|
||||
import nsGoodsSku from '@/components/ns-goods-sku/ns-goods-sku.vue';
|
||||
// 商品SKU
|
||||
export default {
|
||||
name: 'ns-goods-sku-index',
|
||||
components: {
|
||||
nsGoodsSku
|
||||
},
|
||||
/**
|
||||
* 单规格
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
singleSpecificationGoods(data, event) {
|
||||
let cart =
|
||||
this.cartList['goods_' + data.goods_id] && this.cartList['goods_' + data.goods_id]['sku_' + data
|
||||
.sku_id
|
||||
] ?
|
||||
data() {
|
||||
return {
|
||||
timeout: {},
|
||||
isRepeat: false,
|
||||
goodsDetail: {}
|
||||
};
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
/**
|
||||
* 添加购物车
|
||||
* @param {Object} config 购物车事件(detail-详情,cart-加入购物车)
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
addCart(config, data, event) {
|
||||
if (!this.storeToken) {
|
||||
this.$refs.login.open('/pages/index/index')
|
||||
return;
|
||||
}
|
||||
if (config == "detail" || data.is_virtual) {
|
||||
this.$util.redirectTo('/pages_goods/detail', {
|
||||
goods_id: data.goods_id
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// 多规格
|
||||
if (data.goods_spec_format) {
|
||||
this.multiSpecificationGoods(data);
|
||||
} else {
|
||||
this.singleSpecificationGoods(data, event);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 单规格
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
singleSpecificationGoods(data, event) {
|
||||
let cart =
|
||||
this.cartList['goods_' + data.goods_id] && this.cartList['goods_' + data.goods_id]['sku_' + data
|
||||
.sku_id
|
||||
] ?
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id] :
|
||||
null;
|
||||
|
||||
let cartNum = cart ? cart.num : 0;
|
||||
let api = cart && cart.cart_id ? '/api/cart/edit' : '/api/cart/add';
|
||||
let minBuy = data.min_buy > 0 ? data.min_buy : 1;
|
||||
let num = cartNum >= minBuy ? cartNum : minBuy;
|
||||
let _num = num;
|
||||
if (cart && cart.cart_id) {
|
||||
_num = _num + (data.min_buy > 0 ? data.min_buy : 1)
|
||||
}
|
||||
let cart_id = cart ? cart.cart_id : 0;
|
||||
if (_num > parseInt(data.stock)) {
|
||||
this.$util.showToast({
|
||||
title: '商品库存不足'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (data.is_limit && data.max_buy && _num > parseInt(data.max_buy)) {
|
||||
this.$util.showToast({
|
||||
title: `该商品每人限购${data.max_buy}${data.unit || '件'}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (cart) {
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id].num = _num;
|
||||
} else {
|
||||
|
||||
// 如果商品第一次添加,则初始化数据
|
||||
if (!this.cartList['goods_' + data.goods_id]) {
|
||||
this.cartList['goods_' + data.goods_id] = {};
|
||||
|
||||
let cartNum = cart ? cart.num : 0;
|
||||
let api = cart && cart.cart_id ? '/api/cart/edit' : '/api/cart/add';
|
||||
let minBuy = data.min_buy > 0 ? data.min_buy : 1;
|
||||
let num = cartNum >= minBuy ? cartNum : minBuy;
|
||||
let _num = num;
|
||||
if(cart && cart.cart_id){
|
||||
_num = _num + (data.min_buy > 0 ? data.min_buy : 1)
|
||||
}
|
||||
let cart_id = cart ? cart.cart_id : 0;
|
||||
if (_num > parseInt(data.stock)) {
|
||||
this.$util.showToast({
|
||||
title: '商品库存不足'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (data.is_limit && data.max_buy && _num > parseInt(data.max_buy)) {
|
||||
this.$util.showToast({
|
||||
title: `该商品每人限购${data.max_buy}${data.unit || '件'}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let discount_price = data.discount_price;
|
||||
if (data.member_price > 0 && Number(data.member_price) <= Number(data.discount_price)) {
|
||||
discount_price = data.member_price;
|
||||
}
|
||||
if (cart) {
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id].num = _num;
|
||||
} else {
|
||||
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id] = {
|
||||
cart_id,
|
||||
goods_id: data.goods_id,
|
||||
sku_id: data.sku_id,
|
||||
num: _num,
|
||||
discount_price
|
||||
};
|
||||
}
|
||||
|
||||
if (this.isRepeat) return;
|
||||
this.isRepeat = true;
|
||||
|
||||
this.$emit('addCart', event.currentTarget.id);
|
||||
|
||||
this.$api.sendRequest({
|
||||
url: api,
|
||||
data: {
|
||||
cart_id,
|
||||
sku_id: data.sku_id,
|
||||
num: _num
|
||||
},
|
||||
success: res => {
|
||||
this.isRepeat = false;
|
||||
if (res.code == 0) {
|
||||
if (cart_id == 0) {
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id].cart_id =
|
||||
res.data;
|
||||
}
|
||||
this.$util.showToast({
|
||||
title: "商品添加购物车成功"
|
||||
});
|
||||
this.$store.commit('setCartChange');
|
||||
this.$store.dispatch('cartCalculate');
|
||||
this.$emit("cartListChange", this.cartList);
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
// 如果商品第一次添加,则初始化数据
|
||||
if (!this.cartList['goods_' + data.goods_id]) {
|
||||
this.cartList['goods_' + data.goods_id] = {};
|
||||
}
|
||||
|
||||
let discount_price = data.discount_price;
|
||||
if (data.member_price > 0 && Number(data.member_price) <= Number(data.discount_price)) {
|
||||
discount_price = data.member_price;
|
||||
}
|
||||
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id] = {
|
||||
cart_id,
|
||||
goods_id: data.goods_id,
|
||||
sku_id: data.sku_id,
|
||||
num: _num,
|
||||
discount_price
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 多规格
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
multiSpecificationGoods(data) {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/goodssku/getInfoForCategory',
|
||||
data: {
|
||||
sku_id: data.sku_id
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
let item = res.data;
|
||||
item.unit = item.unit || '件';
|
||||
|
||||
if (item.sku_images) item.sku_images = item.sku_images.split(',');
|
||||
else item.sku_images = [];
|
||||
if (this.isRepeat) return;
|
||||
this.isRepeat = true;
|
||||
|
||||
// 多规格时合并主图
|
||||
if (item.goods_spec_format && item.goods_image) {
|
||||
item.goods_image = item.goods_image.split(',');
|
||||
item.sku_images = item.goods_image.concat(item.sku_images);
|
||||
this.$emit('addCart', event.currentTarget.id);
|
||||
|
||||
this.$api.sendRequest({
|
||||
url: api,
|
||||
data: {
|
||||
cart_id,
|
||||
sku_id: data.sku_id,
|
||||
num: _num
|
||||
},
|
||||
success: res => {
|
||||
this.isRepeat = false;
|
||||
if (res.code == 0) {
|
||||
if (cart_id == 0) {
|
||||
this.cartList['goods_' + data.goods_id]['sku_' + data.sku_id].cart_id =
|
||||
res.data;
|
||||
}
|
||||
this.$util.showToast({
|
||||
title: "商品添加购物车成功"
|
||||
});
|
||||
this.$store.commit('setCartChange');
|
||||
this.$store.dispatch('cartCalculate');
|
||||
this.$emit("cartListChange", this.cartList);
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 多规格
|
||||
* @param {Object} data 商品项
|
||||
*/
|
||||
multiSpecificationGoods(data) {
|
||||
this.$api.sendRequest({
|
||||
url: '/api/goodssku/getInfoForCategory',
|
||||
data: {
|
||||
sku_id: data.sku_id
|
||||
},
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
let item = res.data;
|
||||
item.unit = item.unit || '件';
|
||||
|
||||
// 当前商品SKU规格
|
||||
if (item.sku_spec_format) item.sku_spec_format = JSON.parse(item.sku_spec_format);
|
||||
if (item.sku_images) item.sku_images = item.sku_images.split(',');
|
||||
else item.sku_images = [];
|
||||
|
||||
// 商品SKU格式
|
||||
if (item.goods_spec_format) item.goods_spec_format = JSON.parse(item.goods_spec_format);
|
||||
// 多规格时合并主图
|
||||
if (item.goods_spec_format && item.goods_image) {
|
||||
item.goods_image = item.goods_image.split(',');
|
||||
item.sku_images = item.goods_image.concat(item.sku_images);
|
||||
}
|
||||
|
||||
// 限时折扣
|
||||
if (item.promotion_type == 1) {
|
||||
item.discountTimeMachine = this.$util.countDown(item.end_time - res.timestamp);
|
||||
}
|
||||
// 当前商品SKU规格
|
||||
if (item.sku_spec_format) item.sku_spec_format = JSON.parse(item.sku_spec_format);
|
||||
|
||||
if (item.promotion_type == 1 && item.discountTimeMachine) {
|
||||
if (item.member_price > 0 && Number(item.member_price) <= Number(item.discount_price)) {
|
||||
// 商品SKU格式
|
||||
if (item.goods_spec_format) item.goods_spec_format = JSON.parse(item.goods_spec_format);
|
||||
|
||||
// 限时折扣
|
||||
if (item.promotion_type == 1) {
|
||||
item.discountTimeMachine = this.$util.countDown(item.end_time - res.timestamp);
|
||||
}
|
||||
|
||||
if (item.promotion_type == 1 && item.discountTimeMachine) {
|
||||
if (item.member_price > 0 && Number(item.member_price) <= Number(item.discount_price)) {
|
||||
item.show_price = item.member_price;
|
||||
} else {
|
||||
item.show_price = item.discount_price;
|
||||
}
|
||||
} else if (item.member_price > 0) {
|
||||
item.show_price = item.member_price;
|
||||
} else {
|
||||
item.show_price = item.discount_price;
|
||||
item.show_price = item.price;
|
||||
}
|
||||
} else if (item.member_price > 0) {
|
||||
item.show_price = item.member_price;
|
||||
} else {
|
||||
item.show_price = item.price;
|
||||
}
|
||||
this.goodsDetail = item;
|
||||
this.goodsDetail = item;
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.goodsSku) {
|
||||
this.$refs.goodsSku.show("join_cart", (res) => {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.goodsSku) {
|
||||
this.$refs.goodsSku.show("join_cart", (res) => {
|
||||
|
||||
let goods = this.cartList['goods_' + res.goods_id];
|
||||
let cart = null;
|
||||
if (goods && goods['sku_' + res.sku_id]) {
|
||||
cart = goods['sku_' + res.sku_id];
|
||||
}
|
||||
|
||||
if (cart) {
|
||||
this.cartList['goods_' + res.goods_id]['sku_' + res.sku_id].num = res.num;
|
||||
} else {
|
||||
|
||||
// 如果商品第一次添加,则初始化数据
|
||||
if (!this.cartList['goods_' + res.goods_id]) {
|
||||
this.cartList['goods_' + res.goods_id] = {};
|
||||
let goods = this.cartList['goods_' + res.goods_id];
|
||||
let cart = null;
|
||||
if (goods && goods['sku_' + res.sku_id]) {
|
||||
cart = goods['sku_' + res.sku_id];
|
||||
}
|
||||
|
||||
this.cartList['goods_' + res.goods_id]['sku_' + res.sku_id] = {
|
||||
cart_id: res.cart_id,
|
||||
goods_id: res.goods_id,
|
||||
sku_id: res.sku_id,
|
||||
num: res.num,
|
||||
discount_price: res.discount_price
|
||||
};
|
||||
if (cart) {
|
||||
this.cartList['goods_' + res.goods_id]['sku_' + res.sku_id].num = res.num;
|
||||
} else {
|
||||
|
||||
}
|
||||
// 如果商品第一次添加,则初始化数据
|
||||
if (!this.cartList['goods_' + res.goods_id]) {
|
||||
this.cartList['goods_' + res.goods_id] = {};
|
||||
}
|
||||
|
||||
this.$store.dispatch('cartCalculate');
|
||||
this.$emit("cartListChange", this.cartList);
|
||||
this.cartList['goods_' + res.goods_id]['sku_' + res.sku_id] = {
|
||||
cart_id: res.cart_id,
|
||||
goods_id: res.goods_id,
|
||||
sku_id: res.sku_id,
|
||||
num: res.num,
|
||||
discount_price: res.discount_price
|
||||
};
|
||||
|
||||
// 加入购物车动效
|
||||
setTimeout(() => {
|
||||
this.$store.commit('setCartChange');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
this.$store.dispatch('cartCalculate');
|
||||
this.$emit("cartListChange", this.cartList);
|
||||
|
||||
// 加入购物车动效
|
||||
setTimeout(() => {
|
||||
this.$store.commit('setCartChange');
|
||||
}, 100);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
refreshGoodsSkuDetail(data) {
|
||||
this.goodsDetail = Object.assign({}, this.goodsDetail, data);
|
||||
});
|
||||
},
|
||||
refreshGoodsSkuDetail(data) {
|
||||
this.goodsDetail = Object.assign({}, this.goodsDetail, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view class="goods-sku" @touchmove.prevent.stop>
|
||||
<uni-popup-sku ref="skuPopup" type="bottom" class="sku-layer" @change="popclose">
|
||||
<uni-popup ref="skuPopup" type="bottom" class="sku-layer" @change="popclose">
|
||||
<view class="sku-info" :style="{ height: skuHeight }">
|
||||
<view class="header">
|
||||
<block v-if="type == 'point' && goodsDetail.type && goodsDetail.type != 1">
|
||||
@@ -208,15 +208,19 @@
|
||||
<button type="primary" v-else disabled="true">该商品已下架</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup-sku>
|
||||
</uni-popup>
|
||||
<ns-login ref="login"></ns-login>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '@/components/uni-popup/uni-popup-sku.vue';
|
||||
// 商品SKU
|
||||
export default {
|
||||
name: 'ns-goods-sku',
|
||||
components: {
|
||||
uniPopup
|
||||
},
|
||||
props: {
|
||||
goodsId: {
|
||||
type: [Number, String],
|
||||
@@ -266,7 +270,7 @@
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
this.systemInfo = this.$util.getDeviceInfo();
|
||||
this.systemInfo = uni.getSystemInfoSync();
|
||||
this.isLoad = true;
|
||||
if (this.goodsId && this.goodsDetail.goods_spec_format) {
|
||||
this.skuId = this.goodsDetail.sku_id;
|
||||
@@ -413,7 +417,7 @@
|
||||
this.isLoad = false;
|
||||
if (callback) callback();
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -441,7 +445,7 @@
|
||||
this.skuId = res.data[0].sku_id;
|
||||
this.goodsSkuInfo = obj;
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -467,7 +471,7 @@
|
||||
this.skuId = res.data[0].sku_id;
|
||||
this.goodsSkuInfo = obj;
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -500,7 +504,7 @@
|
||||
this.skuId = res.data[0].sku_id;
|
||||
this.goodsSkuInfo = obj;
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -527,7 +531,7 @@
|
||||
this.skuId = res.data[0].sku_id;
|
||||
this.goodsSkuInfo = obj;
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -553,7 +557,7 @@
|
||||
this.skuId = res.data[0].sku_id;
|
||||
this.goodsSkuInfo = obj;
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -579,7 +583,7 @@
|
||||
this.skuId = res.data[0].sku_id;
|
||||
this.goodsSkuInfo = obj;
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -606,7 +610,7 @@
|
||||
this.skuId = res.data[0].sku_id;
|
||||
this.goodsSkuInfo = obj;
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -630,7 +634,7 @@
|
||||
this.skuId = res.data[0].sku_id;
|
||||
this.goodsSkuInfo = obj;
|
||||
} else {
|
||||
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
|
||||
this.$util.redirectTo('/pages/index/index');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@
|
||||
|
||||
<style lang="scss">
|
||||
.mp-html{
|
||||
::v-deep img{
|
||||
/deep/ img{
|
||||
width:100% !important;
|
||||
display:block;
|
||||
}
|
||||
|
||||
@@ -75,8 +75,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniPopup from '../uni-popup/uni-popup.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
uniPopup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newgift: {
|
||||
@@ -168,17 +172,17 @@
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep .newgift-content uni-image {
|
||||
/deep/ .newgift-content uni-image {
|
||||
width: 113rpx !important;
|
||||
height: 24rpx !important;
|
||||
}
|
||||
|
||||
::v-deep .reward-popup .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
/deep/ .reward-popup .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
max-height: unset !important;
|
||||
overflow-y: unset;
|
||||
}
|
||||
|
||||
.register-box ::v-deep .uni-scroll-view {
|
||||
.register-box /deep/ .uni-scroll-view {
|
||||
background: unset !important;
|
||||
}
|
||||
|
||||
@@ -278,8 +278,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pickRegions from '@/components/pick-regions/pick-regions.vue'
|
||||
|
||||
export default {
|
||||
name: 'ns-form',
|
||||
components: {
|
||||
pickRegions
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user