Compare commits
142 Commits
release/v1
...
merge/tmp-
| Author | SHA1 | Date | |
|---|---|---|---|
| 50908a274b | |||
| 9e68562de5 | |||
| 8e5561c2a7 | |||
| 8d5c543a4f | |||
| cf411407dd | |||
| 86e4be302b | |||
| 2fd06796e1 | |||
| 60c51e551a | |||
| d0d3ac47c6 | |||
| af677f6565 | |||
| f889efeb16 | |||
| d026bb6180 | |||
| 82b856f5d9 | |||
| 7f33b6948a | |||
| 3489b89a0b | |||
| dc4f2769f9 | |||
| 5cf87e4d56 | |||
| c9ca63cff5 | |||
| a6072f4895 | |||
| 38947ddc62 | |||
| cfe83ada38 | |||
| 1e9e0ffea8 | |||
| 28acdfb621 | |||
| ad9f1c495b | |||
| 7c2a7468e7 | |||
| b2051dcf92 | |||
| e3c86de84a | |||
| 6e0eb5d4f3 | |||
| 9d186ff094 | |||
| 8611ec4dc3 | |||
| 89bfd94a07 | |||
| 5cf8b7b467 | |||
| 2cc0162435 | |||
| d8e75a0c9e | |||
| 8af3c0ccb9 | |||
| d8b78168a8 | |||
| 7675e8e04d | |||
| 88d05048a6 | |||
| 28a92c0635 | |||
| b5a47b8b4e | |||
| 4f99e8b5f2 | |||
| 87fc49146c | |||
| 826fcfb024 | |||
| 7174d87b79 | |||
| 4bc747cd9c | |||
| e046868665 | |||
| 19c3ec4f9f | |||
| ffbc15929d | |||
| 524280d816 | |||
| 6e736e0733 | |||
| 4891566793 | |||
| b02f5fbc21 | |||
| 4f5a300afa | |||
| aae6e76797 | |||
| 3162d6a9f2 | |||
| 8010ac45a6 | |||
| baebba4cef | |||
| 1be7155fe8 | |||
| 611c0b930b | |||
| ec1903519d | |||
| b1953a020d | |||
| 3ce26322e0 | |||
| 588ec60948 | |||
| 962ea124fa | |||
| 0ca0fe3b0d | |||
| cef2b6e02e | |||
| e018f9a8b9 | |||
| def8a6cf6f | |||
| 857f295923 | |||
| 50ee885b74 | |||
| 410f248510 | |||
| ba5fcfaab1 | |||
| 5a46bb8d69 | |||
| e33ad16d10 | |||
| d8ba7ace0f | |||
| 875072bb68 | |||
| 0912b9b031 | |||
| 7ffe4acc0f | |||
| 4bcf0cbd2d | |||
| fdf85dfec7 | |||
| 1d62b37060 | |||
| 4ad93ceace | |||
| 294856d9ef | |||
| ba2c7d6d64 | |||
| ec9e76fda7 | |||
| 5dba8071e4 | |||
| 19a53ef414 | |||
| e943b11c8f | |||
| e9db54980e | |||
| 3ddcc665b8 | |||
| a981c02baf | |||
| 1c3f759b35 | |||
| bb58866192 | |||
| 069b3c2c07 | |||
| c6fd13956a | |||
| a489e24988 | |||
| 6897fc631b | |||
| 6d23a64aef | |||
| f34533b0c7 | |||
| 72c74f44f0 | |||
| 7f3d9c0f10 | |||
| 37f95e7267 | |||
| d3c630e860 | |||
| c5b57cedeb | |||
| bf24746a7c | |||
| 5ff2925ba1 | |||
| 3dc81e7f53 | |||
| 0417c5c5ed | |||
| db26a85c8b | |||
| 54c39259a7 | |||
| 15361211b1 | |||
| e301ddc6ec | |||
| a560ad4a5d | |||
| 7f7a18803f | |||
| 42563d7184 | |||
| 14a903f42a | |||
| c9f8614927 | |||
| fe9303bf4c | |||
| e4dfd0ae11 | |||
| 7037d0b083 | |||
| e8a79bd245 | |||
| 047cf765da | |||
| 3a30b0817d | |||
| a464a8731f | |||
| 7599a80943 | |||
| 992a01cc76 | |||
| dd09c66215 | |||
| e2b89c348f | |||
| 475edc93a6 | |||
| cb86cba389 | |||
| 0dc4dec616 | |||
| 2a5214df11 | |||
| 09e410df00 | |||
|
|
75dfe80bde | ||
|
|
2a1f33323c | ||
|
|
b441c46993 | ||
| 38ade75046 | |||
| 1e51abd7cd | |||
| 0939449aa7 | |||
| 29b5cfda6f | |||
| ceca4e5956 | |||
| aa9d2e64d2 |
@@ -41,7 +41,19 @@ const localDevConfig = ({
|
|||||||
'local-2': { // 测试平台
|
'local-2': { // 测试平台
|
||||||
uniacid: 2,
|
uniacid: 2,
|
||||||
domain: 'http://localhost:8050/',
|
domain: 'http://localhost:8050/',
|
||||||
},
|
},
|
||||||
})['2811']; // 选择要使用的环境配置
|
'100': {
|
||||||
|
uniacid: 100,
|
||||||
|
domain: 'https://5g.aigc-quickapp.com/',
|
||||||
|
},
|
||||||
|
'1': {
|
||||||
|
uniacid: 1,
|
||||||
|
domain: 'https://5g.aigc-quickapp.com/',
|
||||||
|
},
|
||||||
|
'115': {
|
||||||
|
uniacid: 115,
|
||||||
|
domain: 'https://5g.aigc-quickapp.com/',
|
||||||
|
},
|
||||||
|
})['1']; // 选择要使用的环境配置
|
||||||
|
|
||||||
export default localDevConfig;
|
export default localDevConfig;
|
||||||
@@ -18,6 +18,10 @@ const localDevConfig = ({
|
|||||||
uniacid: 2811,
|
uniacid: 2811,
|
||||||
domain: 'https://xcx6.aigc-quickapp.com/',
|
domain: 'https://xcx6.aigc-quickapp.com/',
|
||||||
},
|
},
|
||||||
|
'2812': { // IVD数商模式
|
||||||
|
uniacid: 2812,
|
||||||
|
domain: 'https://xcx6.aigc-quickapp.com/',
|
||||||
|
},
|
||||||
'2724': { // 生物菌肥
|
'2724': { // 生物菌肥
|
||||||
uniacid: 2724,
|
uniacid: 2724,
|
||||||
domain: 'https://xcx.aigc-quickapp.com/',
|
domain: 'https://xcx.aigc-quickapp.com/',
|
||||||
@@ -42,6 +46,10 @@ const localDevConfig = ({
|
|||||||
uniacid: 2,
|
uniacid: 2,
|
||||||
domain: 'http://localhost:8050/',
|
domain: 'http://localhost:8050/',
|
||||||
},
|
},
|
||||||
})['2811']; // 选择要使用的环境配置
|
'local-2-dev': { // 本地开发测试平台
|
||||||
|
uniacid: 2,
|
||||||
|
domain: 'http://localhost:8050/',
|
||||||
|
},
|
||||||
|
})['2812']; // 选择要使用的环境配置
|
||||||
|
|
||||||
export default localDevConfig;
|
export default localDevConfig;
|
||||||
@@ -5,6 +5,17 @@ import store from '@/store/index.js'
|
|||||||
let currentConversationId = null;
|
let currentConversationId = null;
|
||||||
const CONVERSATION_KEY = 'ai_conversation_id';
|
const CONVERSATION_KEY = 'ai_conversation_id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取域名配置参数(避免重复代码)
|
||||||
|
*/
|
||||||
|
function getDomainParams() {
|
||||||
|
return {
|
||||||
|
imgDomain: Config.imgDomain,
|
||||||
|
h5Domain: Config.h5Domain,
|
||||||
|
baseUrl: Config.baseUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化时从本地读取会话ID
|
// 初始化时从本地读取会话ID
|
||||||
try {
|
try {
|
||||||
const saved = uni.getStorageSync(CONVERSATION_KEY);
|
const saved = uni.getStorageSync(CONVERSATION_KEY);
|
||||||
@@ -16,12 +27,28 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
/**
|
||||||
|
* 获取uniacid
|
||||||
|
* @returns {number} uniacid
|
||||||
|
*/
|
||||||
|
getUniacid() {
|
||||||
|
return uni.getStorageSync('uniacid') || Config.uniacid; // 从缓存中获取uniacid,或使用默认uniacid
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送普通消息(blocking 模式)
|
* 发送普通消息(blocking 模式)
|
||||||
*/
|
*/
|
||||||
async sendMessage(message, options = {}) {
|
async sendMessage(message, options = {}) {
|
||||||
try {
|
try {
|
||||||
|
// 调试:打印关键状态
|
||||||
|
console.log('[AI Service] sendMessage 开始执行');
|
||||||
|
console.log('[AI Service] store.state.memberInfo:', store.state.memberInfo);
|
||||||
|
console.log('[AI Service] uniacid:', this.getUniacid());
|
||||||
|
console.log('[AI Service] currentConversationId:', this.getConversationId());
|
||||||
|
|
||||||
const aiConfig = store.getters.globalAIKefuConfig;
|
const aiConfig = store.getters.globalAIKefuConfig;
|
||||||
|
console.log('[AI Service] aiConfig:', aiConfig);
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
url: '/api/kefu/chat',
|
url: '/api/kefu/chat',
|
||||||
data: {
|
data: {
|
||||||
@@ -31,28 +58,38 @@ export default {
|
|||||||
query: message,
|
query: message,
|
||||||
response_mode: 'blocking', // 强制 blocking
|
response_mode: 'blocking', // 强制 blocking
|
||||||
user: store.state.memberInfo?.id || 'anonymous',
|
user: store.state.memberInfo?.id || 'anonymous',
|
||||||
conversation_id: this.getConversationId() || ''
|
conversation_id: this.getConversationId() || '',
|
||||||
|
...getDomainParams()
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Sending blocking request to:', params.url);
|
console.log('[AI Service] 发送请求到:', params.url);
|
||||||
console.log('Request data:', params.data);
|
console.log('[AI Service] 请求参数:', JSON.stringify(params.data, null, 2));
|
||||||
|
|
||||||
const response = await http.sendRequest({
|
const response = await http.sendRequest({
|
||||||
...params,
|
...params,
|
||||||
async: false
|
async: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('[AI Service] 收到响应:', response);
|
||||||
|
|
||||||
const result = this.handleResponse(response);
|
const result = this.handleResponse(response);
|
||||||
if (result.conversationId) {
|
if (result.conversationId) {
|
||||||
this.setConversationId(result.conversationId);
|
this.setConversationId(result.conversationId);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Dify API请求失败:', error);
|
console.error('[AI Service] Dify API请求失败,详细错误:', error);
|
||||||
|
console.error('[AI Service] 错误堆栈:', error.stack);
|
||||||
|
// 打印更多信息帮助调试
|
||||||
|
console.error('[AI Service] store 状态:', {
|
||||||
|
memberInfo: store.state.memberInfo,
|
||||||
|
uniacid: this.getUniacid(),
|
||||||
|
token: store.state.token
|
||||||
|
});
|
||||||
throw new Error('AI服务暂时不可用,请稍后重试');
|
throw new Error('AI服务暂时不可用,请稍后重试');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -60,55 +97,112 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* 流式消息入口(自动适配平台)
|
* 流式消息入口(自动适配平台)
|
||||||
*/
|
*/
|
||||||
async sendStreamMessage(message, onChunk, onComplete) {
|
async sendStreamMessage(message, onChunk, onComplete) {
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
// 微信小程序:降级为普通请求 + 前端打字模拟
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
const match = Config.baseUrl.match(/^(?:https?:\/\/|wss?:\/\/)([^\/\s:]+)/);
|
||||||
const result = await this.sendMessage(message);
|
const domain = match ? match[1] : '';
|
||||||
const content = result.content || '';
|
const wssUrl = `wss://${domain}/ws/aikefu`;
|
||||||
const conversationId = result.conversationId || '';
|
console.log(`wssUrl = ${wssUrl}`);
|
||||||
|
const socketTask = wx.connectSocket({
|
||||||
// 保存会话ID(确保连续对话)
|
url: wssUrl,
|
||||||
if (conversationId) {
|
header: {}
|
||||||
this.setConversationId(conversationId);
|
});
|
||||||
}
|
|
||||||
|
let content = '';
|
||||||
// 模拟打字效果
|
let conversationId = '';
|
||||||
let index = 0;
|
let isAuthenticated = false;
|
||||||
const chunkSize = 2; // 每次显示2个字符
|
|
||||||
return new Promise((resolve) => {
|
socketTask.onOpen(() => {
|
||||||
const timer = setInterval(() => {
|
console.log('WebSocket 连接成功,开始认证...');
|
||||||
if (index < content.length) {
|
socketTask.send({
|
||||||
const chunk = content.substring(index, index + chunkSize);
|
data: JSON.stringify({
|
||||||
index += chunkSize;
|
action: 'auth',
|
||||||
if (onChunk) onChunk(chunk);
|
uniacid: this.getUniacid(),
|
||||||
} else {
|
token: store.state.token || 'test_token',
|
||||||
clearInterval(timer);
|
user_id: store.state.memberInfo?.id || 'anonymous'
|
||||||
if (onComplete) {
|
})
|
||||||
onComplete({
|
});
|
||||||
content: content,
|
});
|
||||||
conversation_id: conversationId
|
|
||||||
});
|
socketTask.onMessage((res) => {
|
||||||
}
|
try {
|
||||||
resolve({ content, conversation_id: conversationId });
|
const data = JSON.parse(res.data);
|
||||||
}
|
console.log('收到 WebSocket 消息:', data);
|
||||||
}, 80); // 打字速度:80ms/次
|
|
||||||
});
|
if (data.type === 'auth_success') {
|
||||||
} catch (error) {
|
console.log('认证成功,发送聊天消息...');
|
||||||
console.error('小程序流式消息降级失败:', error);
|
isAuthenticated = true;
|
||||||
if (onComplete) {
|
socketTask.send({
|
||||||
onComplete({ error: error.message || '发送失败' });
|
data: JSON.stringify({
|
||||||
}
|
action: 'chat',
|
||||||
throw error;
|
uniacid: this.getUniacid(),
|
||||||
}
|
query: message,
|
||||||
|
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||||
|
conversation_id: this.getConversationId() || '',
|
||||||
|
...getDomainParams()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} 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.event === 'message') {
|
||||||
|
const text = data.answer || data.content || data.text || '';
|
||||||
|
content += text;
|
||||||
|
if (onChunk) onChunk(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理流结束
|
||||||
|
else if (data.event === '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);
|
||||||
|
});
|
||||||
// #endif
|
// #endif
|
||||||
|
},
|
||||||
// #ifdef H5
|
|
||||||
// H5:使用真实流式(EventSource / Fetch)
|
|
||||||
return this.sendHttpStream(message, onChunk, onComplete);
|
|
||||||
// #endif
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP 流式请求(仅 H5 使用)
|
* HTTP 流式请求(仅 H5 使用)
|
||||||
*/
|
*/
|
||||||
@@ -123,72 +217,85 @@ export default {
|
|||||||
'Accept': 'text/event-stream',
|
'Accept': 'text/event-stream',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
uniacid: store.state.uniacid || '1',
|
uniacid: this.getUniacid(),
|
||||||
|
token: store.state.token || 'test_token',
|
||||||
inputs: {},
|
inputs: {},
|
||||||
query: message,
|
query: message,
|
||||||
response_mode: 'streaming',
|
response_mode: 'streaming',
|
||||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||||
conversation_id: this.getConversationId() || ''
|
conversation_id: this.getConversationId() || '',
|
||||||
|
...getDomainParams()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok || !response.body) {
|
||||||
throw new Error(`HTTP ${response.status}`);
|
throw new Error('无效响应');
|
||||||
}
|
}
|
||||||
if (!response.body) {
|
|
||||||
throw new Error('响应体不可用');
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = response.body.getReader();
|
const reader = response.body.getReader();
|
||||||
const decoder = new TextDecoder('utf-8');
|
const decoder = new TextDecoder('utf-8');
|
||||||
let buffer = '';
|
let buffer = '';
|
||||||
let content = '';
|
let content = '';
|
||||||
let conversationId = '';
|
let conversationId = '';
|
||||||
|
|
||||||
function processBuffer(buf, callback) {
|
while (true) {
|
||||||
const lines = buf.split('\n');
|
const { done, value } = await reader.read();
|
||||||
buf = lines.pop() || '';
|
if (done) break;
|
||||||
|
|
||||||
|
buffer += decoder.decode(value, { stream: true });
|
||||||
|
|
||||||
|
// 按行分割,保留不完整的最后一行
|
||||||
|
const lines = buffer.split('\n');
|
||||||
|
buffer = lines.pop() || ''; // 未完成的行留到下次
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const trimmed = line.trim();
|
const trimmed = line.trim();
|
||||||
if (trimmed.startsWith('data:')) {
|
if (trimmed.startsWith('data:')) {
|
||||||
const jsonStr = trimmed.slice(5).trim();
|
try {
|
||||||
if (jsonStr) {
|
const jsonStr = trimmed.slice(5).trim();
|
||||||
try {
|
if (jsonStr && jsonStr !== '[DONE]') {
|
||||||
const data = JSON.parse(jsonStr);
|
const data = JSON.parse(jsonStr);
|
||||||
if (data.event === 'message') {
|
if (data.event === 'message') {
|
||||||
const text = data.answer || data.text || '';
|
const text = data.answer || data.text || '';
|
||||||
content += text;
|
content += text;
|
||||||
callback(text);
|
if (onChunk) onChunk(text);
|
||||||
}
|
}
|
||||||
if (data.conversation_id) {
|
if (data.conversation_id) {
|
||||||
conversationId = data.conversation_id;
|
conversationId = data.conversation_id;
|
||||||
}
|
}
|
||||||
if (data.event === 'message_end') {
|
if (data.event === 'message_end') {
|
||||||
// 可选:提前完成
|
// 可提前结束
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
console.warn('解析流数据失败:', e);
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('解析失败:', e, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
// 处理最后残留的 buffer(如果有)
|
||||||
const { done, value } = await reader.read();
|
if (buffer.trim().startsWith('data:')) {
|
||||||
if (done) break;
|
try {
|
||||||
buffer += decoder.decode(value, { stream: true });
|
const jsonStr = buffer.trim().slice(5);
|
||||||
buffer = processBuffer(buffer, (chunk) => {
|
if (jsonStr) {
|
||||||
if (onChunk) onChunk(chunk);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onComplete) {
|
if (onComplete) {
|
||||||
onComplete({
|
onComplete({ content, conversation_id: conversationId });
|
||||||
content,
|
|
||||||
conversation_id: conversationId
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return { content, conversation_id: conversationId };
|
return { content, conversation_id: conversationId };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -196,11 +303,6 @@ export default {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
// 理论上不会执行到这里,但防止 fallback
|
|
||||||
return this.sendStreamMessage(message, onChunk, onComplete);
|
|
||||||
// #endif
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,17 +358,19 @@ export default {
|
|||||||
* 生成新会话(如需)
|
* 生成新会话(如需)
|
||||||
*/
|
*/
|
||||||
async generateConversationId() {
|
async generateConversationId() {
|
||||||
const params = {
|
const params = {
|
||||||
url: '/api/kefu/createConversation',
|
url: '/api/kefu/createConversation',
|
||||||
data: {
|
data: {
|
||||||
uniacid: store.state.uniacid,
|
uniacid: this.getUniacid(),
|
||||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
token: store.state.token || 'test_token',
|
||||||
member_id: store.state.memberInfo?.id || '',
|
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||||
},
|
member_id: store.state.memberInfo?.id || '',
|
||||||
header: {
|
...getDomainParams()
|
||||||
'Content-Type': 'application/json'
|
},
|
||||||
}
|
header: {
|
||||||
};
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
};
|
||||||
const response = await http.sendRequest({
|
const response = await http.sendRequest({
|
||||||
...params,
|
...params,
|
||||||
async: false
|
async: false
|
||||||
@@ -284,6 +388,7 @@ export default {
|
|||||||
async: false,
|
async: false,
|
||||||
data: {}
|
data: {}
|
||||||
});
|
});
|
||||||
|
console.log('/api/kefu/health response', response);
|
||||||
const available = [response?.data?.status, response?.data?.components?.ai_service_config?.status]
|
const available = [response?.data?.status, response?.data?.components?.ai_service_config?.status]
|
||||||
.filter(item => item === 'healthy').length > 0;
|
.filter(item => item === 'healthy').length > 0;
|
||||||
return {
|
return {
|
||||||
@@ -305,7 +410,10 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const response = await http.sendRequest({
|
const response = await http.sendRequest({
|
||||||
url: '/api/kefu/clear-conversation',
|
url: '/api/kefu/clear-conversation',
|
||||||
data: { conversation_id: conversationId },
|
data: {
|
||||||
|
conversation_id: conversationId,
|
||||||
|
...getDomainParams()
|
||||||
|
},
|
||||||
async: false
|
async: false
|
||||||
});
|
});
|
||||||
return response.success;
|
return response.success;
|
||||||
@@ -324,13 +432,14 @@ export default {
|
|||||||
throw new Error('会话ID(conversation_id)是必填参数');
|
throw new Error('会话ID(conversation_id)是必填参数');
|
||||||
}
|
}
|
||||||
const requestData = {
|
const requestData = {
|
||||||
uniacid: params.uniacid || store.state.uniacid || '1',
|
uniacid: params.uniacid || this.getUniacid(),
|
||||||
conversation_id: params.conversation_id,
|
conversation_id: params.conversation_id,
|
||||||
user_id: params.user_id || store.state.memberInfo?.id || 'anonymous',
|
user_id: params.user_id || store.state.memberInfo?.id || 'anonymous',
|
||||||
limit: params.limit || 20,
|
limit: params.limit || 20,
|
||||||
offset: params.offset || 0,
|
offset: params.offset || 0,
|
||||||
member_id: params.member_id || store.state.memberInfo?.id || '',
|
member_id: params.member_id || store.state.memberInfo?.id || '',
|
||||||
token: params.token || ''
|
token: params.token || '',
|
||||||
|
...getDomainParams()
|
||||||
};
|
};
|
||||||
const response = await http.sendRequest({
|
const response = await http.sendRequest({
|
||||||
url: '/api/kefu/getHistory',
|
url: '/api/kefu/getHistory',
|
||||||
@@ -369,13 +478,15 @@ export default {
|
|||||||
if (window.currentEventSource) {
|
if (window.currentEventSource) {
|
||||||
window.currentEventSource.close();
|
window.currentEventSource.close();
|
||||||
}
|
}
|
||||||
const params = new URLSearchParams({
|
const paramsObj = {
|
||||||
uniacid: store.state.uniacid || '1',
|
uniacid: this.getUniacid(),
|
||||||
user_id: store.state.memberInfo?.id || '123456',
|
user_id: store.state.memberInfo?.id,
|
||||||
query: message,
|
query: message,
|
||||||
conversation_id: conversationId || '',
|
conversation_id: conversationId || '',
|
||||||
stream: 'true'
|
stream: 'true',
|
||||||
});
|
...getDomainParams()
|
||||||
|
};
|
||||||
|
const params = new URLSearchParams(paramsObj);
|
||||||
const url = `${Config.baseUrl}/api/kefu/chat?${params.toString()}`;
|
const url = `${Config.baseUrl}/api/kefu/chat?${params.toString()}`;
|
||||||
try {
|
try {
|
||||||
const eventSource = new EventSource(url);
|
const eventSource = new EventSource(url);
|
||||||
|
|||||||
@@ -2,68 +2,15 @@
|
|||||||
* 客服统一处理服务
|
* 客服统一处理服务
|
||||||
* 整合各种客服方式,提供统一的调用接口
|
* 整合各种客服方式,提供统一的调用接口
|
||||||
*/
|
*/
|
||||||
class CustomerService {
|
import IMAGE_CONFIG from './image-config.js';
|
||||||
constructor(vueInstance, externalConfig = {}) {
|
|
||||||
if (!vueInstance.$lang) {
|
|
||||||
throw new Error('CustomerService 必须在 Vue 实例中初始化');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export class CustomerService {
|
||||||
|
constructor(vueInstance, externalConfig = null) {
|
||||||
this.vm = vueInstance;
|
this.vm = vueInstance;
|
||||||
this.externalConfig = externalConfig; // 外部传入的最新配置(优先级最高)
|
this.externalConfig = externalConfig; // 外部传入的最新配置(优先级最高)
|
||||||
this.latestPlatformConfig = null;
|
this.latestPlatformConfig = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSupoortKeFuList() {
|
|
||||||
if (!this.vm) return [];
|
|
||||||
|
|
||||||
const vm = this.vm;
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: 'weixin-official',
|
|
||||||
name: vm.$lang('customer.weChatKefu'),
|
|
||||||
isOfficial: true,
|
|
||||||
type: 'weapp'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'custom-kefu',
|
|
||||||
name: vm.$lang('customer.systemKefu'),
|
|
||||||
isOfficial: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'qyweixin-kefu',
|
|
||||||
name: vm.$lang('customer.weChatWorkKefu'),
|
|
||||||
isOfficial: false
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开客服选择弹窗
|
|
||||||
*/
|
|
||||||
openCustomerSelectPopupDialog() {
|
|
||||||
const kefu_list = this.getSupoortKeFuList();
|
|
||||||
const kefuNames = kefu_list.map(item => item.name);
|
|
||||||
|
|
||||||
uni.showActionSheet({
|
|
||||||
itemList: kefuNames,
|
|
||||||
success: (res) => {
|
|
||||||
const kefu = kefu_list[res.tapIndex];
|
|
||||||
this.externalConfig = kefu ?? this.externalConfig ?? {};
|
|
||||||
if (kefu.isOfficial) {
|
|
||||||
uni.openCustomerServiceConversation({
|
|
||||||
sessionFrom: 'weapp',
|
|
||||||
showMessageCard: true
|
|
||||||
});
|
|
||||||
} else if (kefu.id === 'custom-kefu') {
|
|
||||||
this.handleCustomerClick();
|
|
||||||
} else if (kefu.id === 'qyweixin-kefu') {
|
|
||||||
this.handleQyWeixinKefuClick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 强制刷新配置(支持传入外部配置)
|
* 强制刷新配置(支持传入外部配置)
|
||||||
* @param {Object} externalConfig 外部最新配置
|
* @param {Object} externalConfig 外部最新配置
|
||||||
@@ -83,28 +30,29 @@ class CustomerService {
|
|||||||
return this.latestPlatformConfig;
|
return this.latestPlatformConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 优先级:外部传入的最新配置 > vuex配置 > 空对象
|
// 优先级:外部传入 > vuex store > 空对象
|
||||||
const servicerConfig = this.externalConfig || this.vm.$store.state.servicerConfig || {};
|
const servicerConfig = this.externalConfig || this.vm.$store.state.servicerConfig || {};
|
||||||
console.log(`【实时客服配置】`, servicerConfig);
|
console.log(`【实时客服配置】`, servicerConfig);
|
||||||
|
|
||||||
let platformConfig = null;
|
let platformConfig = null;
|
||||||
|
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
platformConfig = servicerConfig.h5 ? (typeof servicerConfig.h5 === 'object' ? servicerConfig.h5 : null) : null;
|
platformConfig = servicerConfig.h5 && typeof servicerConfig.h5 === 'object' ? servicerConfig.h5 : null;
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
platformConfig = servicerConfig.weapp ? (typeof servicerConfig.weapp === 'object' ? servicerConfig.weapp : null) : null;
|
platformConfig = servicerConfig.weapp && typeof servicerConfig.weapp === 'object' ? servicerConfig.weapp : null;
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef MP-ALIPAY
|
// #ifdef MP-ALIPAY
|
||||||
platformConfig = servicerConfig.aliapp ? (typeof servicerConfig.aliapp === 'object' ? servicerConfig.aliapp : null) : null;
|
platformConfig = servicerConfig.aliapp && typeof servicerConfig.aliapp === 'object' ? servicerConfig.aliapp : null;
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef PC
|
// #ifdef PC
|
||||||
platformConfig = servicerConfig.pc ? (typeof servicerConfig.pc === 'object' ? servicerConfig.pc : null) : null;
|
platformConfig = servicerConfig.pc && typeof servicerConfig.pc === 'object' ? servicerConfig.pc : null;
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// 处理空数组情况(你的配置中pc/aliapp是空数组,转为null)
|
// 防止空数组被当作有效配置
|
||||||
if (Array.isArray(platformConfig)) {
|
if (Array.isArray(platformConfig)) {
|
||||||
platformConfig = null;
|
platformConfig = null;
|
||||||
}
|
}
|
||||||
@@ -130,6 +78,15 @@ class CustomerService {
|
|||||||
return config && typeof config === 'object' && config.type;
|
return config && typeof config === 'object' && config.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否有有效的客服配置(用于判断是否显示客服按钮)
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
hasValidKefuConfig() {
|
||||||
|
const config = this.getPlatformConfig();
|
||||||
|
return config && typeof config === 'object' && config.type && config.type !== 'none';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证客服配置完整性
|
* 验证客服配置完整性
|
||||||
* @returns {Object} 验证结果
|
* @returns {Object} 验证结果
|
||||||
@@ -144,32 +101,18 @@ class CustomerService {
|
|||||||
warnings: []
|
warnings: []
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!config) {
|
if (!config || !config.type) {
|
||||||
result.isValid = false;
|
|
||||||
result.errors.push('客服配置不存在');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.type === 'aikefu') {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.type) {
|
|
||||||
result.isValid = false;
|
result.isValid = false;
|
||||||
result.errors.push('客服类型未配置');
|
result.errors.push('客服类型未配置');
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.type === 'wxwork') {
|
if (config.type === 'wxwork') {
|
||||||
if (!wxworkConfig) {
|
if (!wxworkConfig || !wxworkConfig.enable) {
|
||||||
result.isValid = false;
|
result.warnings.push('企业微信未启用');
|
||||||
result.errors.push('企业微信配置不存在');
|
}
|
||||||
} else {
|
if (!wxworkConfig.contact_url) {
|
||||||
if (!wxworkConfig.enable) {
|
result.warnings.push('企业微信活码链接未配置');
|
||||||
result.warnings.push('企业微信功能未启用');
|
|
||||||
}
|
|
||||||
if (!wxworkConfig.contact_url) {
|
|
||||||
result.warnings.push('企业微信活码链接未配置,将使用原有客服方式');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,16 +120,39 @@ class CustomerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跳转到AI客服页面
|
* 跳转到 AI 客服页面(Dify)
|
||||||
*/
|
*/
|
||||||
openAIKeFuService() {
|
openDifyService() {
|
||||||
const vm = this.vm;
|
try {
|
||||||
vm.$util.redirectTo(vm.$util.AI_CHAT_PAGE_URL);
|
// 清除未读数(如果存在)
|
||||||
|
if (typeof this.vm.setAiUnreadCount === 'function') {
|
||||||
|
this.vm.setAiUnreadCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 修正路径:必须与 pages.json 中注册的路径一致
|
||||||
|
const aiChatUrl = '/pages_tool/ai-chat/index';
|
||||||
|
|
||||||
|
// ✅ 使用 navigateTo 保留返回栈(体验更好)
|
||||||
|
uni.navigateTo({
|
||||||
|
url: aiChatUrl,
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('跳转 AI 客服失败:', err);
|
||||||
|
// H5 兜底
|
||||||
|
// #ifdef H5
|
||||||
|
window.location.href = aiChatUrl;
|
||||||
|
// #endif
|
||||||
|
uni.showToast({ title: '打开客服失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('跳转 AI 客服异常:', e);
|
||||||
|
uni.showToast({ title: '打开客服失败', icon: 'none' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理客服点击事件
|
* 处理客服点击事件(统一入口)
|
||||||
* @param {Object} options 选项参数
|
* @param {Object} options 选项参数(用于消息卡片等)
|
||||||
*/
|
*/
|
||||||
handleCustomerClick(options = {}) {
|
handleCustomerClick(options = {}) {
|
||||||
const validation = this.validateConfig();
|
const validation = this.validateConfig();
|
||||||
@@ -201,51 +167,61 @@ class CustomerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config = this.getPlatformConfig();
|
const config = this.getPlatformConfig();
|
||||||
const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
|
console.log('【当前客服配置】', config);
|
||||||
|
console.log('【客服类型】', config.type);
|
||||||
|
|
||||||
|
const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
|
||||||
|
|
||||||
if (config.type === 'none') {
|
if (config.type === 'none') {
|
||||||
this.showNoServicePopup();
|
this.showNoServicePopup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 核心分支:根据最新的type处理
|
// 核心路由:根据 type 决定行为
|
||||||
switch (config.type) {
|
switch (config.type) {
|
||||||
case 'aikefu':
|
case 'aikefu':
|
||||||
this.openAIKeFuService();
|
console.log('【跳转 AI 客服】目标路径: /pages_tool/ai-chat/index');
|
||||||
|
this.openDifyService();
|
||||||
break;
|
break;
|
||||||
case 'wxwork':
|
case 'wxwork':
|
||||||
|
console.log('【跳转企业微信客服】');
|
||||||
this.openWxworkService(false, config, options);
|
this.openWxworkService(false, config, options);
|
||||||
break;
|
break;
|
||||||
case 'third':
|
case 'third':
|
||||||
|
console.log('【跳转第三方客服】');
|
||||||
|
this.openThirdService(config);
|
||||||
|
break;
|
||||||
|
case 'miniprogram':
|
||||||
|
console.log('【跳转第三方小程序客服】');
|
||||||
this.openThirdService(config);
|
this.openThirdService(config);
|
||||||
break;
|
break;
|
||||||
case 'niushop':
|
case 'niushop':
|
||||||
|
console.log('【跳转牛商客服】');
|
||||||
this.openNiushopService(niushop);
|
this.openNiushopService(niushop);
|
||||||
break;
|
break;
|
||||||
case 'weapp':
|
case 'weapp':
|
||||||
|
console.log('【跳转微信官方客服】');
|
||||||
this.openWeappService(config, options);
|
this.openWeappService(config, options);
|
||||||
break;
|
break;
|
||||||
case 'aliapp':
|
case 'aliapp':
|
||||||
|
console.log('【跳转支付宝客服】');
|
||||||
this.openAliappService(config);
|
this.openAliappService(config);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
console.error('【未知客服类型】', config.type);
|
||||||
this.makePhoneCall();
|
this.makePhoneCall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ================== 各类型客服实现 ==================
|
||||||
* 打开企业微信客服
|
|
||||||
* @param {boolean} useOriginalService 是否使用原有客服方式
|
|
||||||
* @param {Object} servicerConfig 客服配置
|
|
||||||
* @param {Object} options 选项参数
|
|
||||||
*/
|
|
||||||
openWxworkService(useOriginalService = false, servicerConfig = null, options = {}) {
|
openWxworkService(useOriginalService = false, servicerConfig = null, options = {}) {
|
||||||
const config = servicerConfig || this.getPlatformConfig();
|
const config = servicerConfig || this.getPlatformConfig();
|
||||||
const wxworkConfig = this.getWxworkConfig();
|
const wxworkConfig = this.getWxworkConfig();
|
||||||
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
|
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
if (wxworkConfig?.enable && wxworkConfig?.contact_url && !useOriginalService) {
|
if (!useOriginalService && wxworkConfig?.enable && wxworkConfig?.contact_url) {
|
||||||
wx.navigateToMiniProgram({
|
wx.navigateToMiniProgram({
|
||||||
appId: 'wxeb490c6f9b154ef9',
|
appId: 'wxeb490c6f9b154ef9',
|
||||||
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig.contact_url)}`,
|
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig.contact_url)}`,
|
||||||
@@ -256,9 +232,16 @@ class CustomerService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// 检查是否有企业微信配置
|
||||||
|
if (!config.wxwork_url && !config.corpid) {
|
||||||
|
console.error('企业微信配置不完整,缺少 wxwork_url 或 corpid');
|
||||||
|
uni.showToast({ title: '企业微信配置不完整', icon: 'none' });
|
||||||
|
this.fallbackToPhoneCall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
wx.openCustomerServiceChat({
|
wx.openCustomerServiceChat({
|
||||||
extInfo: { url: config.wxwork_url },
|
extInfo: { url: config.wxwork_url || '' },
|
||||||
corpId: config.corpid,
|
corpId: config.corpid || '',
|
||||||
showMessageCard: true,
|
showMessageCard: true,
|
||||||
sendMessageTitle,
|
sendMessageTitle,
|
||||||
sendMessagePath,
|
sendMessagePath,
|
||||||
@@ -268,227 +251,181 @@ class CustomerService {
|
|||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
if (wxworkConfig?.enable && wxworkConfig?.contact_url) {
|
if (!useOriginalService && wxworkConfig?.enable && wxworkConfig?.contact_url) {
|
||||||
window.location.href = wxworkConfig.contact_url;
|
window.location.href = wxworkConfig.contact_url;
|
||||||
} else if (config.wxwork_url) {
|
} else if (config.wxwork_url) {
|
||||||
location.href = config.wxwork_url;
|
window.location.href = config.wxwork_url;
|
||||||
} else {
|
} else {
|
||||||
this.fallbackToPhoneCall();
|
this.fallbackToPhoneCall();
|
||||||
}
|
}
|
||||||
// #endif
|
// #endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开第三方客服
|
|
||||||
* @param {Object} config 客服配置
|
|
||||||
*/
|
|
||||||
openThirdService(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) {
|
if (config.third_url) {
|
||||||
|
console.log('【跳转第三方链接】', config.third_url);
|
||||||
|
// #ifdef H5
|
||||||
window.location.href = config.third_url;
|
window.location.href = config.third_url;
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.setClipboardData({
|
||||||
|
data: config.third_url,
|
||||||
|
success: () => {
|
||||||
|
uni.showToast({ title: '链接已复制,请在浏览器打开', icon: 'none' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
} else {
|
} else {
|
||||||
|
console.error('【第三方客服配置不完整】缺少 mini_app_id 或 third_url');
|
||||||
this.fallbackToPhoneCall();
|
this.fallbackToPhoneCall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开牛商客服
|
|
||||||
* @param {Object} niushop 牛商参数
|
|
||||||
*/
|
|
||||||
openNiushopService(niushop) {
|
openNiushopService(niushop) {
|
||||||
if (Object.keys(niushop).length > 0) {
|
if (Object.keys(niushop).length > 0 && this.vm.$util?.redirectTo) {
|
||||||
this.vm.$util.redirectTo('/pages_tool/chat/room', niushop);
|
this.vm.$util.redirectTo('/pages_tool/chat/room', niushop);
|
||||||
} else {
|
} else {
|
||||||
this.makePhoneCall();
|
this.makePhoneCall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开微信小程序客服
|
|
||||||
* @param {Object} config 客服配置
|
|
||||||
* @param {Object} options 选项参数
|
|
||||||
*/
|
|
||||||
openWeappService(config, options = {}) {
|
openWeappService(config, options = {}) {
|
||||||
if (!this.shouldUseCustomService(config)) {
|
// 如果 useOfficial 为 true 或 undefined,则使用原生系统客服(由 button open-type="contact" 触发)
|
||||||
console.log('使用官方微信小程序客服');
|
// 此方法仅用于自定义跳转(如 useOfficial: false)
|
||||||
|
if (config.useOfficial !== false) {
|
||||||
|
// 不做任何事,应由 <button open-type="contact"> 触发
|
||||||
|
console.log('使用微信官方客服,请确保按钮为 <button open-type="contact">');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('使用自定义微信小程序客服');
|
|
||||||
this.handleCustomWeappService(config, options);
|
this.handleCustomWeappService(config, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理自定义微信小程序客服
|
|
||||||
* @param {Object} config 客服配置
|
|
||||||
* @param {Object} options 选项参数
|
|
||||||
*/
|
|
||||||
handleCustomWeappService(config, options = {}) {
|
handleCustomWeappService(config, options = {}) {
|
||||||
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
|
|
||||||
|
|
||||||
if (config.customServiceUrl) {
|
if (config.customServiceUrl) {
|
||||||
let url = config.customServiceUrl;
|
let url = config.customServiceUrl;
|
||||||
const params = [];
|
const params = [];
|
||||||
|
const { sendMessageTitle, sendMessagePath, sendMessageImg } = options;
|
||||||
if (sendMessageTitle) params.push(`title=${encodeURIComponent(sendMessageTitle)}`);
|
if (sendMessageTitle) params.push(`title=${encodeURIComponent(sendMessageTitle)}`);
|
||||||
if (sendMessagePath) params.push(`path=${encodeURIComponent(sendMessagePath)}`);
|
if (sendMessagePath) params.push(`path=${encodeURIComponent(sendMessagePath)}`);
|
||||||
if (sendMessageImg) params.push(`img=${encodeURIComponent(sendMessageImg)}`);
|
if (sendMessageImg) params.push(`img=${encodeURIComponent(sendMessageImg)}`);
|
||||||
|
|
||||||
if (params.length > 0) {
|
if (params.length > 0) {
|
||||||
url += (url.includes('?') ? '&' : '?') + params.join('&');
|
url += (url.includes('?') ? '&' : '?') + params.join('&');
|
||||||
}
|
}
|
||||||
|
uni.navigateTo({ url });
|
||||||
uni.navigateTo({
|
|
||||||
url: url,
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('跳转自定义客服页面失败:', err);
|
|
||||||
this.tryThirdPartyService(config, options);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tryThirdPartyService(config, options);
|
this.tryThirdPartyService(config, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 尝试使用第三方客服
|
|
||||||
* @param {Object} config 客服配置
|
|
||||||
* @param {Object} options 选项参数
|
|
||||||
*/
|
|
||||||
tryThirdPartyService(config, options = {}) {
|
tryThirdPartyService(config, options = {}) {
|
||||||
if (config.thirdPartyServiceUrl) {
|
// 支持第三方微信小程序客服
|
||||||
// #ifdef H5
|
if (config.thirdPartyMiniAppId || config.mini_app_id) {
|
||||||
window.open(config.thirdPartyServiceUrl, '_blank');
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
if (config.thirdPartyMiniAppId) {
|
wx.navigateToMiniProgram({
|
||||||
wx.navigateToMiniProgram({
|
appId: config.thirdPartyMiniAppId || config.mini_app_id,
|
||||||
appId: config.thirdPartyMiniAppId,
|
path: config.thirdPartyMiniAppPath || config.mini_app_path || ''
|
||||||
path: config.thirdPartyMiniAppPath || '',
|
});
|
||||||
fail: (err) => {
|
|
||||||
console.error('跳转第三方小程序失败:', err);
|
|
||||||
this.fallbackToPhoneCall();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
uni.setClipboardData({
|
|
||||||
data: config.thirdPartyServiceUrl,
|
|
||||||
success: () => {
|
|
||||||
uni.showModal({
|
|
||||||
title: '客服链接已复制',
|
|
||||||
content: '客服链接已复制到剪贴板,请在浏览器中粘贴访问',
|
|
||||||
showCancel: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// #endif
|
// #endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 支持第三方链接客服
|
||||||
|
if (config.thirdPartyServiceUrl || config.third_url) {
|
||||||
|
const serviceUrl = config.thirdPartyServiceUrl || config.third_url;
|
||||||
|
// #ifdef H5
|
||||||
|
window.open(serviceUrl, '_blank');
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.setClipboardData({ data: serviceUrl });
|
||||||
|
uni.showToast({ title: '客服链接已复制', icon: 'none' });
|
||||||
|
// #endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.fallbackToPhoneCall();
|
this.fallbackToPhoneCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 降级到电话客服
|
|
||||||
*/
|
|
||||||
fallbackToPhoneCall() {
|
|
||||||
uni.showModal({
|
|
||||||
title: '联系客服',
|
|
||||||
content: '在线客服暂时不可用,是否拨打电话联系客服?',
|
|
||||||
success: (res) => {
|
|
||||||
if (res.confirm) {
|
|
||||||
this.makePhoneCall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开支付宝小程序客服
|
|
||||||
* @param {Object} config 客服配置
|
|
||||||
*/
|
|
||||||
openAliappService(config) {
|
openAliappService(config) {
|
||||||
console.log('支付宝小程序客服', config);
|
if (config.type === 'aikefu') {
|
||||||
switch (config.type) {
|
this.openDifyService();
|
||||||
case 'aikefu':
|
} else if (config.type === 'third') {
|
||||||
this.openAIKeFuService();
|
this.openThirdService(config);
|
||||||
break;
|
} else {
|
||||||
case 'third':
|
// 支付宝原生客服由 button open-type="contact" 触发,此处不处理
|
||||||
this.openThirdService(config);
|
console.log('使用支付宝官方客服');
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.log('使用支付宝官方客服');
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ================== 辅助方法 ==================
|
||||||
* 拨打电话
|
|
||||||
*/
|
|
||||||
makePhoneCall(mobileNumber) {
|
|
||||||
if (mobileNumber) {
|
|
||||||
return uni.makePhoneCall({
|
|
||||||
phoneNumber: mobileNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从缓存中获取电话信息
|
makePhoneCall() {
|
||||||
uni.getStorage({
|
this.vm.$api.sendRequest({
|
||||||
key: 'shopInfo',
|
url: '/api/site/shopcontact',
|
||||||
success: (res) => {
|
success: res => {
|
||||||
const shopInfo = res.data;
|
if (res.code === 0 && res.data?.mobile) {
|
||||||
const mobile = shopInfo?.mobile ?? '';
|
uni.makePhoneCall({ phoneNumber: res.data.mobile });
|
||||||
if (mobile) {
|
|
||||||
uni.makePhoneCall({
|
|
||||||
phoneNumber: mobile
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({ title: '暂无客服电话', icon: 'none' });
|
||||||
title: '暂无客服电话',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
uni.showToast({ title: '获取客服电话失败', icon: 'none' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示无客服弹窗
|
|
||||||
*/
|
|
||||||
showNoServicePopup() {
|
showNoServicePopup() {
|
||||||
const siteInfo = this.vm.$store.state.siteInfo || {};
|
const siteInfo = this.vm.$store.state.siteInfo || {};
|
||||||
const message = siteInfo?.site_tel
|
const message = siteInfo?.site_tel
|
||||||
? `请联系客服,客服电话是${siteInfo.site_tel}`
|
? `请联系客服,客服电话是 ${siteInfo.site_tel}`
|
||||||
: '抱歉,商家暂无客服,请线下联系';
|
: '抱歉,商家暂无客服,请线下联系';
|
||||||
|
uni.showModal({ title: '联系客服', content: message, showCancel: false });
|
||||||
uni.showModal({
|
|
||||||
title: '联系客服',
|
|
||||||
content: message,
|
|
||||||
showCancel: false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示配置错误弹窗
|
|
||||||
* @param {Array} errors 错误列表
|
|
||||||
*/
|
|
||||||
showConfigErrorPopup(errors) {
|
showConfigErrorPopup(errors) {
|
||||||
const message = errors.join('\n');
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '配置错误',
|
title: '客服配置错误',
|
||||||
content: `客服配置有误:\n${message}`,
|
content: `配置有误:\n${errors.join('\n')}`,
|
||||||
showCancel: false
|
showCancel: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 降级处理:使用原有客服方式
|
|
||||||
*/
|
|
||||||
fallbackToOriginalService() {
|
fallbackToOriginalService() {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
content: '无法直接添加企业微信客服,是否使用其他方式联系客服?',
|
content: '无法直接添加企业微信,是否使用其他方式联系客服?',
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
this.openWxworkService(true);
|
this.openWxworkService(true);
|
||||||
@@ -497,9 +434,19 @@ class CustomerService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fallbackToPhoneCall() {
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '在线客服不可用,是否拨打电话联系客服?',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) this.makePhoneCall();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取客服按钮配置
|
* 获取按钮配置(用于 template 中 v-if / open-type 判断)
|
||||||
* @returns {Object} 按钮配置
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
getButtonConfig() {
|
getButtonConfig() {
|
||||||
const config = this.getPlatformConfig();
|
const config = this.getPlatformConfig();
|
||||||
@@ -507,11 +454,10 @@ class CustomerService {
|
|||||||
|
|
||||||
let openType = '';
|
let openType = '';
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
if (config.type === 'weapp') {
|
if (config.type === 'weapp' && config.useOfficial !== false) {
|
||||||
openType = config.useOfficial !== false ? 'contact' : '';
|
openType = 'contact';
|
||||||
}
|
}
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef MP-ALIPAY
|
// #ifdef MP-ALIPAY
|
||||||
if (config.type === 'aliapp') openType = 'contact';
|
if (config.type === 'aliapp') openType = 'contact';
|
||||||
// #endif
|
// #endif
|
||||||
@@ -520,26 +466,239 @@ class CustomerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否应该使用自定义客服处理
|
* 获取客服按钮图标
|
||||||
* @param {Object} config 客服配置
|
* @returns {String} 图标URL
|
||||||
* @returns {boolean} 是否使用自定义客服
|
|
||||||
*/
|
*/
|
||||||
shouldUseCustomService(config) {
|
getKefuButtonIcon() {
|
||||||
// #ifdef MP-WEIXIN
|
const shopInfo = this.vm.shopInfo || {};
|
||||||
if (config?.type === 'weapp') {
|
const config = this.getPlatformConfig();
|
||||||
return config.useOfficial === false;
|
|
||||||
|
// 优先使用指定的智能客服头像
|
||||||
|
if (config?.type === 'aikefu' || config?.type === 'wxwork' || config?.type === 'qyweixin') {
|
||||||
|
return this.vm.$util.img(IMAGE_CONFIG.aiAvatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return shopInfo.kefuimg || this.vm.$util?.getDefaultImage()?.kefu || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为微信官方客服
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
isWeappOfficialKefu() {
|
||||||
|
const config = this.getPlatformConfig();
|
||||||
|
return config?.type === 'weapp';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为智能客服
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
isAIKefu() {
|
||||||
|
const config = this.getPlatformConfig();
|
||||||
|
return config?.type === 'aikefu';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为企业微信客服
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
isWxworkKefu() {
|
||||||
|
const config = this.getPlatformConfig();
|
||||||
|
return config?.type === 'wxwork' || config?.type === 'qyweixin';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为第三方客服
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
isThirdKefu() {
|
||||||
|
const config = this.getPlatformConfig();
|
||||||
|
return config?.type === 'third';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否需要同时显示小程序系统客服
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
shouldShowExtraWeappSystemKefu() {
|
||||||
|
const config = this.getPlatformConfig();
|
||||||
|
return (config?.show_system_service === true || config?.show_system_service === '1') && config?.type !== 'weapp';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算容器高度
|
||||||
|
* @param {Boolean} isLanguageSwitchEnabled 是否启用语言切换
|
||||||
|
* @param {Boolean} showWeappSystemKefu 是否显示小程序系统客服
|
||||||
|
* @param {Boolean} fixBtnShow 是否显示按钮
|
||||||
|
* @returns {String} 高度值(px)
|
||||||
|
*/
|
||||||
|
getContainerHeight(isLanguageSwitchEnabled, showWeappSystemKefu, fixBtnShow) {
|
||||||
|
if (!fixBtnShow) return '160px';
|
||||||
|
|
||||||
|
let buttonCount = 1;
|
||||||
|
if (isLanguageSwitchEnabled) buttonCount++;
|
||||||
|
if (showWeappSystemKefu) buttonCount++;
|
||||||
|
|
||||||
|
const totalRpx = 94 * buttonCount - 14;
|
||||||
|
const pxValue = Math.round(totalRpx * 0.5);
|
||||||
|
|
||||||
|
return `${pxValue}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取未读消息数量
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
getUnreadCount() {
|
||||||
|
return this.vm.$store?.state?.aiUnreadCount || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拨打电话联系客服
|
||||||
|
* @param {String} phoneNumber 电话号码
|
||||||
|
*/
|
||||||
|
makePhoneCallByNumber(phoneNumber) {
|
||||||
|
if (phoneNumber) {
|
||||||
|
uni.makePhoneCall({ phoneNumber });
|
||||||
|
} else {
|
||||||
|
this.makePhoneCall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开 AI 智能助手
|
||||||
|
*/
|
||||||
|
openAIChat() {
|
||||||
|
try {
|
||||||
|
if (typeof this.vm.setAiUnreadCount === 'function') {
|
||||||
|
this.vm.setAiUnreadCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const aiChatUrl = '/pages_tool/ai-chat/index';
|
||||||
|
|
||||||
|
uni.navigateTo({
|
||||||
|
url: aiChatUrl,
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('跳转 AI 客服失败:', err);
|
||||||
|
// #ifdef H5
|
||||||
|
window.location.href = aiChatUrl;
|
||||||
|
// #endif
|
||||||
|
uni.showToast({ title: '打开客服失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('跳转 AI 客服异常:', e);
|
||||||
|
uni.showToast({ title: '打开客服失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开客服选择对话框(预留方法)
|
||||||
|
*/
|
||||||
|
openCustomerSelectPopupDialog() {
|
||||||
|
uni.showToast({ title: '客服选择功能开发中', icon: 'none' });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开客服选择弹出层(ActionSheet)
|
||||||
|
* @param {Array} kefuList 客服列表
|
||||||
|
*/
|
||||||
|
openKefuSelectPopup(kefuList) {
|
||||||
|
const kefuNames = kefuList.map(item => item.name);
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: kefuNames,
|
||||||
|
success: (res) => {
|
||||||
|
const selectedKefu = kefuList[res.tapIndex];
|
||||||
|
const cs = createCustomerService(this.vm, selectedKefu);
|
||||||
|
|
||||||
|
if (selectedKefu.isOfficial) {
|
||||||
|
uni.openCustomerServiceConversation({
|
||||||
|
sessionFrom: 'weapp',
|
||||||
|
showMessageCard: true
|
||||||
|
});
|
||||||
|
} else if (selectedKefu.id === 'qyweixin-kefu') {
|
||||||
|
if (uni.getSystemInfoSync().platform === 'wechat') {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages_tool/qyweixin-kefu/index'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const qyweixinUrl = this.vm.shopInfo?.qyweixinUrl;
|
||||||
|
if (qyweixinUrl) {
|
||||||
|
window.location.href = qyweixinUrl;
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '企业微信客服未配置', icon: 'none' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cs.handleCustomerClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心方法:统一客服入口(带验证和配置检查)
|
||||||
|
* @param {Object} options 选项参数
|
||||||
|
*/
|
||||||
|
handleUnifiedKefuClick(options = {}) {
|
||||||
|
const validation = this.validateConfig();
|
||||||
|
|
||||||
|
console.log('【客服配置验证】', validation);
|
||||||
|
|
||||||
|
if (!validation.isValid) {
|
||||||
|
console.error('客服配置无效:', validation.errors);
|
||||||
|
uni.showToast({ title: '客服暂不可用', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validation.warnings.length > 0) {
|
||||||
|
console.warn('客服配置警告:', validation.warnings);
|
||||||
|
}
|
||||||
|
|
||||||
|
const platformConfig = this.getPlatformConfig();
|
||||||
|
console.log('【当前客服配置】', platformConfig);
|
||||||
|
|
||||||
|
// 检查企业微信配置
|
||||||
|
if (platformConfig.type === 'wxwork') {
|
||||||
|
const wxworkConfig = this.getWxworkConfig();
|
||||||
|
console.log('【企业微信配置】', wxworkConfig);
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
if (!wxworkConfig?.enable || !wxworkConfig?.contact_url) {
|
||||||
|
console.warn('企业微信配置不完整,使用原生客服');
|
||||||
|
uni.showToast({ title: '企业微信配置不完整', icon: 'none' });
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
if (!wxworkConfig?.contact_url && !platformConfig.wxwork_url) {
|
||||||
|
console.error('企业微信链接未配置');
|
||||||
|
uni.showToast({ title: '企业微信链接未配置', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接调用统一处理方法,由 CustomerService 内部根据配置路由
|
||||||
|
try {
|
||||||
|
this.handleCustomerClick({
|
||||||
|
sendMessageTitle: options.sendMessageTitle || '来自悬浮按钮的咨询',
|
||||||
|
sendMessagePath: options.sendMessagePath || '/pages/index/index'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('客服处理失败:', error);
|
||||||
|
uni.showToast({ title: '打开客服失败', icon: 'none' });
|
||||||
}
|
}
|
||||||
// #endif
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建客服服务实例
|
* 创建客服服务实例
|
||||||
* @param {Object} vueInstance Vue实例
|
* @param {Object} vueInstance Vue 实例(通常是 this)
|
||||||
* @param {Object} externalConfig 外部最新配置
|
* @param {Object} externalConfig 可选:外部传入的最新配置(如从 DIY 数据中提取)
|
||||||
* @returns {CustomerService} 客服服务实例
|
* @returns {CustomerService}
|
||||||
*/
|
*/
|
||||||
export function createCustomerService(vueInstance, externalConfig = {}) {
|
export function createCustomerService(vueInstance, externalConfig = null) {
|
||||||
return new CustomerService(vueInstance, externalConfig);
|
return new CustomerService(vueInstance, externalConfig);
|
||||||
}
|
}
|
||||||
@@ -609,10 +609,10 @@ export default {
|
|||||||
},
|
},
|
||||||
// 分享给好友
|
// 分享给好友
|
||||||
onShareAppMessage() {
|
onShareAppMessage() {
|
||||||
return this.mpShareData.appMessage;
|
return this.mpShareData?.appMessage;
|
||||||
},
|
},
|
||||||
// 分享到朋友圈
|
// 分享到朋友圈
|
||||||
onShareTimeline() {
|
onShareTimeline() {
|
||||||
return this.mpShareData.timeLine;
|
return this.mpShareData?.timeLine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
// 是否是英文环境
|
// 是否是英文环境
|
||||||
isEnEnv() {
|
isEnEnv() {
|
||||||
return uni.getStorageSync('lang') === 'en-us';
|
return this.$langConfig.getCurrentLocale() === 'en-us';
|
||||||
},
|
},
|
||||||
themeStyle() {
|
themeStyle() {
|
||||||
return this.$store.state.themeStyle;
|
return this.$store.state.themeStyle;
|
||||||
@@ -65,6 +65,10 @@ export default {
|
|||||||
componentRefresh() {
|
componentRefresh() {
|
||||||
return this.$store.state.componentRefresh;
|
return this.$store.state.componentRefresh;
|
||||||
},
|
},
|
||||||
|
// AI客服配置
|
||||||
|
globalAIKefuConfig() {
|
||||||
|
return this.$store.state.globalAIKefuConfig;
|
||||||
|
},
|
||||||
// 客服配置
|
// 客服配置
|
||||||
servicerConfig() {
|
servicerConfig() {
|
||||||
return this.$store.state.servicerConfig;
|
return this.$store.state.servicerConfig;
|
||||||
|
|||||||
15
common/js/image-config.js
Normal file
15
common/js/image-config.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* 图片配置文件
|
||||||
|
* 将大图片上传到服务器后,请在此处配置网络URL
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 替换为你上传后的实际图片URL
|
||||||
|
const IMAGE_CONFIG = {
|
||||||
|
// AI客服头像
|
||||||
|
aiAvatar: 'public/static/img/s-agent.jpg',
|
||||||
|
|
||||||
|
// 用户默认头像
|
||||||
|
userAvatar: 'public/static/img/s-user.jpg'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default IMAGE_CONFIG;
|
||||||
@@ -54,18 +54,30 @@ function loadLangPackSync(lang, path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentLocale() {
|
||||||
|
return uni.getStorageSync('lang') || "zh-cn";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
langList: langConfig.langList,
|
langList: langConfig.langList,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当前本地语言
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getCurrentLocale,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 解析多语言
|
* * 解析多语言
|
||||||
* @param {Object} field
|
* @param {Object} field
|
||||||
*/
|
*/
|
||||||
lang(field) {
|
lang(field) {
|
||||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
let _page = getCurrentPages()[getCurrentPages().length - 1];
|
||||||
if (!_this) return;
|
if (!_page) return;
|
||||||
|
|
||||||
const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
|
|
||||||
|
|
||||||
|
const locale = getCurrentLocale(); // 获得当前本地语言
|
||||||
|
|
||||||
let value = ''; // 存放解析后的语言值
|
let value = ''; // 存放解析后的语言值
|
||||||
let langPath = ''; // 存放当前页面语言包路径
|
let langPath = ''; // 存放当前页面语言包路径
|
||||||
|
|
||||||
@@ -74,7 +86,7 @@ export default {
|
|||||||
var lang = loadLangPackSync(locale, 'common');
|
var lang = loadLangPackSync(locale, 'common');
|
||||||
|
|
||||||
//当前页面语言包(同步加载)
|
//当前页面语言包(同步加载)
|
||||||
let route = _this.route;
|
let route = _page.route;
|
||||||
langPath = processRoutePath(route);
|
langPath = processRoutePath(route);
|
||||||
|
|
||||||
// 加载当前页面语言包
|
// 加载当前页面语言包
|
||||||
@@ -128,11 +140,11 @@ export default {
|
|||||||
* @param {String} url 切换后跳转的页面url
|
* @param {String} url 切换后跳转的页面url
|
||||||
*/
|
*/
|
||||||
change(value, url = '/pages_tool/member/index') {
|
change(value, url = '/pages_tool/member/index') {
|
||||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
let _page = getCurrentPages()[getCurrentPages().length - 1];
|
||||||
if (!_this) return;
|
if (!_page) return;
|
||||||
|
|
||||||
uni.setStorageSync("lang", value);
|
uni.setStorageSync("lang", value);
|
||||||
const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
|
const locale = getCurrentLocale();
|
||||||
|
|
||||||
// 清空已加载的语言包缓存
|
// 清空已加载的语言包缓存
|
||||||
for (let key in loadedLangPacks) {
|
for (let key in loadedLangPacks) {
|
||||||
@@ -149,9 +161,10 @@ export default {
|
|||||||
},
|
},
|
||||||
//刷新标题、tabbar
|
//刷新标题、tabbar
|
||||||
refresh() {
|
refresh() {
|
||||||
let _this = getCurrentPages()[getCurrentPages().length - 1];
|
let _page = getCurrentPages()[getCurrentPages().length - 1];
|
||||||
if (!_this) return;
|
if (!_page) return;
|
||||||
const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
|
|
||||||
|
const locale = getCurrentLocale();
|
||||||
|
|
||||||
this.title(this.lang("title"));
|
this.title(this.lang("title"));
|
||||||
|
|
||||||
@@ -202,4 +215,4 @@ export default {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -843,6 +843,15 @@ export default {
|
|||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 隐藏“返回首页/小房子”按钮
|
||||||
|
* 这个函数,用到页面show, onshow 的生命周期时
|
||||||
|
*/
|
||||||
|
hideHomeButton() {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
wx.hideHomeButton();
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param val 转化时间字符串 (转化时分秒)
|
* @param val 转化时间字符串 (转化时分秒)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
:autoplay="swiperConfig.autoplay !== false" :circular="swiperConfig.circular !== false"
|
:autoplay="swiperConfig.autoplay !== false" :circular="swiperConfig.circular !== false"
|
||||||
:interval="swiperConfig.interval || 3000" :duration="swiperConfig.duration || 500"
|
:interval="swiperConfig.interval || 3000" :duration="swiperConfig.duration || 500"
|
||||||
:display-multiple-items="safeDisplayMultipleItems">
|
:display-multiple-items="safeDisplayMultipleItems">
|
||||||
<swiper-item v-for="(item, index) in list" :key="index" @click="toDetail(item)">
|
<swiper-item v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)">
|
||||||
<view class="swiper-item-content">
|
<view class="swiper-item-content">
|
||||||
<view :class="['item', value.ornament.type]" :style="itemCss">
|
<view :class="['item', value.ornament.type]" :style="itemCss">
|
||||||
<view class="article-img">
|
<view class="article-img">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<view class="time" :style="{ color: value.timecolor }">
|
<view class="time" :style="{ color: value.timecolor }">
|
||||||
{{ audiotime }}
|
{{ audiotime }}
|
||||||
</view>
|
</view>
|
||||||
<view @click="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"
|
<view @tap.stop="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"
|
||||||
style="padding-top: 18rpx"></view>
|
style="padding-top: 18rpx"></view>
|
||||||
</view>
|
</view>
|
||||||
<view class="fui-audio style3" :style="{ background: value.background }" v-else>
|
<view class="fui-audio style3" :style="{ background: value.background }" v-else>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<!-- {{audios[value.id].audiotime}} -->
|
<!-- {{audios[value.id].audiotime}} -->
|
||||||
{{ audiotime }}
|
{{ audiotime }}
|
||||||
</view>
|
</view>
|
||||||
<view @click="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"></view>
|
<view @tap.stop="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
:style="{ color: value.titleStyle.textColor }">低至0元免费拿</view>
|
:style="{ color: value.titleStyle.textColor }">低至0元免费拿</view>
|
||||||
<view class="head-right"
|
<view class="head-right"
|
||||||
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
||||||
@click="$util.redirectTo('/pages_promotion/bargain/list')">
|
@tap.stop="$util.redirectTo('/pages_promotion/bargain/list')">
|
||||||
<text>{{ value.titleStyle.more }}</text>
|
<text>{{ value.titleStyle.more }}</text>
|
||||||
<text class="iconfont icon-right"></text>
|
<text class="iconfont icon-right"></text>
|
||||||
</view>
|
</view>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<!-- 商品列表 -->
|
<!-- 商品列表 -->
|
||||||
<template v-if="value.template == 'row1-of1'">
|
<template v-if="value.template == 'row1-of1'">
|
||||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
|
|
||||||
<template v-if="value.template == 'horizontal-slide'">
|
<template v-if="value.template == 'horizontal-slide'">
|
||||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
<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" @click="toDetail(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :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"
|
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||||
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view data-component-name="diy-bottom-nav" v-if="tabBarList && tabBarList.list">
|
<view data-component-name="diy-bottom-nav" v-if="tabBarList && tabBarList.list">
|
||||||
<view class="tab-bar" :style="{ backgroundColor: tabBarList.backgroundColor }">
|
<view class="tab-bar" :style="{ backgroundColor: tabBarList.backgroundColor }">
|
||||||
<view class="tabbar-border"></view>
|
<view class="tabbar-border"></view>
|
||||||
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @click="redirectTo(item.link)">
|
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @tap.stop="redirectTo(item.link)">
|
||||||
<view class="bd">
|
<view class="bd">
|
||||||
<block v-if="item.link.wap_url == '/pages_goods/cart'">
|
<block v-if="item.link.wap_url == '/pages_goods/cart'">
|
||||||
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2"
|
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view data-component-name="diy-category-item" class="item-wrap" :class="type">
|
<view data-component-name="diy-category-item" class="item-wrap" :class="type">
|
||||||
<block v-if="type == 'category' && category.child_list && category.child_list.length">
|
<block v-if="type == 'category' && category.child_list && category.child_list.length">
|
||||||
<view class="category-adv" v-if="category.image_adv" @click="diyRedirectTo(category.link_url)">
|
<view class="category-adv" v-if="category.image_adv" @tap.stop="diyRedirectTo(category.link_url)">
|
||||||
<image :src="$util.img(category.image_adv)" mode="widthFix" />
|
<image :src="$util.img(category.image_adv)" mode="widthFix" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<view class="category-title">{{ category.category_name }}</view>
|
<view class="category-title">{{ category.category_name }}</view>
|
||||||
<view class="category-list">
|
<view class="category-list">
|
||||||
<view class="category-item" v-for="(one, oneIndex) in category.child_list" :key="oneIndex"
|
<view class="category-item" v-for="(one, oneIndex) in category.child_list" :key="oneIndex"
|
||||||
@click="$util.redirectTo('/pages_goods/list', { category_id: one.category_id })">
|
@tap.stop="$util.redirectTo('/pages_goods/list', { category_id: one.category_id })">
|
||||||
<view class="img-box">
|
<view class="img-box">
|
||||||
<image :src="$util.img(one.image)" mode="widthFix" />
|
<image :src="$util.img(one.image)" mode="widthFix" />
|
||||||
</view>
|
</view>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<view class="category-title">{{ one.category_name }}</view>
|
<view class="category-title">{{ one.category_name }}</view>
|
||||||
<view class="category-list">
|
<view class="category-list">
|
||||||
<view class="category-item" v-for="(two, twoIndex) in one.child_list" :key="twoIndex"
|
<view class="category-item" v-for="(two, twoIndex) in one.child_list" :key="twoIndex"
|
||||||
@click="$util.redirectTo('/pages_goods/list', { category_id: two.category_id })">
|
@tap.stop="$util.redirectTo('/pages_goods/list', { category_id: two.category_id })">
|
||||||
<view class="img-box">
|
<view class="img-box">
|
||||||
<image :src="$util.img(two.image)" mode="widthFix" :lazy-load="true" />
|
<image :src="$util.img(two.image)" mode="widthFix" :lazy-load="true" />
|
||||||
</view>
|
</view>
|
||||||
@@ -44,22 +44,22 @@
|
|||||||
:class="{ 'screen-category-4': value.template == 4 }" :scroll-with-animation="true"
|
:class="{ 'screen-category-4': value.template == 4 }" :scroll-with-animation="true"
|
||||||
:scroll-into-view="scrollIntoView">
|
:scroll-into-view="scrollIntoView">
|
||||||
<view class="item" id="category-2--1" :class="{ selected: categoryId == -1 }"
|
<view class="item" id="category-2--1" :class="{ selected: categoryId == -1 }"
|
||||||
@click="selectCategory(-1)">全部</view>
|
@tap.stop="selectCategory(-1)">全部</view>
|
||||||
<view class="item" :id="'category-2-' + oneIndex"
|
<view class="item" :id="'category-2-' + oneIndex"
|
||||||
:class="{ selected: categoryId == oneIndex }" @click="selectCategory(oneIndex)"
|
:class="{ selected: categoryId == oneIndex }" @tap.stop="selectCategory(oneIndex)"
|
||||||
v-for="(one, oneIndex) in category.child_list" :key="oneIndex">
|
v-for="(one, oneIndex) in category.child_list" :key="oneIndex">
|
||||||
{{ one.category_name }}
|
{{ one.category_name }}
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<view class="iconfont icon-unfold" @click="$refs.screenCategoryPopup.open()"></view>
|
<view class="iconfont icon-unfold" @tap.stop="$refs.screenCategoryPopup.open()"></view>
|
||||||
</view>
|
</view>
|
||||||
<uni-popup type="top" ref="screenCategoryPopup">
|
<uni-popup type="top" ref="screenCategoryPopup">
|
||||||
<view class="screen-category-popup" @click="$refs.screenCategoryPopup.close()">
|
<view class="screen-category-popup" @tap.stop="$refs.screenCategoryPopup.close()">
|
||||||
<scroll-view scroll-y="true" class="screen-category"
|
<scroll-view scroll-y="true" class="screen-category"
|
||||||
:class="{ 'screen-category-4': value.template == 4 }">
|
:class="{ 'screen-category-4': value.template == 4 }">
|
||||||
<view class="title">全部</view>
|
<view class="title">全部</view>
|
||||||
<view class="item" :class="{ selected: categoryId == oneIndex }"
|
<view class="item" :class="{ selected: categoryId == oneIndex }"
|
||||||
@click="selectCategory(oneIndex)" v-for="(one, oneIndex) in category.child_list"
|
@tap.stop="selectCategory(oneIndex)" v-for="(one, oneIndex) in category.child_list"
|
||||||
:key="oneIndex">
|
:key="oneIndex">
|
||||||
{{ one.category_name }}
|
{{ one.category_name }}
|
||||||
</view>
|
</view>
|
||||||
@@ -81,13 +81,13 @@
|
|||||||
:data-template="value.template">
|
:data-template="value.template">
|
||||||
<block v-if="goodsList.length">
|
<block v-if="goodsList.length">
|
||||||
<view class="goods-item" v-for="(item, index) in goodsList" :key="index">
|
<view class="goods-item" v-for="(item, index) in goodsList" :key="index">
|
||||||
<view class="goods-img" @click="toDetail(item)">
|
<view class="goods-img" @tap.stop="toDetail(item)">
|
||||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" />
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" :show-menu-by-longpress="true" />
|
||||||
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}
|
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<view class="info-wrap">
|
<view class="info-wrap">
|
||||||
<view class="name-wrap" @click="toDetail(item)">
|
<view class="name-wrap" @tap.stop="toDetail(item)">
|
||||||
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
|
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-wrap">
|
<view class="price-wrap">
|
||||||
@@ -99,9 +99,6 @@
|
|||||||
<text class="unit price-style small">.{{
|
<text class="unit price-style small">.{{
|
||||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||||
</block>
|
</block>
|
||||||
<block v-else>
|
|
||||||
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询底价' }}</text>
|
|
||||||
</block>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="member-price-tag"
|
<view class="member-price-tag"
|
||||||
v-if="item.member_price && item.member_price == showPrice(item)">
|
v-if="item.member_price && item.member_price == showPrice(item)">
|
||||||
@@ -120,27 +117,33 @@
|
|||||||
<text>{{ showMarketPrice(item) }}</text>
|
<text>{{ showMarketPrice(item) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
||||||
|
<view class="ai-chat-btn" @tap.stop="sendToAIChat(item)">
|
||||||
|
立即咨询
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- <view class="right-wrap" v-if="value.template == 2 || value.template == 4">
|
<!-- <view class="right-wrap" v-if="value.template == 2 || value.template == 4">
|
||||||
<block v-if="item.is_virtual">
|
<block v-if="item.is_virtual">
|
||||||
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
|
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||||
</block>
|
</block>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<view v-if="item.goods_spec_format" class="color-base-bg select-sku" @click="selectSku(item)">
|
<view v-if="item.goods_spec_format" class="color-base-bg select-sku" @tap.stop="selectSku(item)">
|
||||||
<text>选规格</text>
|
<text>选规格</text>
|
||||||
<text class="num-tag" v-if="item.num">{{ item.num }}</text>
|
<text class="num-tag" v-if="item.num">{{ item.num }}</text>
|
||||||
</view>
|
</view>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<block v-if="cartList['goods_' + item.goods_id]&&cartList['goods_' + item.goods_id]['sku_' + item.sku_id]">
|
<block v-if="cartList['goods_' + item.goods_id]&&cartList['goods_' + item.goods_id]['sku_' + item.sku_id]">
|
||||||
<view class="num-action reduce" @click="reduce(item)">
|
<view class="num-action reduce" @tap.stop="reduce(item)">
|
||||||
<text class="iconfont icon-jian"></text>
|
<text class="iconfont icon-jian"></text>
|
||||||
</view>
|
</view>
|
||||||
<view class="num">{{ cartList['goods_' + item.goods_id]['sku_' + item.sku_id].num }}</view>
|
<view class="num">{{ cartList['goods_' + item.goods_id]['sku_' + item.sku_id].num }}</view>
|
||||||
<view class="num-action" :id="'cart-num-' + index" @click="increase($event, item)">
|
<view class="num-action" :id="'cart-num-' + index" @tap.stop="increase($event, item)">
|
||||||
<text class="iconfont icon-jia"></text>
|
<text class="iconfont icon-jia"></text>
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
<view class="num-action" v-else :id="'cart-num-' + index" @click="increase($event, item, 0)">
|
<view class="num-action" v-else :id="'cart-num-' + index" @tap.stop="increase($event, item, 0)">
|
||||||
<text class="iconfont icon-jia"></text>
|
<text class="iconfont icon-jia"></text>
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
</view>
|
</view>
|
||||||
@@ -148,7 +151,7 @@
|
|||||||
</block>
|
</block>
|
||||||
</view> -->
|
</view> -->
|
||||||
<!-- <view class="right-wrap" v-if="value.template == 3">
|
<!-- <view class="right-wrap" v-if="value.template == 3">
|
||||||
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
|
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||||
</view> -->
|
</view> -->
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -158,7 +161,7 @@
|
|||||||
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" />
|
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" />
|
||||||
</view>
|
</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-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 @click="switchCategory('next')">
|
<view class="end-tips" ref="endTips" v-else @tap.stop="switchCategory('next')">
|
||||||
<text class="iconfont icon-xiangshangzhanhang"></text>
|
<text class="iconfont icon-xiangshangzhanhang"></text>
|
||||||
上滑查看下一分类
|
上滑查看下一分类
|
||||||
</view> -->
|
</view> -->
|
||||||
@@ -173,29 +176,25 @@
|
|||||||
<view class="goods-list" :class="{ 'double-column': !isList, 'single-column': isList }"
|
<view class="goods-list" :class="{ 'double-column': !isList, 'single-column': isList }"
|
||||||
:data-template="value.template">
|
:data-template="value.template">
|
||||||
<view class="goods-item" v-for="(item, index) in goodsList" :key="index">
|
<view class="goods-item" v-for="(item, index) in goodsList" :key="index">
|
||||||
<view class="goods-img" @click="toDetail(item)">
|
<view class="goods-img" @tap.stop="toDetail(item)">
|
||||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"
|
||||||
:lazy-load="true" />
|
:lazy-load="true" :show-menu-by-longpress="true" />
|
||||||
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}</view>
|
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-wrap">
|
<view class="info-wrap">
|
||||||
<view class="name-wrap" @click="toDetail(item)">
|
<view class="name-wrap" @tap.stop="toDetail(item)">
|
||||||
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
|
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-wrap">
|
<view class="price-wrap">
|
||||||
<view class="discount-price">
|
<view class="discount-price">
|
||||||
<block v-if="item.isinformation == 0">
|
<block v-if="item.isinformation == 0">
|
||||||
<text class="unit price-style small">¥</text>
|
<text class="unit price-style small">¥</text>
|
||||||
<text class="price price-style large">{{
|
<text class="price price-style large">{{
|
||||||
parseFloat(showPrice(item)).toFixed(2).split('.')[0] }}</text>
|
parseFloat(showPrice(item)).toFixed(2).split('.')[0] }}</text>
|
||||||
<text class="unit price-style small">.{{
|
<text class="unit price-style small">.{{
|
||||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||||
</block>
|
</block>
|
||||||
<block v-else>
|
</view>
|
||||||
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询底价' }}</text>
|
|
||||||
</block>
|
|
||||||
|
|
||||||
</view>
|
|
||||||
<view class="member-price-tag"
|
<view class="member-price-tag"
|
||||||
v-if="item.member_price && item.member_price == showPrice(item)">
|
v-if="item.member_price && item.member_price == showPrice(item)">
|
||||||
<image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix" />
|
<image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix" />
|
||||||
@@ -212,32 +211,38 @@
|
|||||||
<text>{{ showMarketPrice(item) }}</text>
|
<text>{{ showMarketPrice(item) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
||||||
|
<view class="ai-chat-btn" @tap.stop="sendToAIChat(item)">
|
||||||
|
立即咨询
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="right-wrap" v-if="value.template == 2">
|
<view class="right-wrap" v-if="value.template == 2">
|
||||||
<block v-if="item.is_virtual">
|
<block v-if="item.is_virtual">
|
||||||
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
|
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||||
</block>
|
</block>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<view v-if="item.goods_spec_format" class="color-base-bg select-sku"
|
<view v-if="item.goods_spec_format" class="color-base-bg select-sku"
|
||||||
@click="selectSku(item)">
|
@tap.stop="selectSku(item)">
|
||||||
<text>选规格</text>
|
<text>选规格</text>
|
||||||
<text class="num-tag" v-if="item.num">{{ item.num }}</text>
|
<text class="num-tag" v-if="item.num">{{ item.num }}</text>
|
||||||
</view>
|
</view>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<block
|
<block
|
||||||
v-if="cartList['goods_' + item.goods_id] && cartList['goods_' + item.goods_id]['sku_' + item.sku_id]">
|
v-if="cartList['goods_' + item.goods_id] && cartList['goods_' + item.goods_id]['sku_' + item.sku_id]">
|
||||||
<view class="num-action reduce" @click="reduce(item)">
|
<view class="num-action reduce" @tap.stop="reduce(item)">
|
||||||
<text class="iconfont icon-jian"></text>
|
<text class="iconfont icon-jian"></text>
|
||||||
</view>
|
</view>
|
||||||
<view class="num">{{ cartList['goods_' + item.goods_id]['sku_' +
|
<view class="num">{{ cartList['goods_' + item.goods_id]['sku_' +
|
||||||
item.sku_id].num }}</view>
|
item.sku_id].num }}</view>
|
||||||
<view class="num-action" :id="'cart-num-' + index"
|
<view class="num-action" :id="'cart-num-' + index"
|
||||||
@click="increase($event, item)">
|
@tap.stop="increase($event, item)">
|
||||||
<text class="iconfont icon-jia"></text>
|
<text class="iconfont icon-jia"></text>
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
<view class="num-action" v-else :id="'cart-num-' + index"
|
<view class="num-action" v-else :id="'cart-num-' + index"
|
||||||
@click="increase($event, item, 0)">
|
@tap.stop="increase($event, item, 0)">
|
||||||
<text class="iconfont icon-jia"></text>
|
<text class="iconfont icon-jia"></text>
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
</view>
|
</view>
|
||||||
@@ -245,7 +250,7 @@
|
|||||||
</block>
|
</block>
|
||||||
</view>
|
</view>
|
||||||
<view class="right-wrap" v-if="value.template == 3">
|
<view class="right-wrap" v-if="value.template == 3">
|
||||||
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
|
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -718,6 +723,15 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 跳转到商品详情
|
||||||
|
* @param {Object} item 商品信息
|
||||||
|
*/
|
||||||
|
sendToAIChat(item) {
|
||||||
|
this.$util.redirectTo('/pages_goods/detail', {
|
||||||
|
goods_id: item.goods_id
|
||||||
|
});
|
||||||
|
},
|
||||||
diyRedirectTo(link) {
|
diyRedirectTo(link) {
|
||||||
if (!link) return;
|
if (!link) return;
|
||||||
this.$util.diyRedirectTo(JSON.parse(link));
|
this.$util.diyRedirectTo(JSON.parse(link));
|
||||||
@@ -1384,4 +1398,25 @@ export default {
|
|||||||
color: var(--main-color);
|
color: var(--main-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-chat-btn-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-chat-btn {
|
||||||
|
background-color: #ff0000;
|
||||||
|
color: #fff;
|
||||||
|
padding: 12rpx 30rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
:style="{ height: 'calc(100vh - ' + tabBarHeight + ')' }">
|
:style="{ height: 'calc(100vh - ' + tabBarHeight + ')' }">
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
<!-- <block v-if="value.template == 4">
|
<!-- <block v-if="value.template == 4">
|
||||||
<view class="search-box" v-if="value.search" @click="$util.redirectTo('/pages_tool/goods/search')" :style="navbarInnerStyle">
|
<view class="search-box" v-if="value.search" @tap.stop="$util.redirectTo('/pages_tool/goods/search')" :style="navbarInnerStyle">
|
||||||
<view class="search-content">
|
<view class="search-content">
|
||||||
<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" />
|
<input type="text" class="uni-input font-size-tag" maxlength="50" :placeholder="$lang('search')" confirm-type="search" @tap.stop="onClickSearch()" disabled="true" />
|
||||||
<text class="iconfont icon-sousuo3"></text>
|
<text class="iconfont icon-sousuo3"></text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -13,35 +13,35 @@
|
|||||||
</block> -->
|
</block> -->
|
||||||
<block v-if="value.template != 4">
|
<block v-if="value.template != 4">
|
||||||
<!-- <view :style="navbarInnerStyle">商品分类</view> -->
|
<!-- <view :style="navbarInnerStyle">商品分类</view> -->
|
||||||
<view class="search-box" v-if="value.search" @click="onClickSearch()" @tap.stop="onClickSearch()"
|
<view class="search-box" v-if="value.search" @tap.stop="onClickSearch()"
|
||||||
:style="wxSearchHeight">
|
:style="wxSearchHeight">
|
||||||
<view class="search-content">
|
<view class="search-content">
|
||||||
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('search')"
|
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('search')"
|
||||||
confirm-type="search" @click.stop="onClickSearch()" @tap.stop="onClickSearch()"
|
confirm-type="search" @tap.stop="onClickSearch()"
|
||||||
disabled="true" />
|
disabled="true" />
|
||||||
<text class="iconfont icon-sousuo3"></text>
|
<text class="iconfont icon-sousuo3"></text>
|
||||||
</view>
|
</view>
|
||||||
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
|
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
|
||||||
@click.stop.prevent="changeListStyle()"></view>
|
@tap.stop.prevent="changeListStyle()"></view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<!-- #ifdef H5 -->
|
<!-- #ifdef H5 -->
|
||||||
<view class="search-box" v-if="value.search" @click="onClickSearch()" @tap.stop="onClickSearch()">
|
<view class="search-box" v-if="value.search" @tap.stop="onClickSearch()">
|
||||||
<view class="search-content">
|
<view class="search-content">
|
||||||
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('search')" confirm-type="search"
|
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('search')" confirm-type="search"
|
||||||
@click.stop="onClickSearch()" @tap.stop="onClickSearch()" disabled="true" />
|
@tap.stop="onClickSearch()" disabled="true" />
|
||||||
<text class="iconfont icon-sousuo3"></text>
|
<text class="iconfont icon-sousuo3"></text>
|
||||||
</view>
|
</view>
|
||||||
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
|
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
|
||||||
@click.stop.prevent="changeListStyle()"></view>
|
@tap.stop.prevent="changeListStyle()"></view>
|
||||||
</view>
|
</view>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<view class="template-four wx" v-if="value.template == 4">
|
<view class="template-four wx" v-if="value.template == 4">
|
||||||
<scroll-view scroll-x="true" class="template-four-wrap" :scroll-with-animation="true"
|
<scroll-view scroll-x="true" class="template-four-wrap" :scroll-with-animation="true"
|
||||||
:scroll-into-view="'category-one-' + oneCategorySelect" enable-flex="true">
|
:scroll-into-view="'category-one-' + oneCategorySelect" enable-flex="true">
|
||||||
<view class="category-item" :id="'category-one-' + index" v-for="(item, index) in templateFourData"
|
<view class="category-item" :id="'category-one-' + index" v-for="(item, index) in templateFourData"
|
||||||
:key="index" :class="{ select: oneCategorySelect == index }" @click="templateFourOneFn(index)">
|
:key="index" :class="{ select: oneCategorySelect == index }" @tap.stop="templateFourOneFn(index)">
|
||||||
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
|
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
|
||||||
<image :src="$util.img(item.image)" mode="aspectFill" />
|
<image :src="$util.img(item.image)" mode="aspectFill" />
|
||||||
</view>
|
</view>
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<view class="category-item-all" @click="$refs.templateFourPopup.open()">
|
<view class="category-item-all" @tap.stop="$refs.templateFourPopup.open()">
|
||||||
<view class="category-item-all-wrap">
|
<view class="category-item-all-wrap">
|
||||||
<text class="text">展开</text>
|
<text class="text">展开</text>
|
||||||
<image class="img" :src="$util.img('/public/uniapp/category/unfold.png')" mode="aspectFill"></image>
|
<image class="img" :src="$util.img('/public/uniapp/category/unfold.png')" mode="aspectFill"></image>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
<view class="template-four-popup">
|
<view class="template-four-popup">
|
||||||
<scroll-view scroll-y="true" class="template-four-scroll" enable-flex="true">
|
<scroll-view scroll-y="true" class="template-four-scroll" enable-flex="true">
|
||||||
<view class="item" :class="{ selected: oneCategorySelect == index }"
|
<view class="item" :class="{ selected: oneCategorySelect == index }"
|
||||||
@click="templateFourOneFn(index)" v-for="(item, index) in templateFourData" :key="index">
|
@tap.stop="templateFourOneFn(index)" v-for="(item, index) in templateFourData" :key="index">
|
||||||
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
|
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
|
||||||
<image :src="$util.img(item.image)" mode="aspectFill"></image>
|
<image :src="$util.img(item.image)" mode="aspectFill"></image>
|
||||||
</view>
|
</view>
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
item.category_name }}</view>
|
item.category_name }}</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<view class="pack-up" @click="$refs.templateFourPopup.close()">
|
<view class="pack-up" @tap.stop="$refs.templateFourPopup.close()">
|
||||||
<text>点击收起</text>
|
<text>点击收起</text>
|
||||||
<text class="iconfont icon-iconangledown-copy"></text>
|
<text class="iconfont icon-iconangledown-copy"></text>
|
||||||
</view>
|
</view>
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
{ select: select == index },
|
{ select: select == index },
|
||||||
{ 'border-bottom': value.template == 4 && select + 1 === index },
|
{ 'border-bottom': value.template == 4 && select + 1 === index },
|
||||||
{ 'border-top': value.template == 4 && select - 1 === index }
|
{ 'border-top': value.template == 4 && select - 1 === index }
|
||||||
]" @click="switchOneCategory(index)">
|
]" @tap.stop="switchOneCategory(index)">
|
||||||
<view class="">{{ item.category_name }}</view>
|
<view class="">{{ item.category_name }}</view>
|
||||||
</view>
|
</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="cart-box" v-if="(value.template == 2 || value.template == 4) && value.quickBuy && storeToken && categoryTree && categoryTree.length">
|
||||||
<view class="left-wrap">
|
<view class="left-wrap">
|
||||||
<view class="cart-icon" ref="cartIcon" :animation="cartAnimation" @click="$util.redirectTo('/pages_goods/cart')">
|
<view class="cart-icon" ref="cartIcon" :animation="cartAnimation" @tap.stop="$util.redirectTo('/pages_goods/cart')">
|
||||||
<text class="iconfont icon-ziyuan1"></text>
|
<text class="iconfont icon-ziyuan1"></text>
|
||||||
<view class="num" v-if="cartNumber">{{ cartNumber < 99 ? cartNumber : '99+' }}</view>
|
<view class="num" v-if="cartNumber">{{ cartNumber < 99 ? cartNumber : '99+' }}</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -141,7 +141,7 @@
|
|||||||
<text class="unit font-size-tag price-font">.{{ cartTotalMoney[1] ? cartTotalMoney[1] : '00' }}</text>
|
<text class="unit font-size-tag price-font">.{{ cartTotalMoney[1] ? cartTotalMoney[1] : '00' }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="right-wrap"><button type="primary" class="settlement-btn" @click="settlement">去结算</button>
|
<view class="right-wrap"><button type="primary" class="settlement-btn" @tap.stop="settlement">去结算</button>
|
||||||
</view>
|
</view>
|
||||||
</view> -->
|
</view> -->
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="video-info">
|
<view class="video-info">
|
||||||
<!-- 视频标题,支持多行显示控制 -->
|
<!-- 视频标题,支持多行显示控制 -->
|
||||||
<view class="video-title" :style="{ '--title-line-clamp': titleLineClamp }">{{ value.videoTitle }}
|
<view class="video-title" :style="[{ '--title-line-clamp': titleLineClamp }]">{{ value.videoTitle }}
|
||||||
</view>
|
</view>
|
||||||
<!-- 视频统计信息 -->
|
<!-- 视频统计信息 -->
|
||||||
<view class="video-stats" v-if="showViewCount && value.showViewCount">{{ value.viewCount }}次观看</view>
|
<view class="video-stats" v-if="showViewCount && value.showViewCount">{{ value.viewCount }}次观看</view>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 跳转式视频播放 -->
|
<!-- 跳转式视频播放 -->
|
||||||
<view v-else @click.stop="playVideo" class="video-container">
|
<view v-else @tap.stop="playVideo" class="video-container">
|
||||||
<view class="video-cover-wrap" :style="[coverStyle]">
|
<view class="video-cover-wrap" :style="[coverStyle]">
|
||||||
<image class="video-cover" :src="$util.img(value.coverUrl)" mode="aspectFill"></image>
|
<image class="video-cover" :src="$util.img(value.coverUrl)" mode="aspectFill"></image>
|
||||||
<view class="channel-play-btn" v-if="showPlayBtn" :style="[playBtnStyle]">
|
<view class="channel-play-btn" v-if="showPlayBtn" :style="[playBtnStyle]">
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="video-info">
|
<view class="video-info">
|
||||||
<!-- 视频标题,支持多行显示控制 -->
|
<!-- 视频标题,支持多行显示控制 -->
|
||||||
<view class="video-title" :style="{ '--title-line-clamp': titleLineClamp }">{{ value.videoTitle }}
|
<view class="video-title" :style="[{ '--title-line-clamp': titleLineClamp }]">{{ value.videoTitle }}
|
||||||
</view>
|
</view>
|
||||||
<!-- 视频统计信息,非列表模式下显示 -->
|
<!-- 视频统计信息,非列表模式下显示 -->
|
||||||
<view class="video-stats" v-if="showViewCount && value.showViewCount && !listMode">{{ value.viewCount }}次观看</view>
|
<view class="video-stats" v-if="showViewCount && value.showViewCount && !listMode">{{ value.viewCount }}次观看</view>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style1-bg.png') + ')',
|
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style1-bg.png') + ')',
|
||||||
marginRight: couponItemHeight + 'px',
|
marginRight: couponItemHeight + 'px',
|
||||||
marginLeft: couponItemHeight + 'px'
|
marginLeft: couponItemHeight + 'px'
|
||||||
}" @click="couponAction(item, index)">
|
}" @tap.stop="couponAction(item, index)">
|
||||||
|
|
||||||
<view class="coupon-info">
|
<view class="coupon-info">
|
||||||
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_bg1.png') + ')',
|
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_bg1.png') + ')',
|
||||||
marginRight: couponItemHeight + 'px',
|
marginRight: couponItemHeight + 'px',
|
||||||
marginLeft: couponItemHeight + 'px'
|
marginLeft: couponItemHeight + 'px'
|
||||||
}" @click="couponAction(item, index)">
|
}" @tap.stop="couponAction(item, index)">
|
||||||
<view class="coupon-info">
|
<view class="coupon-info">
|
||||||
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
||||||
v-if="!parseInt(item.discount)">
|
v-if="!parseInt(item.discount)">
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_shu.png') + ')',
|
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_shu.png') + ')',
|
||||||
marginRight: couponItemHeight + 'px',
|
marginRight: couponItemHeight + 'px',
|
||||||
marginLeft: couponItemHeight + 'px'
|
marginLeft: couponItemHeight + 'px'
|
||||||
}" @click="couponAction(item, index)">
|
}" @tap.stop="couponAction(item, index)">
|
||||||
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
||||||
v-if="!parseInt(item.discount)">
|
v-if="!parseInt(item.discount)">
|
||||||
<text class="font-size-tag coupon-sign">¥</text>
|
<text class="font-size-tag coupon-sign">¥</text>
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style4_bg.png') + ')',
|
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style4_bg.png') + ')',
|
||||||
marginRight: couponItemHeight + 'px',
|
marginRight: couponItemHeight + 'px',
|
||||||
marginLeft: couponItemHeight + 'px'
|
marginLeft: couponItemHeight + 'px'
|
||||||
}" @click="couponAction(item, index)">
|
}" @tap.stop="couponAction(item, index)">
|
||||||
<view class="coupon-info">
|
<view class="coupon-info">
|
||||||
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
<view class="coupon-num" :style="{ color: value.moneyColor }"
|
||||||
v-if="!parseInt(item.discount)">
|
v-if="!parseInt(item.discount)">
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
<view class="coupon-all">
|
<view class="coupon-all">
|
||||||
<view class="coupon-box">
|
<view class="coupon-box">
|
||||||
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index"
|
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index"
|
||||||
@click="couponAction(item, index)">
|
@tap.stop="couponAction(item, index)">
|
||||||
<image :src="$util.img('public/uniapp/coupon/style5_bg.png')"></image>
|
<image :src="$util.img('public/uniapp/coupon/style5_bg.png')"></image>
|
||||||
<view class="coupon">
|
<view class="coupon">
|
||||||
<view class="coupon-info">
|
<view class="coupon-info">
|
||||||
@@ -199,7 +199,7 @@
|
|||||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-1.png') + ')',
|
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-1.png') + ')',
|
||||||
marginRight: couponItemHeight + 'px',
|
marginRight: couponItemHeight + 'px',
|
||||||
marginLeft: couponItemHeight + 'px'
|
marginLeft: couponItemHeight + 'px'
|
||||||
}" @click="couponAction(item, index)">
|
}" @tap.stop="couponAction(item, index)">
|
||||||
<view class="coupon-content">
|
<view class="coupon-content">
|
||||||
<view class="price-wrap">
|
<view class="price-wrap">
|
||||||
<text class="price" :style="{ color: value.moneyColor }">{{ (item.discount == '0.00'
|
<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>
|
<text class="limit" :style="{ color: value.limitColor }" v-else>无门槛使用</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<div v-if="computedCouponList.length <= 2" @click="$util.redirectTo('/pages_goods/category')"
|
<div v-if="computedCouponList.length <= 2" @tap.stop="$util.redirectTo('/pages_goods/category')"
|
||||||
class="coupon coupon-null" :style="{
|
class="coupon coupon-null" :style="{
|
||||||
color: value.moneyColor,
|
color: value.moneyColor,
|
||||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-2.png') + ')',
|
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-2.png') + ')',
|
||||||
@@ -250,7 +250,7 @@
|
|||||||
<scroll-view class="coupon-style-seven" scroll-x="true">
|
<scroll-view class="coupon-style-seven" scroll-x="true">
|
||||||
<view class="wrap">
|
<view class="wrap">
|
||||||
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index"
|
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index"
|
||||||
@click="couponAction(item, index)">
|
@tap.stop="couponAction(item, index)">
|
||||||
<image :src="$util.img('public/uniapp/coupon/style7_bg.png')"></image>
|
<image :src="$util.img('public/uniapp/coupon/style7_bg.png')"></image>
|
||||||
<view class="coupon">
|
<view class="coupon">
|
||||||
<view class="coupon-info">
|
<view class="coupon-info">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view data-component-name="diy-fenxiao-goods-list" class="diy-fenxiao" v-if="list.length"
|
<view data-component-name="diy-fenxiao-goods-list" class="diy-fenxiao" v-if="list.length"
|
||||||
:class="['goods-list', value.template, value.style]" :style="goodsListWarpCss">
|
:class="['goods-list', value.template, value.style]" :style="goodsListWarpCss">
|
||||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :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 + ')' : '',
|
background: value.btnStyle.theme == 'diy' ? 'linear-gradient(to right,' + value.btnStyle.bgColorStart + ',' + value.btnStyle.bgColorEnd + ')' : '',
|
||||||
color: value.btnStyle.theme == 'diy' ? value.btnStyle.textColor : '',
|
color: value.btnStyle.theme == 'diy' ? value.btnStyle.textColor : '',
|
||||||
borderRadius: value.btnStyle.aroundRadius * 2 + 'rpx'
|
borderRadius: value.btnStyle.aroundRadius * 2 + 'rpx'
|
||||||
}" @click.stop="followGoods(item, index)">
|
}" @tap.stop="followGoods(item, index)">
|
||||||
关注
|
关注
|
||||||
</view>
|
</view>
|
||||||
<view class="sale-btn" v-if="value.btnStyle.control && item.is_collect == 1" :style="{
|
<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 + ')' : '',
|
background: value.btnStyle.theme == 'diy' ? 'linear-gradient(to right,' + value.btnStyle.bgColorStart + ',' + value.btnStyle.bgColorEnd + ')' : '',
|
||||||
color: value.btnStyle.theme == 'diy' ? value.btnStyle.textColor : '',
|
color: value.btnStyle.theme == 'diy' ? value.btnStyle.textColor : '',
|
||||||
borderRadius: value.btnStyle.aroundRadius * 2 + 'rpx'
|
borderRadius: value.btnStyle.aroundRadius * 2 + 'rpx'
|
||||||
}" @click.stop="delFollowTip(item, index)">
|
}" @tap.stop="delFollowTip(item, index)">
|
||||||
取消关注
|
取消关注
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -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 }"
|
:class="{ left_top: value.bottomPosition == 1, right_top: value.bottomPosition == 2, left_bottom: value.bottomPosition == 3, right_bottom: value.bottomPosition == 4 }"
|
||||||
:style="style">
|
:style="style">
|
||||||
<block v-for="(item, index) in value.list" :key="index">
|
<block v-for="(item, index) in value.list" :key="index">
|
||||||
<view class="button-box" @click="$util.diyRedirectTo(item.link)"
|
<view class="button-box" @tap.stop="$util.diyRedirectTo(item.link)"
|
||||||
:style="{ width: value.imageSize + 'px', height: value.imageSize + 'px', fontSize: value.imageSize + 'px' }">
|
: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"
|
<image v-if="!item.iconType || item.iconType == 'img'" :src="$util.img(item.imageUrl)" mode="aspectFit"
|
||||||
:show-menu-by-longpress="true" />
|
:show-menu-by-longpress="true" />
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view @click="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
|
<view @tap.stop="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<view class="ul-wrap">
|
<view class="ul-wrap">
|
||||||
<view class="li-item" v-for="(item, index) in list" :key="index">
|
<view class="li-item" v-for="(item, index) in list" :key="index">
|
||||||
<image class="brand-pic" :src="$util.img(item.image_url)" mode="aspectFit"
|
<image class="brand-pic" :src="$util.img(item.image_url)" mode="aspectFit"
|
||||||
@click="handlerClick(item)" @tap="handlerClick(item)" @error="imgError(index)"
|
@tap.stop="handlerClick(item)" @error="imgError(index)"
|
||||||
:style="itemCss" />
|
:style="itemCss" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
<x-skeleton data-component-name="diy-goods-list" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
<x-skeleton data-component-name="diy-goods-list" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
||||||
<view :class="['goods-list', goodsValue.template, goodsValue.style]" :style="goodsListWarpCss">
|
<view :class="['goods-list', goodsValue.template, goodsValue.style]" :style="goodsListWarpCss">
|
||||||
<template v-if="goodsValue.template != 'horizontal-slide'">
|
<template v-if="goodsValue.template != 'horizontal-slide'">
|
||||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
|
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
|
||||||
@tap="handlerClick(item)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="goods-img-wrap">
|
<view class="goods-img-wrap">
|
||||||
<image class="goods-img"
|
<image class="goods-img"
|
||||||
:src="$util.img(item.goods_image, { size: goodsValue.template == 'large-mode' ? 'big' : 'mid' })"
|
:src="$util.img(item.goods_image, { size: goodsValue.template == 'large-mode' ? 'big' : 'mid' })"
|
||||||
mode="widthFix" @error="imgError(index)"
|
mode="widthFix" @error="imgError(index)"
|
||||||
:style="{ borderRadius: goodsValue.imgAroundRadius * 2 + 'rpx' }" />
|
:style="{ borderRadius: goodsValue.imgAroundRadius * 2 + 'rpx' }"
|
||||||
|
:show-menu-by-longpress="true" />
|
||||||
<view class="sell-out" v-if="item.stock <= 0">
|
<view class="sell-out" v-if="item.stock <= 0">
|
||||||
<text class="iconfont icon-shuqing"></text>
|
<text class="iconfont icon-shuqing"></text>
|
||||||
</view>
|
</view>
|
||||||
@@ -70,7 +71,7 @@
|
|||||||
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : '',
|
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : '',
|
||||||
borderColor: 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"
|
}" class="cart shopping-cart-btn iconfont icon-gouwuche click-wrap" :id="'goods-' + item.id"
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -79,7 +80,7 @@
|
|||||||
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : '',
|
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : '',
|
||||||
borderColor: 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"
|
}" class="cart plus-sign-btn iconfont icon-add1 click-wrap" :id="'goods-' + item.id"
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@
|
|||||||
fontWeight: goodsValue.btnStyle.theme == 'diy' ? (goodsValue.btnStyle.fontWeight ? 'bold' : 'normal') : '',
|
fontWeight: goodsValue.btnStyle.theme == 'diy' ? (goodsValue.btnStyle.fontWeight ? 'bold' : 'normal') : '',
|
||||||
padding: goodsValue.btnStyle.theme == 'diy' ? '0 ' + goodsValue.btnStyle.padding * 2 + 'rpx' : ''
|
padding: goodsValue.btnStyle.theme == 'diy' ? '0 ' + goodsValue.btnStyle.padding * 2 + 'rpx' : ''
|
||||||
}" class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
}" class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||||
{{ goodsValue.btnStyle.text }}
|
{{ goodsValue.btnStyle.text }}
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
<!-- <text class="cart-num" v-if="cartList['goods_' + item.goods_id]">{{ cartList['goods_' + item.goods_id].num }}</text> -->
|
<!-- <text class="cart-num" v-if="cartList['goods_' + item.goods_id]">{{ cartList['goods_' + item.goods_id].num }}</text> -->
|
||||||
@@ -100,7 +101,7 @@
|
|||||||
<view v-else-if="goodsValue.btnStyle.style == 'icon-diy'" :style="{
|
<view v-else-if="goodsValue.btnStyle.style == 'icon-diy'" :style="{
|
||||||
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : ''
|
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : ''
|
||||||
}" class="icon-diy click-wrap" :id="'goods-' + item.id"
|
}" class="icon-diy click-wrap" :id="'goods-' + item.id"
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
<diy-icon :icon="goodsValue.btnStyle.iconDiy.icon"
|
<diy-icon :icon="goodsValue.btnStyle.iconDiy.icon"
|
||||||
:value="goodsValue.btnStyle.iconDiy.style ? goodsValue.btnStyle.iconDiy.style : null"></diy-icon>
|
:value="goodsValue.btnStyle.iconDiy.style ? goodsValue.btnStyle.iconDiy.style : null"></diy-icon>
|
||||||
@@ -112,12 +113,12 @@
|
|||||||
</template>
|
</template>
|
||||||
<scroll-view v-if="goodsValue.template == 'horizontal-slide' && goodsValue.slideMode == 'scroll'"
|
<scroll-view v-if="goodsValue.template == 'horizontal-slide' && goodsValue.slideMode == 'scroll'"
|
||||||
class="scroll" :scroll-x="true">
|
class="scroll" :scroll-x="true">
|
||||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
|
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
|
||||||
@tap="handlerClick(item)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="goods-img-wrap">
|
<view class="goods-img-wrap">
|
||||||
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)"
|
||||||
:lazy-load="true" />
|
:lazy-load="true" :show-menu-by-longpress="true" />
|
||||||
<view class="sell-out" v-if="item.stock <= 0">
|
<view class="sell-out" v-if="item.stock <= 0">
|
||||||
<text class="iconfont icon-shuqing"></text>
|
<text class="iconfont icon-shuqing"></text>
|
||||||
</view>
|
</view>
|
||||||
@@ -179,12 +180,12 @@
|
|||||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
: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"
|
<view class="goods-item" v-for="(dataItem, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||||
@click="handlerClick(dataItem)" @tap="handlerClick(dataItem)"
|
@tap.stop="handlerClick(dataItem)"
|
||||||
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="goods-img-wrap">
|
<view class="goods-img-wrap">
|
||||||
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
@error="imgError(dataIndex)" :lazy-load="true" />
|
@error="imgError(dataIndex)" :lazy-load="true" :show-menu-by-longpress="true" />
|
||||||
<view class="sell-out" v-if="dataItem.stock <= 0">
|
<view class="sell-out" v-if="dataItem.stock <= 0">
|
||||||
<text class="iconfont icon-shuqing"></text>
|
<text class="iconfont icon-shuqing"></text>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
<swiper-item v-for="(item, index) in page" :key="index"
|
<swiper-item v-for="(item, index) in page" :key="index"
|
||||||
:class="['swiper-item', [list[index].length / 3] >= 1 && 'flex-between']">
|
:class="['swiper-item', [list[index].length / 3] >= 1 && 'flex-between']">
|
||||||
<view class="goods-item" v-for="(dataItem, dataIndex) in list[index]" :key="dataIndex"
|
<view class="goods-item" v-for="(dataItem, dataIndex) in list[index]" :key="dataIndex"
|
||||||
@click="toDetail(dataItem)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
@tap.stop="toDetail(dataItem)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||||
<div class="goods-img-wrap">
|
<div class="goods-img-wrap">
|
||||||
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
@error="imgError(index, dataIndex)" :lazy-load="true" />
|
@error="imgError(index, dataIndex)" :lazy-load="true" :show-menu-by-longpress="true" />
|
||||||
<view class="sell-out" v-if="dataItem.stock <= 0">
|
<view class="sell-out" v-if="dataItem.stock <= 0">
|
||||||
<text class="iconfont icon-shuqing"></text>
|
<text class="iconfont icon-shuqing"></text>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
|
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
|
||||||
:key="index"
|
:key="index"
|
||||||
v-if="index >= [(numItem) * (value.pageCount * value.rowCount)] && index < [(numItem + 1) * (value.pageCount * value.rowCount)]"
|
v-if="index >= [(numItem) * (value.pageCount * value.rowCount)] && index < [(numItem + 1) * (value.pageCount * value.rowCount)]"
|
||||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<!-- #ifdef H5 -->
|
<!-- #ifdef H5 -->
|
||||||
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
|
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
|
||||||
:key="index"
|
:key="index"
|
||||||
v-if="index >= [(numItem - 1) * (value.pageCount * value.rowCount)] && index < [numItem * (value.pageCount * value.rowCount)]"
|
v-if="index >= [(numItem - 1) * (value.pageCount * value.rowCount)] && index < [numItem * (value.pageCount * value.rowCount)]"
|
||||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<view class="graphic-img" v-if="value.mode != 'text'"
|
<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' }">
|
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
|
|
||||||
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list" :key="index"
|
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list" :key="index"
|
||||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
|
||||||
<view class="graphic-img" v-if="value.mode != 'text'"
|
<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' }">
|
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
|
||||||
<image v-if="item.iconType == 'img'"
|
<image v-if="item.iconType == 'img'"
|
||||||
|
|||||||
@@ -251,6 +251,11 @@
|
|||||||
<diy-icon :value="item"></diy-icon>
|
<diy-icon :value="item"></diy-icon>
|
||||||
</template>
|
</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)">
|
<template v-if="['ChannelList', 'WechatChannel'].includes(item.componentName)">
|
||||||
<!-- 视频号列表 -->
|
<!-- 视频号列表 -->
|
||||||
<diy-channel-list :value="item"></diy-channel-list>
|
<diy-channel-list :value="item"></diy-channel-list>
|
||||||
@@ -267,6 +272,7 @@
|
|||||||
import DiyMinx from './minx.js'
|
import DiyMinx from './minx.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'diy-group',
|
||||||
props: {
|
props: {
|
||||||
diyData: {
|
diyData: {
|
||||||
type: Object
|
type: Object
|
||||||
@@ -311,7 +317,12 @@ export default {
|
|||||||
this.diyGlobalData.value.forEach((item, index) => {
|
this.diyGlobalData.value.forEach((item, index) => {
|
||||||
item.pageStyle = '';
|
item.pageStyle = '';
|
||||||
// 给每个组件增加位置属性,用于定位,搜索、分类导航等定位
|
// 给每个组件增加位置属性,用于定位,搜索、分类导航等定位
|
||||||
item.moduleIndex = index + 1;
|
// 如果是Tab组件内部的子组件,添加tabIndex前缀避免moduleIndex冲突
|
||||||
|
if (this.diyData.tabIndex !== undefined) {
|
||||||
|
item.moduleIndex = `${this.diyData.tabIndex}-${index + 1}`;
|
||||||
|
} else {
|
||||||
|
item.moduleIndex = index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
// 特殊处理搜索框 当显示位置为滚动至顶部固定时,只设置背景颜色
|
// 特殊处理搜索框 当显示位置为滚动至顶部固定时,只设置背景颜色
|
||||||
if (item.componentName == 'Search' && item.positionWay == 'fixed') {
|
if (item.componentName == 'Search' && item.positionWay == 'fixed') {
|
||||||
@@ -346,6 +357,12 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else data = this.setPagestyle;
|
} else data = this.setPagestyle;
|
||||||
|
|
||||||
|
console.log(`diy-group ['diyDataArray'] = `, {
|
||||||
|
data: data,
|
||||||
|
diyData: this.diyData,
|
||||||
|
diyGlobalData: this.diyGlobalData,
|
||||||
|
})
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<x-skeleton data-component-name="diy-groupbuy" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
<x-skeleton data-component-name="diy-groupbuy" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
||||||
<view class="diy-groupbuy" :class="[value.template, value.style]" :style="warpCss">
|
<view class="diy-groupbuy" :class="[value.template, value.style]" :style="warpCss">
|
||||||
<template v-if="value.template == 'row1-of1'">
|
<template v-if="value.template == 'row1-of1'">
|
||||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-if="value.template == 'horizontal-slide'">
|
<template v-if="value.template == 'horizontal-slide'">
|
||||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
<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" @click="toDetail(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :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"
|
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||||
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
height: mapItem.height + '%',
|
height: mapItem.height + '%',
|
||||||
left: mapItem.left + '%',
|
left: mapItem.left + '%',
|
||||||
top: mapItem.top + '%'
|
top: mapItem.top + '%'
|
||||||
}" @click.stop="$util.diyRedirectTo(mapItem.link)"></view>
|
}" @tap.stop="$util.diyRedirectTo(mapItem.link)"></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
'width': (item.imgWidth / 2 + 'rpx') + ';',
|
'width': (item.imgWidth / 2 + 'rpx') + ';',
|
||||||
'height': (item.imgHeight / 2 + 'rpx') + ';'
|
'height': (item.imgHeight / 2 + 'rpx') + ';'
|
||||||
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
|
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
|
||||||
:show-menu-by-longpress="true" @tap="redirectTo(item.link)"></image>
|
:show-menu-by-longpress="true" @tap.stop="redirectTo(item.link)"></image>
|
||||||
<image v-else :style="{
|
<image v-else :style="{
|
||||||
'width': (item.imgWidth / 2 + 'rpx') + ';',
|
'width': (item.imgWidth / 2 + 'rpx') + ';',
|
||||||
'height': (item.imgHeight / 2 + 'rpx') + ';'
|
'height': (item.imgHeight / 2 + 'rpx') + ';'
|
||||||
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
|
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
|
||||||
:show-menu-by-longpress="true" @tap="previewImg(item.imageUrl)"></image>
|
:show-menu-by-longpress="true" @tap.stop="previewImg(item.imageUrl)"></image>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 文字部分 -->
|
<!-- 文字部分 -->
|
||||||
@@ -103,17 +103,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 预览图片
|
|
||||||
previewImg(imageUrl) {
|
|
||||||
uni.previewImage({
|
|
||||||
current: 0,
|
|
||||||
urls: [this.$util.img(imageUrl)],
|
|
||||||
success: (res) => { },
|
|
||||||
fail: (res) => { },
|
|
||||||
complete: (res) => { }
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 页面跳转
|
// 页面跳转
|
||||||
redirectTo(link) {
|
redirectTo(link) {
|
||||||
if (!link.wap_url || this.$util.getCurrRoute() != this.$util.MEMBER_PAGE_URL || this.storeToken) {
|
if (!link.wap_url || this.$util.getCurrRoute() != this.$util.MEMBER_PAGE_URL || this.storeToken) {
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
<view data-component-name="diy-img-ads" class="single-graph">
|
<view data-component-name="diy-img-ads" class="single-graph">
|
||||||
<view :style="imgAdsMarginWarp" class="swiper-box">
|
<view :style="imgAdsMarginWarp" class="swiper-box">
|
||||||
<block v-if="imgAdsValue.list.length == 1">
|
<block v-if="imgAdsValue.list.length == 1">
|
||||||
<view class="simple-graph-wrap" :style="imgAdsSwiper" @click="handlerClick(imgAdsValue.list[0].link)"
|
<view class="simple-graph-wrap" :style="imgAdsSwiper" @tap.stop="handlerClick(imgAdsValue.list[0].link)">
|
||||||
@tap="handlerClick(imgAdsValue.list[0].link)">
|
|
||||||
<image :style="{ height: imgAdsValue.list[0].imgHeight }"
|
<image :style="{ height: imgAdsValue.list[0].imgHeight }"
|
||||||
:src="$util.img(imgAdsValue.list[0].imageUrl)" mode="widthFix" :show-menu-by-longpress="true" />
|
:src="$util.img(imgAdsValue.list[0].imageUrl)" mode="widthFix" :show-menu-by-longpress="true" />
|
||||||
</view>
|
</view>
|
||||||
@@ -16,7 +15,7 @@
|
|||||||
indicator-color="rgba(130, 130, 130, .5)" :indicator-active-color="imgAdsValue.indicatorColor"
|
indicator-color="rgba(130, 130, 130, .5)" :indicator-active-color="imgAdsValue.indicatorColor"
|
||||||
@change="swiperChange">
|
@change="swiperChange">
|
||||||
<swiper-item class="swiper-item" :style="imgAdsSwiper" v-for="(item, index) in imgAdsValue.list"
|
<swiper-item class="swiper-item" :style="imgAdsSwiper" v-for="(item, index) in imgAdsValue.list"
|
||||||
:key="index" v-if="item.imageUrl" @click="handlerClick(item.link)" @tap="handlerClick(item.link)">
|
:key="index" v-if="item.imageUrl" @tap.stop="handlerClick(item.link)">
|
||||||
<view class="item" :style="imgAdsSwiper + 'height: ' + item.imgHeight">
|
<view class="item" :style="imgAdsSwiper + 'height: ' + item.imgHeight">
|
||||||
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
||||||
:show-menu-by-longpress="true" />
|
:show-menu-by-longpress="true" />
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
:style="{ background: value.backgroundColor ? value.backgroundColor : '', width: 'calc(100% - 48rpx)' }"
|
:style="{ background: value.backgroundColor ? value.backgroundColor : '', width: 'calc(100% - 48rpx)' }"
|
||||||
@touchmove.stop>
|
@touchmove.stop>
|
||||||
<view class="item" :id="'a' + index" v-for="(item, index) in cateList" :key="index"
|
<view class="item" :id="'a' + index" v-for="(item, index) in cateList" :key="index"
|
||||||
@click="changePageIndex(index)" :class="{ fill: value.styleType == 'fill' }"
|
@tap.stop="changePageIndex(index)" :class="{ fill: value.styleType == 'fill' }"
|
||||||
:style="{ background: index == pageIndex && value.styleType == 'fill' ? value.selectColor : '' }">
|
:style="{ background: index == pageIndex && value.styleType == 'fill' ? value.selectColor : '' }">
|
||||||
<view class="text-con" :class="index == pageIndex ? 'active' : ''" :style="{
|
<view class="text-con" :class="index == pageIndex ? 'active' : ''" :style="{
|
||||||
color: index == pageIndex ? '' : value.noColor
|
color: index == pageIndex ? '' : value.noColor
|
||||||
@@ -25,13 +25,13 @@
|
|||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<text class="iconfont icon-unfold unfold-arrows" :style="{ color: value.moreColor }"
|
<text class="iconfont icon-unfold unfold-arrows" :style="{ color: value.moreColor }"
|
||||||
@click="unfoldMenu"></text>
|
@tap.stop="unfoldMenu"></text>
|
||||||
</view>
|
</view>
|
||||||
<uni-popup ref="navTopCategoryPop" type="top" :top="uniPopTop">
|
<uni-popup ref="navTopCategoryPop" type="top" :top="uniPopTop">
|
||||||
<view class="nav-topcategory-pop">
|
<view class="nav-topcategory-pop">
|
||||||
<text v-for="(item, index) in cateList" :key="index"
|
<text v-for="(item, index) in cateList" :key="index"
|
||||||
:class="['category-item', { 'color-base-text color-base-border active': pageIndex == index }]"
|
:class="['category-item', { 'color-base-text color-base-border active': pageIndex == index }]"
|
||||||
@click="changePageIndex(index)">
|
@tap.stop="changePageIndex(index)">
|
||||||
{{ item.short_name ? item.short_name : item.category_name }}
|
{{ item.short_name ? item.short_name : item.category_name }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
<view class="twoCategory min" v-if="twoCategorylist.length <= 5">
|
<view class="twoCategory min" v-if="twoCategorylist.length <= 5">
|
||||||
<view class="twoCategory-page">
|
<view class="twoCategory-page">
|
||||||
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
||||||
:key="index" @click="toCateGoodsList(item.category_id_2, 2)">
|
:key="index" @tap.stop="toCateGoodsList(item.category_id_2, 2)">
|
||||||
<view class="item-box">
|
<view class="item-box">
|
||||||
<image :src="$util.img(item.image)" v-if="item.image"
|
<image :src="$util.img(item.image)" v-if="item.image"
|
||||||
mode="aspectFill" />
|
mode="aspectFill" />
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
v-if="twoCategorylist.length > 5 && twoCategorylist.length <= 10">
|
v-if="twoCategorylist.length > 5 && twoCategorylist.length <= 10">
|
||||||
<view class="twoCategory-page">
|
<view class="twoCategory-page">
|
||||||
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
||||||
:key="index" @click="toCateGoodsList(item.category_id_2, 2)">
|
:key="index" @tap.stop="toCateGoodsList(item.category_id_2, 2)">
|
||||||
<view class="item-box">
|
<view class="item-box">
|
||||||
<image :src="$util.img(item.image)" v-if="item.image"
|
<image :src="$util.img(item.image)" v-if="item.image"
|
||||||
mode="aspectFill" />
|
mode="aspectFill" />
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
<swiper-item class="twoCategory-page" v-for="page in maxPage" :key="page">
|
<swiper-item class="twoCategory-page" v-for="page in maxPage" :key="page">
|
||||||
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
|
||||||
:key="index" v-if="index >= (page - 1) * 10 && index < page * 10"
|
:key="index" v-if="index >= (page - 1) * 10 && index < page * 10"
|
||||||
@click="toCateGoodsList(item.category_id_2, 2)">
|
@tap.stop="toCateGoodsList(item.category_id_2, 2)">
|
||||||
<view class="item-box">
|
<view class="item-box">
|
||||||
<image :src="item.image" mode="aspectFill" />
|
<image :src="item.image" mode="aspectFill" />
|
||||||
<view>{{ item.category_name }}</view>
|
<view>{{ item.category_name }}</view>
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
<view class="goods-list double-column" v-if="goodsList[pageIndex].list.length">
|
<view class="goods-list double-column" v-if="goodsList[pageIndex].list.length">
|
||||||
<view class="goods-item" v-for="(item, index) in goodsList[pageIndex].list"
|
<view class="goods-item" v-for="(item, index) in goodsList[pageIndex].list"
|
||||||
:key="index" @click="toDetail(item)">
|
:key="index" @tap.stop="toDetail(item)">
|
||||||
<view class="goods-img">
|
<view class="goods-img">
|
||||||
<image :src="goodsImg(item.goods_image)" mode="widthFix"
|
<image :src="goodsImg(item.goods_image)" mode="widthFix"
|
||||||
@error="imgError(index)" />
|
@error="imgError(index)" />
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="fui-remark jump" style="padding-right: 20rpx; text-align: center; line-height: 140rpx;">
|
<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"
|
<span style="font-size:24rpx;padding: 14rpx 18rpx;border-radius:8rpx"
|
||||||
:style="{ background: item.BtBgColor, color: item.BtColor }" @click="previewSqs()">立即添加</span>
|
:style="{ background: item.BtBgColor, color: item.BtColor }" @tap.stop="previewSqs()">立即添加</span>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<view class="fui-cell-group">
|
<view class="fui-cell-group">
|
||||||
<!-- <image mode="widthFix" style="width: 100%;" :src="$util.img(item.imageUrl)"></image> -->
|
<!-- <image mode="widthFix" style="width: 100%;" :src="$util.img(item.imageUrl)"></image> -->
|
||||||
|
|
||||||
<view v-for="(item, index) in value.list" @click="redirectTo(item.link)" class="fui-cell"
|
<view v-for="(item, index) in value.list" @tap.stop="redirectTo(item.link)" class="fui-cell"
|
||||||
:class="item.iconType == 'img' ? 'img-cell' : ''">
|
:class="item.iconType == 'img' ? 'img-cell' : ''">
|
||||||
<view class="fui-cell-icon" :style="{ 'color': item.style ? item.style.iconColor : '#333' }">
|
<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"
|
<diy-icon v-if="item.iconType == 'icon'" :icon="item.icon" :value="item.style ? item.style : null"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<x-skeleton data-component-name="diy-live" type="banner" :loading="loading" :configs="skeletonConfig">
|
<x-skeleton data-component-name="diy-live" type="banner" :loading="loading" :configs="skeletonConfig">
|
||||||
<view class="live-wrap" @click="handlerClick(liveInfo.roomid)" @tap="handlerClick(liveInfo.roomid)"
|
<view class="live-wrap" @tap.stop="handlerClick(liveInfo.roomid)"
|
||||||
v-if="liveInfo">
|
v-if="liveInfo">
|
||||||
<view class="banner-wrap">
|
<view class="banner-wrap">
|
||||||
<image
|
<image
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<scroll-view scroll-x="true" class="many-goods-list-head" :scroll-into-view="'a' + cateIndex"
|
<scroll-view scroll-x="true" class="many-goods-list-head" :scroll-into-view="'a' + cateIndex"
|
||||||
:style="manyWrapCss">
|
:style="manyWrapCss">
|
||||||
<view v-for="(item, index) in value.list" class="scroll-item" :class="{ active: index == cateIndex }"
|
<view v-for="(item, index) in value.list" class="scroll-item" :class="{ active: index == cateIndex }"
|
||||||
:id="'a' + index" :key="index" @click="handlerClick({ item, index })" @tap="handlerClick({ item, index })">
|
:id="'a' + index" :key="index" @tap.stop="handlerClick({ item, index })">
|
||||||
<view class="split-line" v-if="index > 0"></view>
|
<view class="split-line" v-if="index > 0"></view>
|
||||||
<view class="cate">
|
<view class="cate">
|
||||||
<view class="name" :style="{ color: value.headStyle.titleColor }">{{ item.title }}</view>
|
<view class="name" :style="{ color: value.headStyle.titleColor }">{{ item.title }}</view>
|
||||||
|
|||||||
@@ -3,11 +3,18 @@
|
|||||||
<view class="fui-list-group merchgroup" style="margin-top:0" v-for="(item, index) in value.list">
|
<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"
|
<map id="map" style="width: 100%; height:600rpx" scale="12" :markers="markerst" bindupdated="bindupdated"
|
||||||
:longitude="item.lng" :latitude="item.lat" show-location>
|
: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;"
|
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;"
|
||||||
@click="handlerClick(item)" @tap="handlerClick(item)">
|
@tap.stop="handlerClick(item)" @tap="handlerClick(item)">
|
||||||
<cover-view style="font-size:24rpx">一键导航</cover-view>
|
<cover-view style="font-size:24rpx">一键导航</cover-view>
|
||||||
</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>
|
||||||
</map>
|
</map>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<view class="common-wrap info-wrap" :class="[`data-style-${value.style}`]">
|
<view class="common-wrap info-wrap" :class="[`data-style-${value.style}`]">
|
||||||
<view class="member-info" :style="memberInfoStyle">
|
<view class="member-info" :style="memberInfoStyle">
|
||||||
<view class="info-wrap" :style="infoStyle" v-if="memberInfo">
|
<view class="info-wrap" :style="infoStyle" v-if="memberInfo">
|
||||||
<view class="headimg" @click="getWxAuth">
|
<view class="headimg" @tap.stop="getWxAuth">
|
||||||
<image :src="memberInfo.headimg ? $util.img(memberInfo.headimg) : $util.getDefaultImage().head"
|
<image :src="memberInfo.headimg ? $util.img(memberInfo.headimg) : $util.getDefaultImage().head"
|
||||||
mode="widthFix" @error="memberInfo.headimg = $util.getDefaultImage().head" />
|
mode="widthFix" @error="memberInfo.headimg = $util.getDefaultImage().head" />
|
||||||
</view>
|
</view>
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
<!-- #ifdef MP -->
|
<!-- #ifdef MP -->
|
||||||
<block
|
<block
|
||||||
v-if="(memberInfo.nickname.indexOf('u_') != -1 && memberInfo.nickname == memberInfo.username) || memberInfo.nickname == memberInfo.mobile">
|
v-if="(memberInfo.nickname.indexOf('u_') != -1 && memberInfo.nickname == memberInfo.username) || memberInfo.nickname == memberInfo.mobile">
|
||||||
<view class="nickname"><text class="name" @click="getWxAuth">点击授权头像昵称</text></view>
|
<view class="nickname"><text class="name" @tap.stop="getWxAuth">点击授权头像昵称</text></view>
|
||||||
</block>
|
</block>
|
||||||
<view class="nickname" v-else>
|
<view class="nickname" v-else>
|
||||||
<text class="name" @click="getWxAuth">{{ memberInfo.nickname }}</text>
|
<text class="name" @tap.stop="getWxAuth">{{ memberInfo.nickname }}</text>
|
||||||
<view class="member-level"
|
<view class="member-level"
|
||||||
v-if="(value.style == 1 || value.style == 2) && memberInfo.member_level">
|
v-if="(value.style == 1 || value.style == 2) && memberInfo.member_level">
|
||||||
<!-- <text class="icondiy icon-system-huangguan"></text> -->
|
<!-- <text class="icondiy icon-system-huangguan"></text> -->
|
||||||
@@ -36,10 +36,10 @@
|
|||||||
<!-- #ifdef H5 -->
|
<!-- #ifdef H5 -->
|
||||||
<block
|
<block
|
||||||
v-if="$util.isWeiXin() && ((memberInfo.nickname.indexOf('u_') != -1 && memberInfo.nickname == memberInfo.username) || memberInfo.nickname == memberInfo.mobile)">
|
v-if="$util.isWeiXin() && ((memberInfo.nickname.indexOf('u_') != -1 && memberInfo.nickname == memberInfo.username) || memberInfo.nickname == memberInfo.mobile)">
|
||||||
<view class="nickname"><text class="name" @click="getWxAuth">点击获取微信头像</text></view>
|
<view class="nickname"><text class="name" @tap.stop="getWxAuth">点击获取微信头像</text></view>
|
||||||
</block>
|
</block>
|
||||||
<view class="nickname" v-else>
|
<view class="nickname" v-else>
|
||||||
<text class="name" @click="redirect('/pages_tool/member/info')">{{ memberInfo.nickname
|
<text class="name" @tap.stop="redirect('/pages_tool/member/info')">{{ memberInfo.nickname
|
||||||
}}</text>
|
}}</text>
|
||||||
<view class="member-level"
|
<view class="member-level"
|
||||||
v-if="(value.style == 1 || value.style == 2) && memberInfo.member_level">
|
v-if="(value.style == 1 || value.style == 2) && memberInfo.member_level">
|
||||||
@@ -61,10 +61,10 @@
|
|||||||
</view>
|
</view>
|
||||||
<view v-if="ischina == 1"
|
<view v-if="ischina == 1"
|
||||||
style="background: #fff;height: 60rpx;width: 60rpx;border-radius: 50rpx;line-height:65rpx;text-align: center;color:#000"
|
style="background: #fff;height: 60rpx;width: 60rpx;border-radius: 50rpx;line-height:65rpx;text-align: center;color:#000"
|
||||||
@click.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
|
@tap.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="info-wrap" v-else :style="infoStyle" @click="redirect($util.MEMBER_PAGE_URL)">
|
<view class="info-wrap" v-else :style="infoStyle" @tap.stop="redirect($util.MEMBER_PAGE_URL)">
|
||||||
<view class="headimg">
|
<view class="headimg">
|
||||||
<image :src="$util.getDefaultImage().head" mode="widthFix"></image>
|
<image :src="$util.getDefaultImage().head" mode="widthFix"></image>
|
||||||
</view>
|
</view>
|
||||||
@@ -75,12 +75,12 @@
|
|||||||
|
|
||||||
<view v-if="ischina == 1"
|
<view v-if="ischina == 1"
|
||||||
style="background: #fff;height: 60rpx;width: 60rpx;border-radius: 50rpx;line-height:65rpx;text-align: center;color:#000"
|
style="background: #fff;height: 60rpx;width: 60rpx;border-radius: 50rpx;line-height:65rpx;text-align: center;color:#000"
|
||||||
@click.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
|
@tap.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="account-info" v-show="value.style == 1"
|
<view class="account-info" v-show="value.style == 1"
|
||||||
:style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
:style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/balance')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance')">
|
||||||
<view class="value price-font">
|
<view class="value price-font">
|
||||||
{{ memberInfo ? (parseFloat(memberInfo.balance) +
|
{{ memberInfo ? (parseFloat(memberInfo.balance) +
|
||||||
parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}
|
parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}
|
||||||
@@ -88,12 +88,12 @@
|
|||||||
<view class="title">{{ $lang('balance') }}</view>
|
<view class="title">{{ $lang('balance') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="solid"></view>
|
<view class="solid"></view>
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
|
||||||
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}</view>
|
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}</view>
|
||||||
<view class="title">{{ $lang('point') }}</view>
|
<view class="title">{{ $lang('point') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="solid"></view>
|
<view class="solid"></view>
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
|
||||||
<view class="value price-font">
|
<view class="value price-font">
|
||||||
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
||||||
</view>
|
</view>
|
||||||
@@ -110,8 +110,8 @@
|
|||||||
<text>超级会员</text>
|
<text>超级会员</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="super-text">
|
<view class="super-text">
|
||||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
|
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
|
||||||
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">会员可享更多权益</text>
|
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">会员可享更多权益</text>
|
||||||
<text class="iconfont icon-right"></text>
|
<text class="iconfont icon-right"></text>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
@@ -121,8 +121,8 @@
|
|||||||
<view class="desc">开通可享更多权益</view>
|
<view class="desc">开通可享更多权益</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="super-text">
|
<view class="super-text">
|
||||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
|
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
|
||||||
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
|
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
</view>
|
</view>
|
||||||
@@ -134,25 +134,25 @@
|
|||||||
<view class="desc">开通可享更多权益</view>
|
<view class="desc">开通可享更多权益</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="super-text" :class="{ 'more' : memberInfo && memberInfo.member_level_type }">
|
<view class="super-text" :class="{ 'more' : memberInfo && memberInfo.member_level_type }">
|
||||||
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看更多权益</text>
|
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看更多权益</text>
|
||||||
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
|
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="account-info" :style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
<view class="account-info" :style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/balance_detail')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance_detail')">
|
||||||
<view class="value price-font">
|
<view class="value price-font">
|
||||||
{{ memberInfo ? (parseFloat(memberInfo.balance) + parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}
|
{{ memberInfo ? (parseFloat(memberInfo.balance) + parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}
|
||||||
</view>
|
</view>
|
||||||
<view class="title">余额</view>
|
<view class="title">余额</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="solid"></view>
|
<view class="solid"></view>
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
|
||||||
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}
|
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}
|
||||||
</view>
|
</view>
|
||||||
<view class="title">积分</view>
|
<view class="title">积分</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="solid"></view>
|
<view class="solid"></view>
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
|
||||||
<view class="value price-font">
|
<view class="value price-font">
|
||||||
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
||||||
</view>
|
</view>
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="style4-other">
|
<view class="style4-other">
|
||||||
<view class="style4-btn-wrap">
|
<view class="style4-btn-wrap">
|
||||||
<view @click="redirect('/pages_tool/recharge/list')" class="recharge-btn">余额充值</view>
|
<view @tap.stop="redirect('/pages_tool/recharge/list')" class="recharge-btn">余额充值</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view> -->
|
</view> -->
|
||||||
@@ -169,18 +169,18 @@
|
|||||||
|
|
||||||
<view class="account-info" v-show="value.style == 2"
|
<view class="account-info" v-show="value.style == 2"
|
||||||
:style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
:style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/balance')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance')">
|
||||||
<view class="value price-font">{{ memberInfo ? (parseFloat(memberInfo.balance) +
|
<view class="value price-font">{{ memberInfo ? (parseFloat(memberInfo.balance) +
|
||||||
parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}</view>
|
parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}</view>
|
||||||
<view class="title">{{ $lang('balance') }}</view>
|
<view class="title">{{ $lang('balance') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="solid"></view>
|
<view class="solid"></view>
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
|
||||||
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}</view>
|
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}</view>
|
||||||
<view class="title">{{ $lang('point') }}</view>
|
<view class="title">{{ $lang('point') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="solid"></view>
|
<view class="solid"></view>
|
||||||
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
|
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
|
||||||
<view class="value price-font">
|
<view class="value price-font">
|
||||||
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
|
||||||
</view>
|
</view>
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
<view class="head">
|
<view class="head">
|
||||||
<text class="title">获取您的昵称、头像</text>
|
<text class="title">获取您的昵称、头像</text>
|
||||||
<text class="color-tip tips">获取用户头像、昵称完善个人资料,主要用于向用户提供具有辨识度的用户中心界面</text>
|
<text class="color-tip tips">获取用户头像、昵称完善个人资料,主要用于向用户提供具有辨识度的用户中心界面</text>
|
||||||
<text class="iconfont icon-close color-tip" @click="cancelCompleteInfo"></text>
|
<text class="iconfont icon-close color-tip" @tap.stop="cancelCompleteInfo"></text>
|
||||||
</view>
|
</view>
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
<view class="item-wrap">
|
<view class="item-wrap">
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
<input type="nickname" placeholder="请输入昵称" v-model="nickName" @blur="blurNickName" />
|
<input type="nickname" placeholder="请输入昵称" v-model="nickName" @blur="blurNickName" />
|
||||||
</view>
|
</view>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<button type="default" class="save-btn" @click="saveCompleteInfo" :disabled="isDisabled">保存</button>
|
<button type="default" class="save-btn" @tap.stop="saveCompleteInfo" :disabled="isDisabled">保存</button>
|
||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view data-component-name="diy-member-my-order" class="common-wrap" :style="warpCss">
|
<view data-component-name="diy-member-my-order" class="common-wrap" :style="warpCss">
|
||||||
<view class="order-wrap">
|
<view class="order-wrap">
|
||||||
<view class="status-wrap">
|
<view class="status-wrap">
|
||||||
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitpay')"
|
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitpay')"
|
||||||
style="margin-right: 10rpx;">
|
style="margin-right: 10rpx;">
|
||||||
<view class="icon-block">
|
<view class="icon-block">
|
||||||
<template v-if="value.style == 3">
|
<template v-if="value.style == 3">
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="title">{{ $lang('waitpay') }}</view>
|
<view class="title">{{ $lang('waitpay') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitsend')"
|
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitsend')"
|
||||||
style="margin-right: 10rpx;">
|
style="margin-right: 10rpx;">
|
||||||
<view class="icon-block">
|
<view class="icon-block">
|
||||||
<template v-if="value.style == 3">
|
<template v-if="value.style == 3">
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="title">{{ $lang('waitsend') }}</view>
|
<view class="title">{{ $lang('waitsend') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitconfirm')"
|
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitconfirm')"
|
||||||
style="margin-right: 10rpx;">
|
style="margin-right: 10rpx;">
|
||||||
<view class="icon-block">
|
<view class="icon-block">
|
||||||
<template v-if="value.style == 3">
|
<template v-if="value.style == 3">
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="title">{{ $lang('waitconfirm') }}</view>
|
<view class="title">{{ $lang('waitconfirm') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitrate')"
|
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitrate')"
|
||||||
style="margin-right: 10rpx;">
|
style="margin-right: 10rpx;">
|
||||||
<view class="icon-block">
|
<view class="icon-block">
|
||||||
<template v-if="value.style == 3">
|
<template v-if="value.style == 3">
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="title">{{ $lang('completed') }}</view>
|
<view class="title">{{ $lang('completed') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="item-wrap" @click="redirect('/pages_tool/order/activist')">
|
<view class="item-wrap" @tap.stop="redirect('/pages_tool/order/activist')">
|
||||||
<view class="icon-block">
|
<view class="icon-block">
|
||||||
<template v-if="value.style == 3">
|
<template v-if="value.style == 3">
|
||||||
<image :src="$util.img('public/uniapp/member/order/refunding.png')" mode="widthFix" />
|
<image :src="$util.img('public/uniapp/member/order/refunding.png')" mode="widthFix" />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<view class="merch-wrap" :style="warpCss">
|
<view class="merch-wrap" :style="warpCss">
|
||||||
<view :class="['list-wrap', value.style]" :style="warpCss">
|
<view :class="['list-wrap', value.style]" :style="warpCss">
|
||||||
<view :class="['item', value.ornament.type]" v-for="(item, index) in list" :key="index"
|
<view :class="['item', value.ornament.type]" v-for="(item, index) in list" :key="index"
|
||||||
:style="itemCss" @click="handlerClick(item)" @tap="handlerClick(item)">
|
:style="itemCss" @tap.stop="handlerClick(item)">
|
||||||
<view class="merch-img">
|
<view class="merch-img">
|
||||||
<image class="cover-img" :src="$util.img(item.merch_image)" mode="widthFix"
|
<image class="cover-img" :src="$util.img(item.merch_image)" mode="widthFix"
|
||||||
@error="imgError(index)" />
|
@error="imgError(index)" />
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
|
|
||||||
<view class="merch-nav-item graphic" v-for="(item, index) in list" :key="index"
|
<view class="merch-nav-item graphic" v-for="(item, index) in list" :key="index"
|
||||||
:style="{ width: 100 / 4 + '%' }" @click="handlerClick(item)" @tap="handlerClick(item)">
|
:style="{ width: 100 / 4 + '%' }" @tap.stop="handlerClick(item)">
|
||||||
<view class="graphic-img" v-if="value.mode != 'text'"
|
<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' }">
|
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
|
||||||
<image
|
<image
|
||||||
|
|||||||
@@ -3,13 +3,12 @@
|
|||||||
<view class="diy-notes" :style="{ backgroundColor: value.componentBgColor }">
|
<view class="diy-notes" :style="{ backgroundColor: value.componentBgColor }">
|
||||||
<view class="diy-notes-top">
|
<view class="diy-notes-top">
|
||||||
<view class="notes-title" :style="{ color: value.titleTextColor }">{{ value.title }}</view>
|
<view class="notes-title" :style="{ color: value.titleTextColor }">{{ value.title }}</view>
|
||||||
<view class="notes-more" @click="toMore()" :style="{ color: value.moreTextColor }">{{ value.more }}
|
<view class="notes-more" @tap.stop="toMore()" :style="{ color: value.moreTextColor }">{{ value.more }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view class="diy-notes-box" scroll-x="true" show-scrollbar="true">
|
<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" @click="handlerClick(item)"
|
<view class="notes-box-item" v-for="(item, i) in dataList" :key="i" @tap.stop="handlerClick(item)" :style="notesItemStyle">
|
||||||
@tap="handlerClick(item)" :style="notesItemStyle">
|
|
||||||
<view class="notes-item" v-if="item.status == 1">
|
<view class="notes-item" v-if="item.status == 1">
|
||||||
<view class="notes-item-con">
|
<view class="notes-item-con">
|
||||||
<view class="notes-title">{{ item.note_title }}</view>
|
<view class="notes-title">{{ item.note_title }}</view>
|
||||||
|
|||||||
@@ -41,12 +41,12 @@
|
|||||||
<view @touchmove.prevent.stop>
|
<view @touchmove.prevent.stop>
|
||||||
<uni-popup ref="noticePopup" type="center">
|
<uni-popup ref="noticePopup" type="center">
|
||||||
<view class="notice-popup">
|
<view class="notice-popup">
|
||||||
<view class="head-wrap" @click="closeNoticePopup">
|
<view class="head-wrap" @tap.stop="closeNoticePopup">
|
||||||
<text>公告</text>
|
<text>公告</text>
|
||||||
<text class="iconfont icon-close"></text>
|
<text class="iconfont icon-close"></text>
|
||||||
</view>
|
</view>
|
||||||
<view class="content-wrap">{{ notice }}</view>
|
<view class="content-wrap">{{ notice }}</view>
|
||||||
<button type="primary" @click="closeNoticePopup">我知道了</button>
|
<button type="primary" @tap.stop="closeNoticePopup">我知道了</button>
|
||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
<!-- <text class="iconfont icon-shuaxin"></text> -->
|
<!-- <text class="iconfont icon-shuaxin"></text> -->
|
||||||
</view>
|
</view>
|
||||||
<view class="qrocde-action">
|
<view class="qrocde-action">
|
||||||
<button type="primary" @click="toLink">
|
<button type="primary" @tap.stop="toLink">
|
||||||
<text class="iconfont icon-fukuanma"></text>
|
<text class="iconfont icon-fukuanma"></text>
|
||||||
<text class="action-name">付款码</text>
|
<text class="action-name">付款码</text>
|
||||||
</button>
|
</button>
|
||||||
<button type="primary" @click="openPaymentPopup">
|
<button type="primary" @tap.stop="openPaymentPopup">
|
||||||
<text class="iconfont icon-saomafu"></text>
|
<text class="iconfont icon-saomafu"></text>
|
||||||
<text class="action-name">扫码付</text>
|
<text class="action-name">扫码付</text>
|
||||||
</button>
|
</button>
|
||||||
@@ -26,12 +26,12 @@
|
|||||||
<view @touchmove.prevent.stop>
|
<view @touchmove.prevent.stop>
|
||||||
<uni-popup ref="paymentPopup" type="center">
|
<uni-popup ref="paymentPopup" type="center">
|
||||||
<view class="payment-popup">
|
<view class="payment-popup">
|
||||||
<view class="head-wrap" @click="closePaymentPopup">
|
<view class="head-wrap" @tap.stop="closePaymentPopup">
|
||||||
<text>提示</text>
|
<text>提示</text>
|
||||||
<text class="iconfont icon-close"></text>
|
<text class="iconfont icon-close"></text>
|
||||||
</view>
|
</view>
|
||||||
<view class="content-wrap">扫码付请退出程序后直接使用微信扫一扫或返回上一页使用付款码进行支付</view>
|
<view class="content-wrap">扫码付请退出程序后直接使用微信扫一扫或返回上一页使用付款码进行支付</view>
|
||||||
<button type="primary" @click="closePaymentPopup">我知道了</button>
|
<button type="primary" @tap.stop="closePaymentPopup">我知道了</button>
|
||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<view class="fui-picture">
|
<view class="fui-picture">
|
||||||
<view v-for="(item, index) in value.list" style="line-height: 0;">
|
<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)"
|
<image mode="widthFix" style="width: 100%;height:auto" :src="$util.img(item.imageUrl)"
|
||||||
v-if="item.link.wap_url" @click="handlerClick(item)" @tap="handlerClick(item)"></image>
|
v-if="item.link.wap_url" @tap.stop="handlerClick(item)"></image>
|
||||||
<image mode="widthFix" style="width: 100%;height:auto" :src="$util.img(item.imageUrl)" v-else
|
<image mode="widthFix" style="width: 100%;height:auto" :src="$util.img(item.imageUrl)" v-else
|
||||||
@click="handlerClick(item)" @tap="handlerClick(item)"></image>
|
@tap.stop="handlerClick(item)"></image>
|
||||||
</view>
|
</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}}">
|
<!-- <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>
|
<image mode="widthFix" src="{{childitem.imgurl}}" style="{{bannerheight?'height:'+bannerheight+'px':'height:auto'}}"></image>
|
||||||
@@ -52,17 +52,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
redirectTo(link) {
|
||||||
if (link.wap_url) {
|
if (link.wap_url) {
|
||||||
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
|
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
|
||||||
@@ -77,7 +66,9 @@ export default {
|
|||||||
await this.__$emitEvent({
|
await this.__$emitEvent({
|
||||||
eventName: 'picture-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
|
eventName: 'picture-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
|
||||||
if (!awaitedResult) return;
|
if (!awaitedResult) return;
|
||||||
if (item.link.wap_url) {
|
|
||||||
|
const link = item.link;
|
||||||
|
if (link?.name || link?.wap_url || link?.appid) {
|
||||||
this.redirectTo(item.link);
|
this.redirectTo(item.link);
|
||||||
} else {
|
} else {
|
||||||
this.previewImg(item.imageUrl);
|
this.previewImg(item.imageUrl);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<x-skeleton data-component-name="diy-pinfan" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
<x-skeleton data-component-name="diy-pinfan" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
||||||
<view class="diy-pinfan" :class="[value.template, value.style]" :style="warpCss">
|
<view class="diy-pinfan" :class="[value.template, value.style]" :style="warpCss">
|
||||||
<template v-if="value.template == 'row1-of1'">
|
<template v-if="value.template == 'row1-of1'">
|
||||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
|
|
||||||
<template v-if="value.template == 'horizontal-slide'">
|
<template v-if="value.template == 'horizontal-slide'">
|
||||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
<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" @click="toDetail(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :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"
|
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||||
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
|
|||||||
@@ -31,14 +31,14 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="head-right"
|
<view class="head-right"
|
||||||
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
||||||
@click="$util.redirectTo('/pages_promotion/pintuan/list')">
|
@tap.stop="$util.redirectTo('/pages_promotion/pintuan/list')">
|
||||||
<text>{{ value.titleStyle.more }}</text>
|
<text>{{ value.titleStyle.more }}</text>
|
||||||
<text class="iconfont icon-right"></text>
|
<text class="iconfont icon-right"></text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<template v-if="value.template == 'row1-of1'">
|
<template v-if="value.template == 'row1-of1'">
|
||||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
|
|
||||||
<template v-if="value.template == 'horizontal-slide'">
|
<template v-if="value.template == 'horizontal-slide'">
|
||||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
<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" @click="toDetail(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :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"
|
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||||
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<x-skeleton data-component-name="diy-presale" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
|
<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">
|
<view class="diy-presale" v-if="list.length" :class="[value.template, value.style]" :style="warpCss">
|
||||||
<template v-if="value.template == 'row1-of1'">
|
<template v-if="value.template == 'row1-of1'">
|
||||||
<view class="item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
|
||||||
@tap="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
@@ -40,8 +40,8 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-if="value.template == 'horizontal-slide'">
|
<template v-if="value.template == 'horizontal-slide'">
|
||||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
<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" @click="handlerClick(item)"
|
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
|
||||||
@tap="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
@@ -75,8 +75,7 @@
|
|||||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||||
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
|
||||||
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
|
||||||
@click="handlerClick(item)" @tap="handlerClick(item)" :class="[value.ornament.type]"
|
@tap.stop="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
:style="goodsItemCss">
|
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<view class="uni-scroll-view-content">
|
<view class="uni-scroll-view-content">
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<view class="quick-nav-item" v-for="(item, index) in value.list" :key="index"
|
<view class="quick-nav-item" v-for="(item, index) in value.list" :key="index"
|
||||||
@click="handlerClick(item)" @tap="handlerClick(item)"
|
@tap.stop="handlerClick(item)"
|
||||||
:style="{ background: 'linear-gradient(to right,' + item.bgColorStart ? item.bgColorStart : '' + ',' + item.bgColorEnd ? item.bgColorEnd : '' + ')' }">
|
:style="{ background: 'linear-gradient(to right,' + item.bgColorStart ? item.bgColorStart : '' + ',' + item.bgColorEnd ? item.bgColorEnd : '' + ')' }">
|
||||||
<view class="quick-img" v-if="item.imageUrl || item.icon">
|
<view class="quick-img" v-if="item.imageUrl || item.icon">
|
||||||
<image v-if="item.iconType == 'img'"
|
<image v-if="item.iconType == 'img'"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view data-component-name="diy-rich-text" class="rich-text-box" :style="richTextWarpCss">
|
<view data-component-name="diy-rich-text" class="rich-text-box" :style="richTextWarpCss">
|
||||||
<rich-text :nodes="html" @click="handlerClick" @tap="handlerClick"></rich-text>
|
<rich-text :nodes="html" @tap.stop="handlerClick"></rich-text>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,8 @@
|
|||||||
<!-- 1左2右 -->
|
<!-- 1左2右 -->
|
||||||
<template v-if="value.mode == 'row1-lt-of2-rt'">
|
<template v-if="value.mode == 'row1-lt-of2-rt'">
|
||||||
<view class="template-left">
|
<view class="template-left">
|
||||||
<view :class="['item', value.mode]" @click="handlerClick(value.list[0].link)"
|
<view :class="['item', value.mode]" @tap.stop="handlerClick(value.list[0].link, value.list[0].imageUrl)"
|
||||||
@tap="handlerClick(value.list[0].link)"
|
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }">
|
||||||
: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'"
|
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
|
||||||
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
|
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
|
||||||
</view>
|
</view>
|
||||||
@@ -19,9 +18,8 @@
|
|||||||
<view class="template-right">
|
<view class="template-right">
|
||||||
<template v-for="(item, index) in list">
|
<template v-for="(item, index) in list">
|
||||||
<template v-if="index > 0">
|
<template v-if="index > 0">
|
||||||
<view :key="index" :class="['item', value.mode]" @click="handlerClick(item.link)"
|
<view :key="index" :class="['item', value.mode]" @tap.stop="handlerClick(item.link, item.imageUrl)"
|
||||||
@tap="handlerClick(item.link)"
|
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: item.imgWidth, height: item.imgHeight + 'px' }">
|
||||||
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: item.imgWidth, height: item.imgHeight + 'px' }">
|
|
||||||
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
||||||
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
||||||
</view>
|
</view>
|
||||||
@@ -34,8 +32,8 @@
|
|||||||
<template v-else-if="value.mode == 'row1-lt-of1-tp-of2-bm'">
|
<template v-else-if="value.mode == 'row1-lt-of1-tp-of2-bm'">
|
||||||
<view class="template-left">
|
<view class="template-left">
|
||||||
<view :class="['item', value.mode]"
|
<view :class="['item', value.mode]"
|
||||||
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }"
|
: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)">
|
@tap.stop="handlerClick(value.list[0].link, value.list[0].imageUrl)">
|
||||||
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
|
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
|
||||||
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
|
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
|
||||||
</view>
|
</view>
|
||||||
@@ -43,20 +41,19 @@
|
|||||||
|
|
||||||
<view class="template-right">
|
<view class="template-right">
|
||||||
<view :class="['item', value.mode]"
|
<view :class="['item', value.mode]"
|
||||||
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: list[1].imgWidth, height: list[1].imgHeight + 'px' }"
|
: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)">
|
@tap.stop="handlerClick(value.list[1].link, value.list[1].imageUrl)">
|
||||||
<image :src="$util.img(value.list[1].imageUrl)" :mode="list[1].imageMode || 'scaleToFill'"
|
<image :src="$util.img(value.list[1].imageUrl)" :mode="list[1].imageMode || 'scaleToFill'"
|
||||||
:style="list[1].pageItemStyle" :show-menu-by-longpress="true" />
|
:style="list[1].pageItemStyle" :show-menu-by-longpress="true" />
|
||||||
</view>
|
</view>
|
||||||
<view class="template-bottom">
|
<view class="template-bottom">
|
||||||
<template v-for="(item, index) in list">
|
<template v-for="(item, index) in list">
|
||||||
<template v-if="index > 1">
|
<template v-if="index > 1">
|
||||||
<view :key="index" :class="['item', value.mode]" @click="handlerClick(item.link)"
|
<view :key="index" :class="['item', value.mode]" @tap.stop="handlerClick(item.link, item.imageUrl)" :style="{
|
||||||
@tap="handlerClick(item.link)" :style="{
|
marginRight: value.imageGap * 2 + 'rpx',
|
||||||
marginRight: value.imageGap * 2 + 'rpx',
|
width: item.imgWidth,
|
||||||
width: item.imgWidth,
|
height: item.imgHeight + 'px'
|
||||||
height: item.imgHeight + 'px'
|
}">
|
||||||
}">
|
|
||||||
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
||||||
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
||||||
</view>
|
</view>
|
||||||
@@ -68,8 +65,8 @@
|
|||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<view :class="['item', value.mode]" v-for="(item, index) in list" :key="index"
|
<view :class="['item', value.mode]" v-for="(item, index) in list" :key="index"
|
||||||
@click="handlerClick(item.link)" @tap="handlerClick(item.link)"
|
@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' }">
|
: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'"
|
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
|
||||||
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
|
||||||
</view>
|
</view>
|
||||||
@@ -374,11 +371,16 @@ export default {
|
|||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
|
||||||
async handlerClick(link) {
|
async handlerClick(link, imageUrl) {
|
||||||
await this.__$emitEvent({
|
await this.__$emitEvent({
|
||||||
eventName: 'rubik-cube-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
|
eventName: 'rubik-cube-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
|
||||||
if (!awaitedResult) return;
|
if (!awaitedResult) return;
|
||||||
this.$util.diyRedirectTo(link);
|
|
||||||
|
if (link?.name || link?.wap_url || link?.appid) {
|
||||||
|
this.$util.diyRedirectTo(link);
|
||||||
|
} else if (imageUrl){
|
||||||
|
this.previewImg(imageUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view data-component-name="diy-search" class="diy-search">
|
<view data-component-name="diy-search" class="diy-search">
|
||||||
<view class="diy-search-wrap" :class="value.positionWay" :style="fixedCss">
|
<view class="diy-search-wrap" :class="value.positionWay" :style="fixedCss">
|
||||||
<view :class="['search-box', 'search-box-' + value.searchStyle]" :style="searchWrapCss"
|
<view :class="['search-box', 'search-box-' + value.searchStyle]" :style="searchWrapCss"
|
||||||
@click="handlerSearchClick" @tap="handlerSearchClick">
|
@tap.stop="handlerSearchClick">
|
||||||
<block v-if="[1, 2].includes(value.searchStyle)">
|
<block v-if="[1, 2].includes(value.searchStyle)">
|
||||||
<view class="img" v-if="value.searchStyle == 2 && value.iconType == 'img'">
|
<view class="img" v-if="value.searchStyle == 2 && value.iconType == 'img'">
|
||||||
<image :src="$util.img(value.imageUrl)" mode="heightFix" />
|
<image :src="$util.img(value.imageUrl)" mode="heightFix" />
|
||||||
@@ -14,32 +14,30 @@
|
|||||||
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title"
|
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title"
|
||||||
v-model="searchText" @confirm="handlerSearchClick" disabled="true"
|
v-model="searchText" @confirm="handlerSearchClick" disabled="true"
|
||||||
:placeholderStyle="placeholderStyle" />
|
:placeholderStyle="placeholderStyle" />
|
||||||
<text class="iconfont icon-sousuo3" @click.stop="handlerSearchClick" @tap="handlerSearchClick"
|
<text class="iconfont icon-sousuo3" @tap.stop="handlerSearchClick"
|
||||||
:style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
|
:style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
<block v-if="value.searchStyle == 3">
|
<block v-if="value.searchStyle == 3">
|
||||||
<view class="search-content" :style="inputStyle" @click.stop="handlerSearchClick"
|
<view class="search-content" :style="inputStyle"
|
||||||
@tap="handlerSearchClick">
|
@tap.stop="handlerSearchClick">
|
||||||
<text class="iconfont icon-sousuo3"
|
<text class="iconfont icon-sousuo3"
|
||||||
:style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
|
: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"
|
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title"
|
||||||
v-model="searchText" @confirm="handlerSearchClick" disabled="true"
|
v-model="searchText" @confirm="handlerSearchClick" disabled="true"
|
||||||
@click.stop="handlerSearchClick" @tap="handlerSearchClick"
|
@tap.stop="handlerSearchClick"
|
||||||
:placeholderStyle="placeholderStyle" />
|
:placeholderStyle="placeholderStyle" />
|
||||||
<text class="search-content-btn" @click.stop="handlerSearchClick" @tap="handlerSearchClick"
|
<text class="search-content-btn" @tap.stop="handlerSearchClick"
|
||||||
:style="{ 'backgroundColor': value.pageBgColor ? value.pageBgColor : 'rgba(0,0,0,0)' }">搜索</text>
|
:style="{ 'backgroundColor': value.pageBgColor ? value.pageBgColor : 'rgba(0,0,0,0)' }">搜索</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="img" v-if="value.iconType == 'img'"
|
<view class="img" v-if="value.iconType == 'img'"
|
||||||
@click.stop="handlerRedirectToClick(value.searchLink)"
|
@tap.stop="handlerRedirectToClick(value.searchLink)">
|
||||||
@tap="handlerRedirectToClick(value.searchLink)">
|
|
||||||
<image :src="$util.img(value.imageUrl)" mode="heightFix" />
|
<image :src="$util.img(value.imageUrl)" mode="heightFix" />
|
||||||
</view>
|
</view>
|
||||||
<diy-icon class="icon" v-if="value.iconType == 'icon'" :icon="value.icon"
|
<diy-icon class="icon" v-if="value.iconType == 'icon'" :icon="value.icon"
|
||||||
:value="value.style ? value.style : 'null'"
|
:value="value.style ? value.style : 'null'"
|
||||||
:style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }"
|
:style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }"
|
||||||
@click.stop="handlerRedirectToClick(value.searchLink)"
|
@tap.stop="handlerRedirectToClick(value.searchLink)"></diy-icon>
|
||||||
@tap="handlerRedirectToClick(value.searchLink)"></diy-icon>
|
|
||||||
</block>
|
</block>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="marketimg-box-title-right" v-if="value.titleStyle.moreSupport"
|
<view class="marketimg-box-title-right" v-if="value.titleStyle.moreSupport"
|
||||||
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
|
||||||
@click="toMore">
|
@tap.stop="toMore">
|
||||||
<text>{{ value.titleStyle.more }}</text>
|
<text>{{ value.titleStyle.more }}</text>
|
||||||
<text class="iconfont icon-right"></text>
|
<text class="iconfont icon-right"></text>
|
||||||
</view>
|
</view>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
<view class="content-wrap">
|
<view class="content-wrap">
|
||||||
<template v-if="value.template == 'row1-of1'">
|
<template v-if="value.template == 'row1-of1'">
|
||||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
|
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="value.template == 'row1-of2'">
|
<template v-if="value.template == 'row1-of2'">
|
||||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
|
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
<template v-if="value.template == 'horizontal-slide'">
|
<template v-if="value.template == 'horizontal-slide'">
|
||||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true"
|
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true"
|
||||||
:show-scrollbar="false">
|
:show-scrollbar="false">
|
||||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
|
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
|
||||||
:class="[value.ornament.type]" :style="goodsItemCss">
|
:class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :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"
|
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
|
||||||
:class="['swiper-item', dataList[pageIndex] && [dataList[pageIndex].length / 3].length >= 1 && 'flex-between']">
|
: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"
|
<view class="item" v-for="(item, dataIndex) in dataList[pageIndex]" :key="dataIndex"
|
||||||
@click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
@tap.stop="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<block v-if="value.style == 1">
|
<block v-if="value.style == 1">
|
||||||
<view class="store-box store-one">
|
<view class="store-box store-one">
|
||||||
<view class="store-info">
|
<view class="store-info">
|
||||||
<view class="info-box" :style="{ color: value.textColor }" @click="toStoreList()">
|
<view class="info-box" :style="{ color: value.textColor }" @tap.stop="toStoreList()">
|
||||||
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
|
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
|
||||||
<text class="title">{{ globalStoreInfo.store_name }}</text>
|
<text class="title">{{ globalStoreInfo.store_name }}</text>
|
||||||
<text>
|
<text>
|
||||||
@@ -15,12 +15,12 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="address-wrap" :style="{ color: value.textColor }">
|
<view class="address-wrap" :style="{ color: value.textColor }">
|
||||||
<text class="iconfont icon-dizhi"></text>
|
<text class="iconfont icon-dizhi"></text>
|
||||||
<text v-if="globalStoreInfo && globalStoreInfo.store_id" @click="mapRoute" class="address">{{
|
<text v-if="globalStoreInfo && globalStoreInfo.store_id" @tap.stop="mapRoute" class="address">{{
|
||||||
globalStoreInfo.show_address }}</text>
|
globalStoreInfo.show_address }}</text>
|
||||||
<text v-else>获取当前位置...</text>
|
<text v-else>获取当前位置...</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="store-image" @click="selectStore()">
|
<view class="store-image" @tap.stop="selectStore()">
|
||||||
<image :src="$util.img(globalStoreInfo.store_image)"
|
<image :src="$util.img(globalStoreInfo.store_image)"
|
||||||
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill"></image>
|
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill"></image>
|
||||||
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill"></image>
|
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill"></image>
|
||||||
@@ -29,9 +29,9 @@
|
|||||||
</block>
|
</block>
|
||||||
|
|
||||||
<block v-if="value.style == 2">
|
<block v-if="value.style == 2">
|
||||||
<view class="store-box store-three" @click="toStoreList()">
|
<view class="store-box store-three" @tap.stop="toStoreList()">
|
||||||
<view class="store-info">
|
<view class="store-info">
|
||||||
<view class="store-image" @click="selectStore()">
|
<view class="store-image" @tap.stop="selectStore()">
|
||||||
<image :src="$util.img(globalStoreInfo.store_image)"
|
<image :src="$util.img(globalStoreInfo.store_image)"
|
||||||
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill"></image>
|
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill"></image>
|
||||||
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill"></image>
|
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill"></image>
|
||||||
@@ -47,13 +47,13 @@
|
|||||||
<text class="title" v-else>定位中...</text>
|
<text class="title" v-else>定位中...</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="store-icon" @click.stop="search()"><text class="iconfont icon-sousuo3"
|
<view class="store-icon" @tap.stop="search()"><text class="iconfont icon-sousuo3"
|
||||||
:style="{ color: value.textColor }"></text></view>
|
:style="{ color: value.textColor }"></text></view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
|
|
||||||
<block v-if="value.style == 3">
|
<block v-if="value.style == 3">
|
||||||
<view class="store-box store-four" @click="toStoreList()">
|
<view class="store-box store-four" @tap.stop="toStoreList()">
|
||||||
<view class="store-left-wrap">
|
<view class="store-left-wrap">
|
||||||
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
|
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
|
||||||
<text class="iconfont icon-weizhi" :style="{ color: value.textColor }"></text>
|
<text class="iconfont icon-weizhi" :style="{ color: value.textColor }"></text>
|
||||||
@@ -64,8 +64,8 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="store-right-search">
|
<view class="store-right-search">
|
||||||
<input type="text" class="uni-input font-size-tag" disabled placeholder="商品搜索"
|
<input type="text" class="uni-input font-size-tag" disabled placeholder="商品搜索"
|
||||||
@click.stop="search()" />
|
@tap.stop="search()" />
|
||||||
<text class="iconfont icon-sousuo3" @click.stop="search()"></text>
|
<text class="iconfont icon-sousuo3" @tap.stop="search()"></text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
|
|||||||
1283
components-diy/diy-tab.vue
Normal file
1283
components-diy/diy-tab.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view data-component-name="diy-text" class="diy-text" @click="handlerClick(value.link)"
|
<view data-component-name="diy-text" class="diy-text" @tap="handlerClick(value.link)" :style="warpCss">
|
||||||
@tap="handlerClick(value.link)" :style="warpCss">
|
|
||||||
<view :class="value.style == 'style-8' ? 'title2' : 'title'"
|
<view :class="value.style == 'style-8' ? 'title2' : 'title'"
|
||||||
:style="{ fontSize: value.fontSize * 2 + 'rpx', color: value.textColor }">
|
:style="{ fontSize: value.fontSize * 2 + 'rpx', color: value.textColor }">
|
||||||
<block v-if="value.style == 'style-0'" style="height: 40rpx; line-height: 40rpx;">
|
<block v-if="value.style == 'style-0'" style="height: 40rpx; line-height: 40rpx;">
|
||||||
@@ -100,13 +99,13 @@
|
|||||||
<image :src="$util.img('public/uniapp/diy/style9-2.png')" />
|
<image :src="$util.img('public/uniapp/diy/style9-2.png')" />
|
||||||
</view>
|
</view>
|
||||||
<view class="style9-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
<view class="style9-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||||
@click.stop="handlerClick(value.more.link)" @tap="handlerClick(value.more.link)">
|
@tap.stop="handlerClick(value.more.link)">
|
||||||
{{ value.more.text }}
|
{{ value.more.text }}
|
||||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<text class="sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
|
<text class="sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
|
||||||
}}</text>
|
}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
@@ -132,13 +131,13 @@
|
|||||||
<image :src="$util.img('public/uniapp/diy/style10-2.png')"></image>
|
<image :src="$util.img('public/uniapp/diy/style10-2.png')"></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="style10-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
<view class="style10-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||||
@click.stop="handlerClick(value.more.link)" @tap="handlerClick(value.more.link)">
|
@tap.stop="handlerClick(value.more.link)">
|
||||||
{{ value.more.text }}
|
{{ value.more.text }}
|
||||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<text class="sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
|
<text class="sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
|
||||||
}}</text>
|
}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
@@ -159,7 +158,7 @@
|
|||||||
value.subTitle.text }}</view>
|
value.subTitle.text }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="style11-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
<view class="style11-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||||
@click.stop="$util.diyRedirectTo(value.more.link)">
|
@tap.stop="$util.diyRedirectTo(value.more.link)">
|
||||||
{{ value.more.text }}
|
{{ value.more.text }}
|
||||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||||
</view>
|
</view>
|
||||||
@@ -183,9 +182,9 @@
|
|||||||
{{ value.text }}
|
{{ value.text }}
|
||||||
</view>
|
</view>
|
||||||
<text class="style12-sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
|
<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 }"
|
<view class="style12-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||||
@click.stop="$util.diyRedirectTo(value.more.link)">
|
@tap.stop="$util.diyRedirectTo(value.more.link)">
|
||||||
<text>{{ value.more.text }}</text>
|
<text>{{ value.more.text }}</text>
|
||||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||||
</view>
|
</view>
|
||||||
@@ -278,7 +277,7 @@
|
|||||||
<text :style="{ fontWeight: value.subTitle.fontWeight }">{{ value.subTitle.text }}</text>
|
<text :style="{ fontWeight: value.subTitle.fontWeight }">{{ value.subTitle.text }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="style16-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
<view class="style16-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
|
||||||
@click.stop="$util.diyRedirectTo(value.more.link)">
|
@tap.stop="$util.diyRedirectTo(value.more.link)">
|
||||||
<text>{{ value.more.text }}</text>
|
<text>{{ value.more.text }}</text>
|
||||||
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -53,9 +53,19 @@
|
|||||||
|
|
||||||
<!-- 视频播放弹窗 -->
|
<!-- 视频播放弹窗 -->
|
||||||
<uni-popup ref="videoPopup" type="center" style="background:transparent;width:100%;height:100%;">
|
<uni-popup ref="videoPopup" type="center" style="background:transparent;width:100%;height:100%;">
|
||||||
<view class="video-container" style="position:fixed;top:30%;width:100%;left:0;">
|
<view class="video-container" :style="popupVideoStyle">
|
||||||
<video class="adaptive-video" :autoPauseIfNavigate="true" :autoPauseIfOpenNative="true"
|
<video
|
||||||
:autoplay="false" :enableAutoRotation="true" id="myVideo" :src="video_url" :controls="true"></video>
|
ref="popupVideoRef"
|
||||||
|
class="adaptive-video"
|
||||||
|
:autoPauseIfNavigate="true"
|
||||||
|
:autoPauseIfOpenNative="true"
|
||||||
|
:autoplay="false"
|
||||||
|
:enableAutoRotation="true"
|
||||||
|
id="myVideo"
|
||||||
|
:src="video_url"
|
||||||
|
:controls="true"
|
||||||
|
@loadedmetadata="onPopupVideoLoaded"
|
||||||
|
></video>
|
||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
@@ -126,12 +136,38 @@ export default {
|
|||||||
isIndicatorDots() {
|
isIndicatorDots() {
|
||||||
return this.value.carousel.type != 'hide' &&
|
return this.value.carousel.type != 'hide' &&
|
||||||
1 != Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount));
|
1 != Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount));
|
||||||
|
},
|
||||||
|
|
||||||
|
// 弹窗视频容器样式
|
||||||
|
popupVideoStyle() {
|
||||||
|
let style = 'position:fixed;width:100%;left:0;';
|
||||||
|
|
||||||
|
if (this.popupVideoRatio) {
|
||||||
|
// 根据视频比例设置位置
|
||||||
|
if (this.popupVideoRatio === 'portrait') {
|
||||||
|
// 竖屏视频:居中显示,使用9/16比例
|
||||||
|
style += 'top:50%;transform:translateY(-50%);';
|
||||||
|
style += 'aspect-ratio: 9 / 16;';
|
||||||
|
} else {
|
||||||
|
// 横屏视频:靠近顶部显示,使用16/9比例
|
||||||
|
style += 'top:20%;';
|
||||||
|
style += 'aspect-ratio: 16 / 9;';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 默认:居中显示,使用竖屏比例
|
||||||
|
style += 'top:50%;transform:translateY(-50%);';
|
||||||
|
style += 'aspect-ratio: 9 / 16;';
|
||||||
|
}
|
||||||
|
|
||||||
|
return style;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 显示视频播放弹窗
|
// 显示视频播放弹窗
|
||||||
showVideo(item) {
|
showVideo(item) {
|
||||||
this.video_url = item.videoUrl;
|
this.video_url = item.videoUrl;
|
||||||
|
// 重置视频比例为null,等待新的检测结果
|
||||||
|
this.popupVideoRatio = null;
|
||||||
this.$refs.videoPopup.open();
|
this.$refs.videoPopup.open();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -139,6 +175,39 @@ export default {
|
|||||||
imgError(index) {
|
imgError(index) {
|
||||||
// 图片加载失败的处理逻辑
|
// 图片加载失败的处理逻辑
|
||||||
console.log('图片加载失败:', index);
|
console.log('图片加载失败:', index);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 弹窗视频加载完成事件
|
||||||
|
onPopupVideoLoaded(event) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
let width = 0;
|
||||||
|
let height = 0;
|
||||||
|
|
||||||
|
// H5 端:获取真实视频宽高
|
||||||
|
// #ifdef H5
|
||||||
|
const video = this.$refs.popupVideoRef;
|
||||||
|
if (video) {
|
||||||
|
width = video.videoWidth || 0;
|
||||||
|
height = video.videoHeight || 0;
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 微信小程序端:通过事件对象获取视频宽高
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
if (event && event.detail) {
|
||||||
|
width = event.detail.width || 0;
|
||||||
|
height = event.detail.height || 0;
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
if (width && height) {
|
||||||
|
this.popupVideoRatio = width >= height ? 'landscape' : 'portrait';
|
||||||
|
console.log(`弹窗视频宽高比检测: ${width}x${height}, 比例: ${this.popupVideoRatio}`);
|
||||||
|
} else {
|
||||||
|
// 获取失败,默认竖屏
|
||||||
|
this.popupVideoRatio = 'portrait';
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<video data-component-name="diy-video" class="diy-video" :src="$util.img(value.videoUrl)"
|
<view class="video-container" :style="containerStyle">
|
||||||
:poster="$util.img(value.imageUrl)" :style="videoWarpCss" objectFit="cover"
|
<!-- H5端使用原生video标签 -->
|
||||||
@click="handlerClick(value.videoUrl)" @tap="handlerClick(value.videoUrl)"></video>
|
<!-- #ifdef H5 -->
|
||||||
|
<video
|
||||||
|
ref="videoRef"
|
||||||
|
data-component-name="diy-video"
|
||||||
|
class="diy-video h5-video"
|
||||||
|
:src="videoUrl"
|
||||||
|
:poster="posterUrl"
|
||||||
|
:style="videoWarpCss"
|
||||||
|
controls
|
||||||
|
preload="metadata"
|
||||||
|
@loadedmetadata="onVideoLoaded"
|
||||||
|
@click="handlerClick(videoUrl)"
|
||||||
|
></video>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
<!-- 微信小程序端使用uni-app的video组件 -->
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<video
|
||||||
|
ref="videoRef"
|
||||||
|
data-component-name="diy-video"
|
||||||
|
class="diy-video mp-video"
|
||||||
|
:src="videoUrl"
|
||||||
|
:poster="posterUrl"
|
||||||
|
:style="videoWarpCss"
|
||||||
|
controls
|
||||||
|
@loadedmetadata="onVideoLoaded"
|
||||||
|
@error="onVideoError"
|
||||||
|
></video>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -15,27 +44,160 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {
|
||||||
|
videoRatio: null, // 视频比例:'landscape'(横屏)或 'portrait'(竖屏)
|
||||||
|
videoUrl: '',
|
||||||
|
posterUrl: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.initVideoData();
|
||||||
},
|
},
|
||||||
created() { },
|
|
||||||
mixins: [DiyMinx],
|
mixins: [DiyMinx],
|
||||||
watch: {
|
watch: {
|
||||||
// 组件刷新监听
|
value: {
|
||||||
componentRefresh: function (nval) { }
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.initVideoData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
videoWarpCss: function () {
|
videoWarpCss: function () {
|
||||||
var obj = '';
|
var obj = '';
|
||||||
if (this.value.componentAngle == 'round') {
|
if (this.value && this.value.componentAngle == 'round') {
|
||||||
obj += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
obj += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
||||||
obj += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
obj += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
||||||
obj += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
obj += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
||||||
obj += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
obj += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
|
},
|
||||||
|
// 动态计算容器比例
|
||||||
|
containerStyle() {
|
||||||
|
let style = '';
|
||||||
|
|
||||||
|
if (this.videoRatio === 'landscape') {
|
||||||
|
// 横屏视频:16/9比例
|
||||||
|
style += 'aspect-ratio: 16 / 9;';
|
||||||
|
} else if (this.videoRatio === 'portrait') {
|
||||||
|
// 竖屏视频:9/16比例
|
||||||
|
style += 'aspect-ratio: 9 / 16;';
|
||||||
|
} else {
|
||||||
|
// 未加载完成 → 默认使用竖屏比例
|
||||||
|
style += 'aspect-ratio: 9 / 16;';
|
||||||
|
}
|
||||||
|
|
||||||
|
return style;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 初始化视频数据
|
||||||
|
initVideoData() {
|
||||||
|
this.videoUrl = this.getVideoUrl();
|
||||||
|
this.posterUrl = this.getPosterUrl();
|
||||||
|
// H5端:预加载视频获取宽高
|
||||||
|
// #ifdef H5
|
||||||
|
this.preloadVideoForRatio();
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取视频URL
|
||||||
|
getVideoUrl() {
|
||||||
|
if (!this.value || !this.value.videoUrl) return '';
|
||||||
|
const videoUrl = this.value.videoUrl;
|
||||||
|
// 如果是完整的http/https链接,直接使用
|
||||||
|
if (videoUrl.indexOf('http://') === 0 || videoUrl.indexOf('https://') === 0) {
|
||||||
|
return videoUrl;
|
||||||
|
}
|
||||||
|
// 否则使用$util.img()处理
|
||||||
|
return this.$util.img(videoUrl);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取封面图URL
|
||||||
|
getPosterUrl() {
|
||||||
|
if (!this.value || !this.value.imageUrl) return '';
|
||||||
|
return this.$util.img(this.value.imageUrl);
|
||||||
|
},
|
||||||
|
|
||||||
|
// H5端:预加载视频获取宽高比例
|
||||||
|
preloadVideoForRatio() {
|
||||||
|
const videoUrl = this.videoUrl;
|
||||||
|
if (!videoUrl) return;
|
||||||
|
|
||||||
|
console.log('H5端预加载视频获取比例:', videoUrl);
|
||||||
|
|
||||||
|
const video = document.createElement('video');
|
||||||
|
video.preload = 'metadata';
|
||||||
|
video.src = videoUrl;
|
||||||
|
video.muted = true;
|
||||||
|
video.playsInline = true;
|
||||||
|
|
||||||
|
video.addEventListener('loadedmetadata', () => {
|
||||||
|
const width = video.videoWidth;
|
||||||
|
const height = video.videoHeight;
|
||||||
|
console.log('H5端预加载获取视频宽高:', width, height);
|
||||||
|
|
||||||
|
if (width && height) {
|
||||||
|
this.videoRatio = width >= height ? 'landscape' : 'portrait';
|
||||||
|
console.log('H5端视频比例判定:', this.videoRatio, width >= height ? '横屏' : '竖屏');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
video.addEventListener('error', (e) => {
|
||||||
|
console.error('H5端预加载视频失败:', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 触发加载
|
||||||
|
video.load();
|
||||||
|
},
|
||||||
|
|
||||||
|
// 视频加载完成事件(组件内video标签)
|
||||||
|
onVideoLoaded(event) {
|
||||||
|
console.log('视频组件 loadedmetadata 事件触发');
|
||||||
|
|
||||||
|
let width = 0;
|
||||||
|
let height = 0;
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
if (event && event.target) {
|
||||||
|
width = event.target.videoWidth || 0;
|
||||||
|
height = event.target.videoHeight || 0;
|
||||||
|
console.log('H5端组件视频宽高:', width, height);
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
if (event && event.detail) {
|
||||||
|
width = event.detail.width || 0;
|
||||||
|
height = event.detail.height || 0;
|
||||||
|
console.log('微信小程序端视频宽高:', width, height);
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
if (width && height) {
|
||||||
|
this.videoRatio = width >= height ? 'landscape' : 'portrait';
|
||||||
|
console.log('视频比例最终判定:', this.videoRatio);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 视频播放事件
|
||||||
|
onVideoPlay() {
|
||||||
|
console.log('视频开始播放');
|
||||||
|
},
|
||||||
|
|
||||||
|
// 视频暂停事件
|
||||||
|
onVideoPause() {
|
||||||
|
console.log('视频暂停');
|
||||||
|
},
|
||||||
|
|
||||||
|
// 视频错误事件
|
||||||
|
onVideoError(event) {
|
||||||
|
console.error('视频加载失败:', event);
|
||||||
|
},
|
||||||
|
|
||||||
async handlerClick(videoUrl) {
|
async handlerClick(videoUrl) {
|
||||||
await this.__$emitEvent({
|
await this.__$emitEvent({
|
||||||
eventName: 'video-tap', data: videoUrl, promiseCallback: (event, handler, awaitedResult) => {
|
eventName: 'video-tap', data: videoUrl, promiseCallback: (event, handler, awaitedResult) => {
|
||||||
@@ -48,11 +210,32 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
video {
|
.video-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.diy-video>>>.uni-video-container {
|
/* 基础样式 */
|
||||||
background-color: transparent;
|
.diy-video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
/* H5端样式 */
|
||||||
|
/* #ifdef H5 */
|
||||||
|
.h5-video {
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
/* 微信小程序端样式 */
|
||||||
|
/* #ifdef MP-WEIXIN */
|
||||||
|
.mp-video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -5,5 +5,18 @@ export default {
|
|||||||
// console.log('__$emitEvent', payload)
|
// console.log('__$emitEvent', payload)
|
||||||
await this.$eventBus.emit(payload.eventName, payload.data, payload.promiseCallback)
|
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
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,6 +179,7 @@
|
|||||||
.chat-message {
|
.chat-message {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
background: white; /* 白色 */
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
padding: 13rpx 20rpx;
|
padding: 13rpx 20rpx;
|
||||||
@@ -270,7 +271,7 @@
|
|||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
background-color: #4cd964;
|
background-color: #c4e0ff; /* 浅蓝色 */
|
||||||
margin-right: 28rpx;
|
margin-right: 28rpx;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
line-height: 36rpx;
|
line-height: 36rpx;
|
||||||
|
|||||||
@@ -1,43 +1,79 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 悬浮按钮 -->
|
<view v-if="pageCount === 1 || need" class="fixed-box"
|
||||||
<view v-if="pageCount == 1 || need" class="fixed-box" :style="[customContainerStyle, {
|
:style="[customContainerStyle, {
|
||||||
height: fixBtnShow ? '400rpx' : '320rpx',
|
height: containerHeight,
|
||||||
backgroundImage: bgUrl ? `url(${bgUrl})` : '',
|
backgroundImage: bgUrl ? `url(${bgUrl})` : '',
|
||||||
backgroundSize: 'cover'
|
backgroundSize: 'cover'
|
||||||
}]">
|
}]">
|
||||||
|
|
||||||
<!-- 中英文切换按钮 -->
|
<!-- 中英文切换按钮 -->
|
||||||
<view v-if="isLanguageSwitchEnabled && fixBtnShow" class="btn-item common-bg" @click="toggleLanguage">
|
<view
|
||||||
|
v-if="isLanguageSwitchEnabled && fixBtnShow"
|
||||||
|
class="btn-item common-bg"
|
||||||
|
@click="toggleLanguage"
|
||||||
|
>
|
||||||
<text>{{ currentLangDisplayName }}</text>
|
<text>{{ currentLangDisplayName }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- 微信官方客服按钮-->
|
||||||
|
<button
|
||||||
|
v-if="fixBtnShow && hasValidKefuConfig && isWeappOfficialKefu"
|
||||||
|
class="btn-item common-bg"
|
||||||
|
open-type="contact"
|
||||||
|
>
|
||||||
|
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- AI 智能助手 -->
|
<!-- 其他类型客服按钮(智能客服、企业微信等)-->
|
||||||
<view v-if="fixBtnShow && enableAIChat" class="btn-item common-bg" @click="openAIChat"
|
<view
|
||||||
:style="{ backgroundImage: aiAgentimg ? `url(${aiAgentimg})` : '', backgroundSize: '100% 100%' }">
|
v-if="fixBtnShow && hasValidKefuConfig && !isWeappOfficialKefu && !showWeappSystemKefu"
|
||||||
<text class="ai-icon" v-if="!aiAgentimg">🤖</text>
|
class="btn-item common-bg"
|
||||||
|
@click="handleUnifiedKefuClick"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
v-if="currentKefuImg"
|
||||||
|
:src="currentKefuImg"
|
||||||
|
mode="aspectFill"
|
||||||
|
class="kefu-img"
|
||||||
|
></image>
|
||||||
|
<text class="ai-icon" v-if="isAIKefu && !currentKefuImg">🤖</text>
|
||||||
|
<text class="ai-icon" v-if="isWxworkKefu && !currentKefuImg">💬</text>
|
||||||
|
<text class="ai-icon" v-if="!isAIKefu && !isWxworkKefu && !currentKefuImg">👤</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 微信小程序客服按钮 -->
|
<!-- 智能客服按钮(当同时显示小程序系统客服时)-->
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<view
|
||||||
<button class="btn-item common-bg" hoverClass="none" openType="contact" sessionFrom="weapp" showMessageCard="true"
|
v-if="fixBtnShow && hasValidKefuConfig && !isWeappOfficialKefu && showWeappSystemKefu"
|
||||||
:style="[{ backgroundImage: kefuimg ? `url(${kefuimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]">
|
class="btn-item common-bg"
|
||||||
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
@click="handleUnifiedKefuClick"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
v-if="currentKefuImg"
|
||||||
|
:src="currentKefuImg"
|
||||||
|
mode="aspectFill"
|
||||||
|
class="kefu-img"
|
||||||
|
></image>
|
||||||
|
<text class="ai-icon" v-if="isAIKefu && !currentKefuImg">🤖</text>
|
||||||
|
<text class="ai-icon" v-if="isWxworkKefu && !currentKefuImg">💬</text>
|
||||||
|
<text class="ai-icon" v-if="!isAIKefu && !isWxworkKefu && !currentKefuImg">👤</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 小程序系统客服按钮 -->
|
||||||
|
<button
|
||||||
|
v-if="fixBtnShow && hasValidKefuConfig && showWeappSystemKefu"
|
||||||
|
class="btn-item common-bg"
|
||||||
|
open-type="contact"
|
||||||
|
>
|
||||||
|
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
||||||
</button>
|
</button>
|
||||||
<!-- #endif -->
|
|
||||||
|
|
||||||
<!-- 普通客服(仅当未启用 AI 时显示) -->
|
|
||||||
<!-- #ifdef H5 -->
|
|
||||||
<template v-if="fixBtnShow">
|
|
||||||
<button class="btn-item common-bg" hoverClass="none" @click="openCustomerSelectPopup"
|
|
||||||
:style="[{ backgroundImage: kefuimg ? `url(${kefuimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]">
|
|
||||||
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
<!-- #endif -->
|
|
||||||
|
|
||||||
<!-- 电话按钮(始终显示) -->
|
<!-- 电话按钮 -->
|
||||||
<view v-if="fixBtnShow" class="btn-item common-bg" @click="call()"
|
<view
|
||||||
:style="[{ backgroundImage: phoneimg ? `url(${phoneimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]">
|
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>
|
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -56,16 +92,13 @@ export default {
|
|||||||
return {
|
return {
|
||||||
pageCount: 0,
|
pageCount: 0,
|
||||||
fixBtnShow: true,
|
fixBtnShow: true,
|
||||||
|
|
||||||
shopInfo: null,
|
shopInfo: null,
|
||||||
currentLangIndex: 0,
|
currentLangIndex: 0,
|
||||||
langIndexMap: {},
|
langIndexMap: {},
|
||||||
|
customerService: null,
|
||||||
customerService: null,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// 安全读取 shopInfo 中的字段,避免 undefined 报错
|
|
||||||
bgUrl() {
|
bgUrl() {
|
||||||
return this.shopInfo?.bgUrl || '';
|
return this.shopInfo?.bgUrl || '';
|
||||||
},
|
},
|
||||||
@@ -84,9 +117,6 @@ export default {
|
|||||||
isLanguageSwitchEnabled() {
|
isLanguageSwitchEnabled() {
|
||||||
return !!this.shopInfo?.ischina;
|
return !!this.shopInfo?.ischina;
|
||||||
},
|
},
|
||||||
enableAIChat() {
|
|
||||||
return !!this.shopInfo?.enableAIChat;
|
|
||||||
},
|
|
||||||
currentLangDisplayName() {
|
currentLangDisplayName() {
|
||||||
const lang = this.langIndexMap[this.currentLangIndex];
|
const lang = this.langIndexMap[this.currentLangIndex];
|
||||||
return lang === 'zh-cn' ? 'EN' : 'CN';
|
return lang === 'zh-cn' ? 'EN' : 'CN';
|
||||||
@@ -96,30 +126,84 @@ export default {
|
|||||||
},
|
},
|
||||||
customButtonStyle() {
|
customButtonStyle() {
|
||||||
return this.shopInfo?.floatingButton?.button || {};
|
return this.shopInfo?.floatingButton?.button || {};
|
||||||
|
},
|
||||||
|
unreadCount() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.getUnreadCount();
|
||||||
|
},
|
||||||
|
currentKefuImg() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.getKefuButtonIcon();
|
||||||
|
},
|
||||||
|
isWeappOfficialKefu() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.isWeappOfficialKefu();
|
||||||
|
},
|
||||||
|
isAIKefu() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.isAIKefu();
|
||||||
|
},
|
||||||
|
isWxworkKefu() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.isWxworkKefu();
|
||||||
|
},
|
||||||
|
isThirdKefu() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.isThirdKefu();
|
||||||
|
},
|
||||||
|
showWeappSystemKefu() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.shouldShowExtraWeappSystemKefu();
|
||||||
|
},
|
||||||
|
hasValidKefuConfig() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.hasValidKefuConfig();
|
||||||
|
},
|
||||||
|
//根据显示的按钮数量动态计算容器高度
|
||||||
|
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() {
|
created() {
|
||||||
this.customerService = createCustomerService(this);
|
|
||||||
this.initLanguage();
|
this.initLanguage();
|
||||||
|
this.pageCount = getCurrentPages().length;
|
||||||
uni.getStorage({
|
uni.getStorage({
|
||||||
key: 'shopInfo',
|
key: 'shopInfo',
|
||||||
success: (e) => {
|
success: (e) => {
|
||||||
|
console.log('【调试】当前 shopInfo:', e.data);
|
||||||
this.shopInfo = e.data;
|
this.shopInfo = e.data;
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
console.warn('未获取到 shopInfo,使用默认设置');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// 初始化 customerService 实例
|
||||||
|
this.customerService = createCustomerService(this);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化多语言配置
|
|
||||||
*/
|
|
||||||
initLanguage() {
|
initLanguage() {
|
||||||
this.langList = this.$langConfig.list();
|
this.langList = this.$langConfig.list();
|
||||||
this.langIndexMap = {};
|
this.langIndexMap = {};
|
||||||
for (let i = 0; i < this.langList.length; i++) {
|
for (let i = 0; i < this.langList.length; i++) {
|
||||||
this.langIndexMap[i] = this.langList[i].value;
|
this.langIndexMap[i] = this.langList[i].value;
|
||||||
}
|
}
|
||||||
const savedLang = uni.getStorageSync('lang');
|
const savedLang = this.$langConfig.getCurrentLocale();
|
||||||
if (savedLang) {
|
if (savedLang) {
|
||||||
for (let i = 0; i < this.langList.length; i++) {
|
for (let i = 0; i < this.langList.length; i++) {
|
||||||
if (this.langList[i].value === savedLang) {
|
if (this.langList[i].value === savedLang) {
|
||||||
@@ -132,36 +216,30 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 电话联系客服
|
|
||||||
*/
|
|
||||||
call() {
|
call() {
|
||||||
this.customerService.makePhoneCall(this.tel);
|
this.customerService.makePhoneCallByNumber(this.tel);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 切换中英文语言,并刷新当前页面(保留所有参数)
|
|
||||||
*/
|
|
||||||
toggleLanguage() {
|
toggleLanguage() {
|
||||||
this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
|
this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
|
||||||
const targetLang = this.langIndexMap[this.currentLangIndex];
|
const targetLang = this.langIndexMap[this.currentLangIndex];
|
||||||
|
|
||||||
// 调用语言切换逻辑(设置 storage + 清空缓存)
|
uni.setStorageSync("lang", targetLang);
|
||||||
this.$langConfig.change(targetLang);
|
|
||||||
|
const pages = getCurrentPages();
|
||||||
|
const currentPage = pages[pages.length - 1];
|
||||||
|
const currentRoute = currentPage.route;
|
||||||
|
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/' + currentRoute
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
handleUnifiedKefuClick() {
|
||||||
* 打开 AI 智能助手
|
this.customerService.handleUnifiedKefuClick({
|
||||||
*/
|
sendMessageTitle: '来自悬浮按钮的咨询',
|
||||||
openAIChat() {
|
sendMessagePath: '/pages/index/index'
|
||||||
this.$util.redirectTo(this.$util.AI_CHAT_PAGE_URL);
|
});
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开客服选择对话框
|
|
||||||
*/
|
|
||||||
openCustomerSelectPopup() {
|
|
||||||
this.customerService.openCustomerSelectPopupDialog();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,17 +274,15 @@ export default {
|
|||||||
margin: 14rpx 0;
|
margin: 14rpx 0;
|
||||||
transition: 0.1s;
|
transition: 0.1s;
|
||||||
color: var(--hover-nav-text-color);
|
color: var(--hover-nav-text-color);
|
||||||
border-radius: 40rpx;
|
border-radius: 50%;
|
||||||
width: 80rpx;
|
width: 80rpx;
|
||||||
height: 80rpx;
|
height: 80rpx;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 定义共同的背景颜色 */
|
|
||||||
.common-bg {
|
.common-bg {
|
||||||
background-color: var(--hover-nav-bg-color);
|
background-color: var(--hover-nav-bg-color);
|
||||||
/* 使用变量以保持一致性 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-item text {
|
.btn-item text {
|
||||||
@@ -236,7 +312,12 @@ export default {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.kefu-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-icon {
|
.ai-icon {
|
||||||
font-size: 40rpx;
|
font-size: 40rpx;
|
||||||
|
|||||||
@@ -53,8 +53,15 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.listenPrivacySettingChange()
|
// 检查配置,决定是否显示隐私协议
|
||||||
this.curPageShow()
|
const shopInfo = uni.getStorageSync('shopInfo');
|
||||||
|
if (shopInfo?.ischina == 1 && shopInfo?.index_login_auth == 1) {
|
||||||
|
this.listenPrivacySettingChange()
|
||||||
|
this.curPageShow()
|
||||||
|
} else {
|
||||||
|
// 如果不需要显示隐私协议,直接触发同意事件
|
||||||
|
this.$emit('agree');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
try {
|
try {
|
||||||
@@ -152,28 +159,62 @@ export default {
|
|||||||
},
|
},
|
||||||
// 主动查询用户隐私政策授权状态
|
// 主动查询用户隐私政策授权状态
|
||||||
proactive() {
|
proactive() {
|
||||||
|
// 检查配置,决定是否显示隐私协议
|
||||||
|
const shopInfo = uni.getStorageSync('shopInfo');
|
||||||
|
if (!(shopInfo?.ischina == 1 && shopInfo?.index_login_auth == 1)) {
|
||||||
|
// 如果不需要显示隐私协议,直接触发同意事件
|
||||||
|
this.$emit('agree');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
if (wx.getPrivacySetting) {
|
if (wx.getPrivacySetting) {
|
||||||
wx.getPrivacySetting({
|
wx.getPrivacySetting({
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
// console.log(res)
|
// console.log(res)
|
||||||
if (res.needAuthorization) {
|
if (res.needAuthorization) {
|
||||||
this.popUp()
|
// 检查本地存储中是否已经同意过隐私政策
|
||||||
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
|
const privacyAgreed = uni.getStorageSync('privacyAgreed');
|
||||||
this.closeOtherPagePopUp(this.disPopUp)
|
if (!privacyAgreed) {
|
||||||
|
this.popUp()
|
||||||
|
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
|
||||||
|
this.closeOtherPagePopUp(this.disPopUp)
|
||||||
|
} else {
|
||||||
|
this.$emit('agree')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.$emit('agree')
|
this.$emit('agree')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.$emit('agree')
|
// 检查本地存储中是否已经同意过隐私政策
|
||||||
|
const privacyAgreed = uni.getStorageSync('privacyAgreed');
|
||||||
|
if (privacyAgreed) {
|
||||||
|
this.$emit('agree');
|
||||||
|
} else {
|
||||||
|
this.popUp()
|
||||||
|
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
|
||||||
|
this.closeOtherPagePopUp(this.disPopUp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef QUICKAPP-WEBVIEW
|
// #ifdef QUICKAPP-WEBVIEW
|
||||||
this.getPrivacySettingByQuickApp();
|
this.getPrivacySettingByQuickApp();
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5 || WEB
|
||||||
|
// 检查本地存储中是否已经同意过隐私政策
|
||||||
|
const privacyAgreed = uni.getStorageSync('privacyAgreed');
|
||||||
|
if (privacyAgreed) {
|
||||||
|
this.$emit('agree');
|
||||||
|
} else {
|
||||||
|
this.popUp()
|
||||||
|
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
|
||||||
|
this.closeOtherPagePopUp(this.disPopUp)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
},
|
},
|
||||||
//初始化监听程序
|
//初始化监听程序
|
||||||
curPageShow() {
|
curPageShow() {
|
||||||
@@ -261,6 +302,8 @@ export default {
|
|||||||
this.privacyResolves.clear()
|
this.privacyResolves.clear()
|
||||||
//关闭弹窗
|
//关闭弹窗
|
||||||
this.disPopUp()
|
this.disPopUp()
|
||||||
|
// 保存用户授权状态到本地存储,无论同意还是不同意,都不再重复弹出
|
||||||
|
uni.setStorageSync('privacyAgreed', true);
|
||||||
//退出小程序
|
//退出小程序
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
content: '未同意隐私协议,无法使用相关功能',
|
content: '未同意隐私协议,无法使用相关功能',
|
||||||
@@ -281,10 +324,8 @@ export default {
|
|||||||
//关闭弹窗
|
//关闭弹窗
|
||||||
this.disPopUp()
|
this.disPopUp()
|
||||||
|
|
||||||
// #ifdef QUICKAPP-WEBVIEW || H5 || WEB
|
// 保存用户授权状态到本地存储,用于所有环境
|
||||||
// 保存用户授权状态到本地存储,用于快应用Webview组件中的H5方式处理
|
|
||||||
uni.setStorageSync('privacyAgreed', true);
|
uni.setStorageSync('privacyAgreed', true);
|
||||||
// #endif
|
|
||||||
this.$emit('agree')
|
this.$emit('agree')
|
||||||
},
|
},
|
||||||
//打开弹窗
|
//打开弹窗
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ export const lang = {
|
|||||||
title: '商品分类',
|
title: '商品分类',
|
||||||
search:'商品搜索',
|
search:'商品搜索',
|
||||||
seeMore : '查看更多',
|
seeMore : '查看更多',
|
||||||
Make: "询底价"
|
Make: "立即咨询"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export const lang = {
|
|||||||
//title为每个页面的标题
|
//title为每个页面的标题
|
||||||
title: '',
|
title: '',
|
||||||
select: '选择',
|
select: '选择',
|
||||||
details:'资源详情',
|
details:'商品详情',
|
||||||
params: '参数',
|
params: '参数',
|
||||||
service: '商品服务',
|
service: '商品服务',
|
||||||
allGoods: '全部商品',
|
allGoods: '全部商品',
|
||||||
@@ -11,7 +11,7 @@ export const lang = {
|
|||||||
home:'首页',
|
home:'首页',
|
||||||
cart:'购物车',
|
cart:'购物车',
|
||||||
leave:'立即留言',
|
leave:'立即留言',
|
||||||
make:'联系我们',
|
make:'立即咨询',
|
||||||
|
|
||||||
send:'配送',
|
send:'配送',
|
||||||
express:'快递发货',
|
express:'快递发货',
|
||||||
@@ -22,7 +22,7 @@ export const lang = {
|
|||||||
status:'该商品已下架',
|
status:'该商品已下架',
|
||||||
sellout:'库存不足',
|
sellout:'库存不足',
|
||||||
max:'已达最大限购数量',
|
max:'已达最大限购数量',
|
||||||
makebtn:'价格电议',
|
makebtn:'立即咨询',
|
||||||
sales:'销量',
|
sales:'销量',
|
||||||
stock:'库存',
|
stock:'库存',
|
||||||
kefu:'客服',
|
kefu:'客服',
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ export const lang = {
|
|||||||
Price:'价格',
|
Price:'价格',
|
||||||
Filter:'筛选',
|
Filter:'筛选',
|
||||||
Search:'请输入您要搜索的商品',
|
Search:'请输入您要搜索的商品',
|
||||||
Make:'立即询底价',
|
Make:'立即咨询',
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,11 +71,14 @@
|
|||||||
"scope.userLocation" : {
|
"scope.userLocation" : {
|
||||||
"desc" : "为了更好地为您提供服务"
|
"desc" : "为了更好地为您提供服务"
|
||||||
},
|
},
|
||||||
"scope.writePhotosAlbum" : {
|
|
||||||
"desc" : "为了更好地为您提供服务"
|
|
||||||
},
|
|
||||||
"scope.userClipboard" : {
|
"scope.userClipboard" : {
|
||||||
"desc" : "为了方便您复制信息"
|
"desc" : "为了方便您复制信息"
|
||||||
|
},
|
||||||
|
"scope.camera" : {
|
||||||
|
"desc" : "用于拍照上传头像"
|
||||||
|
},
|
||||||
|
"scope.writePhotosAlbum" : {
|
||||||
|
"desc" : "用于从相册选择和保存头像"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requiredPrivateInfos" : [ "chooseLocation", "getLocation", "chooseAddress" ],
|
"requiredPrivateInfos" : [ "chooseLocation", "getLocation", "chooseAddress" ],
|
||||||
@@ -104,7 +107,7 @@
|
|||||||
},
|
},
|
||||||
"router" : {
|
"router" : {
|
||||||
"mode" : "history",
|
"mode" : "history",
|
||||||
"base" : "/hwappx/common/"
|
"base" : "/hwappx/test/"
|
||||||
},
|
},
|
||||||
"title" : "",
|
"title" : "",
|
||||||
"devServer" : {
|
"devServer" : {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
{
|
{
|
||||||
"path": "detail",
|
"path": "detail",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "资源详情"
|
"navigationBarTitleText": "商品详情"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ export default {
|
|||||||
return {
|
return {
|
||||||
minScrollTop: 100, // 设置回到顶端按钮显示要求,最小页面滚动距离
|
minScrollTop: 100, // 设置回到顶端按钮显示要求,最小页面滚动距离
|
||||||
wechatQrcode: '', // 公众号二维码
|
wechatQrcode: '', // 公众号二维码
|
||||||
diyRoute: '/pages/index/index'
|
diyRoute: '/pages/index/index',
|
||||||
|
shopInfo: null // 店铺信息
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad(option) {
|
onLoad(option) {
|
||||||
@@ -15,10 +16,15 @@ export default {
|
|||||||
// #endif
|
// #endif
|
||||||
this.name = option.name || 'DIY_VIEW_INDEX'; // 根据店铺运营模式,打开平台(shop)或者连锁门店(stroe)页面,接口会自行判断
|
this.name = option.name || 'DIY_VIEW_INDEX'; // 根据店铺运营模式,打开平台(shop)或者连锁门店(stroe)页面,接口会自行判断
|
||||||
|
|
||||||
|
// 获取店铺信息
|
||||||
|
this.shopInfo = uni.getStorageSync('shopInfo');
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
// 获取关注公众号二维码
|
// 获取关注公众号二维码
|
||||||
this.getFollowQrcode();
|
this.getFollowQrcode();
|
||||||
|
|
||||||
|
// 重新获取店铺信息
|
||||||
|
this.shopInfo = uni.getStorageSync('shopInfo');
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// 监听图片、文字、商品列表等组件的点击事件
|
// 监听图片、文字、商品列表等组件的点击事件
|
||||||
@@ -59,6 +65,11 @@ export default {
|
|||||||
officialAccountsClose() {
|
officialAccountsClose() {
|
||||||
this.$refs.officialAccountsPopup.close();
|
this.$refs.officialAccountsPopup.close();
|
||||||
},
|
},
|
||||||
|
// 判断是否需要登录授权
|
||||||
|
_needLoginAuth() {
|
||||||
|
// 检查 index_login_auth 都开启时才需要登录授权
|
||||||
|
return this.shopInfo?.index_login_auth == 1;
|
||||||
|
},
|
||||||
// 统一处理点击及触摸事件
|
// 统一处理点击及触摸事件
|
||||||
_handleDiyGroupInteractionEvent(payload) {
|
_handleDiyGroupInteractionEvent(payload) {
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
@@ -66,6 +77,11 @@ export default {
|
|||||||
return true;
|
return true;
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
|
// 如果不需要登录授权,直接返回 true 继续传播
|
||||||
|
if (!this._needLoginAuth()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// 如果已登录,直接返回 true 继续传播
|
// 如果已登录,直接返回 true 继续传播
|
||||||
if (this.storeToken) {
|
if (this.storeToken) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
<view>
|
<view>
|
||||||
<view scroll-y="true" class="goods-detail" :class="isIphoneX ? 'active' : ''">
|
<view scroll-y="true" class="goods-detail" :class="isIphoneX ? 'active' : ''">
|
||||||
<view class="goods-container">
|
<view class="goods-container">
|
||||||
|
<!-- AI客服悬浮按钮 -->
|
||||||
|
<view class="ai-chat-float-btn" @tap.stop="$emit('aiChatClick')" v-if="showAIChatBtn">
|
||||||
|
<image :src="aiAvatarUrl" mode="aspectFill" class="ai-avatar-icon" />
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 弹幕 -->
|
<!-- 弹幕 -->
|
||||||
<pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai"
|
<pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai"
|
||||||
:duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true"
|
:duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true"
|
||||||
@@ -17,7 +22,7 @@
|
|||||||
:item-id="'goods_id_' + index">
|
:item-id="'goods_id_' + index">
|
||||||
<view class="item" @click="previewMedia(index)">
|
<view class="item" @click="previewMedia(index)">
|
||||||
<image :src="$util.img(item, { size: 'big' })" @error="swiperImageError(index)"
|
<image :src="$util.img(item, { size: 'big' })" @error="swiperImageError(index)"
|
||||||
mode="aspectFit" />
|
mode="aspectFit" :show-menu-by-longpress="true" />
|
||||||
</view>
|
</view>
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
@@ -458,6 +463,8 @@
|
|||||||
// 商品详情视图
|
// 商品详情视图
|
||||||
import scroll from '@/common/js/scroll-view.js';
|
import scroll from '@/common/js/scroll-view.js';
|
||||||
import detail from './detail.js';
|
import detail from './detail.js';
|
||||||
|
import IMAGE_CONFIG from '@/common/js/image-config.js';
|
||||||
|
import { createCustomerService } from '@/common/js/customer-service.js';
|
||||||
|
|
||||||
import pengpaiFadeinOut from '../pengpai-fadein-out/pengpai-fadein-out.vue';
|
import pengpaiFadeinOut from '../pengpai-fadein-out/pengpai-fadein-out.vue';
|
||||||
|
|
||||||
@@ -474,6 +481,15 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
pengpaiFadeinOut
|
pengpaiFadeinOut
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
aiAvatarUrl() {
|
||||||
|
return this.$util.img(IMAGE_CONFIG.aiAvatar);
|
||||||
|
},
|
||||||
|
showAIChatBtn() {
|
||||||
|
const customerService = createCustomerService(this);
|
||||||
|
return customerService.hasValidKefuConfig() && customerService.isAIKefu();
|
||||||
|
}
|
||||||
|
},
|
||||||
mixins: [scroll, detail]
|
mixins: [scroll, detail]
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -481,4 +497,36 @@ export default {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '@/common/css/goods_detail.scss';
|
@import '@/common/css/goods_detail.scss';
|
||||||
</style>
|
</style>
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.ai-chat-float-btn {
|
||||||
|
position: fixed;
|
||||||
|
right: 20rpx;
|
||||||
|
top: 100rpx;
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15);
|
||||||
|
z-index: 9999;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-chat-float-btn:active {
|
||||||
|
transform: scale(0.9);
|
||||||
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-chat-float-btn .iconfont {
|
||||||
|
font-size: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-chat-float-btn .ai-avatar-icon {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -26,18 +26,38 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
diyData: null
|
diyData: null,
|
||||||
|
mpShareData: null //小程序分享数据
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
this.$util.hideHomeButton();
|
||||||
//刷新多语言
|
//刷新多语言
|
||||||
this.$langConfig.refresh();
|
this.$langConfig.refresh();
|
||||||
|
|
||||||
uni.hideTabBar();
|
|
||||||
this.getDiyInfo();
|
this.getDiyInfo();
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
|
this.$util.hideHomeButton();
|
||||||
if (this.$refs.category) this.$refs.category[0].pageShow();
|
if (this.$refs.category) this.$refs.category[0].pageShow();
|
||||||
|
|
||||||
|
//小程序分享
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.$util.getMpShare('/pages_goods/category').then(res => {
|
||||||
|
this.mpShareData = res;
|
||||||
|
}).catch(err => {
|
||||||
|
// 如果后台没配置,用默认值
|
||||||
|
this.mpShareData = {
|
||||||
|
appMessage: {
|
||||||
|
title: '发现超多好物,快来看看',
|
||||||
|
path: '/pages_goods/category'
|
||||||
|
},
|
||||||
|
timeLine: {
|
||||||
|
title: '发现超多好物,快来看看',
|
||||||
|
query: '/pages_goods/category'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
},
|
},
|
||||||
onUnload() {
|
onUnload() {
|
||||||
if (!this.storeToken && this.$refs.login) this.$refs.login.cancelCompleteInfo();
|
if (!this.storeToken && this.$refs.login) this.$refs.login.cancelCompleteInfo();
|
||||||
@@ -69,6 +89,24 @@ export default {
|
|||||||
onPullDownRefresh() {
|
onPullDownRefresh() {
|
||||||
uni.hideTabBar();
|
uni.hideTabBar();
|
||||||
this.getDiyInfo();
|
this.getDiyInfo();
|
||||||
|
},
|
||||||
|
onShareAppMessage() {
|
||||||
|
return this.mpShareData?.appMessage || {
|
||||||
|
title: '发现超多好物,快来看看',
|
||||||
|
path: '/pages_goods/category'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onShareTimeline() {
|
||||||
|
return this.mpShareData?.timeLine || {
|
||||||
|
title: '发现超多好物,快来看看',
|
||||||
|
query: '/pages_goods/category'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onAddToFavorites() {
|
||||||
|
return {
|
||||||
|
title: '发现超多好物,快来看看',
|
||||||
|
path: '/pages_goods/category'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
</view> -->
|
</view> -->
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
|
|
||||||
<goods-detail-view :goodsSkuDetail="goodsSkuDetail" ref="goodsDetailView">
|
<goods-detail-view :goodsSkuDetail="goodsSkuDetail" ref="goodsDetailView" @aiChatClick="sendToAIChat(goodsSkuDetail)">
|
||||||
<!-- 价格区域 -->
|
<!-- 价格区域 -->
|
||||||
<template v-slot:price>
|
<template v-slot:price>
|
||||||
<!-- 限时折扣 -->
|
<!-- 限时折扣 -->
|
||||||
@@ -77,7 +77,6 @@
|
|||||||
</block>
|
</block>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<template>
|
<template>
|
||||||
<text class="price price-font" style="font-weight: 600;">{{$lang('makebtn')}}</text>
|
|
||||||
</template>
|
</template>
|
||||||
</block>
|
</block>
|
||||||
</view>
|
</view>
|
||||||
@@ -461,11 +460,12 @@
|
|||||||
<ns-goods-action-icon :text="$lang('follow')" :icon="whetherCollection == 1 ? 'icon-likefill color-base-text' : 'icon-guanzhu'" @click="editCollection" />
|
<ns-goods-action-icon :text="$lang('follow')" :icon="whetherCollection == 1 ? 'icon-likefill color-base-text' : 'icon-guanzhu'" @click="editCollection" />
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<block v-if="goodsSkuDetail.isinformation >= 1">
|
<block v-if="goodsSkuDetail.isinformation >= 1">
|
||||||
|
|
||||||
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 1" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="phoneClick(goodsSkuDetail.goods_mobile)" :text="$lang('make')" :disabled="false" />
|
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 1" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="phoneClick(goodsSkuDetail.goods_mobile)" :text="$lang('make')" :disabled="false" />
|
||||||
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="showinformation" :text="$lang('leave')" :disabled="false" />
|
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="showinformation" :text="$lang('leave')" :disabled="false" />
|
||||||
<!-- <ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="buyNow" text="商品留言" :disabled="false" /> -->
|
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 3" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="goToAIChat" text="智能客服" :disabled="false" />
|
||||||
|
<!-- <ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="buyNow" text="商品留言" :disabled="false" /> -->
|
||||||
|
|
||||||
</block>
|
</block>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<block v-if="goodsSkuDetail.stock == 0 && !goodsSkuDetail.sku_spec_format">
|
<block v-if="goodsSkuDetail.stock == 0 && !goodsSkuDetail.sku_spec_format">
|
||||||
@@ -515,6 +515,19 @@
|
|||||||
|
|
||||||
<!-- 隐私弹窗 -->
|
<!-- 隐私弹窗 -->
|
||||||
<privacy-popup ref="privacyPopup"></privacy-popup>
|
<privacy-popup ref="privacyPopup"></privacy-popup>
|
||||||
|
|
||||||
|
<!-- 联系电话弹窗 -->
|
||||||
|
<uni-popup ref="contactPopup" type="center">
|
||||||
|
<view class="contact-popup">
|
||||||
|
<view class="contact-content">
|
||||||
|
<text class="contact-text">可在手机端拨打 021-51815181</text>
|
||||||
|
</view>
|
||||||
|
<view class="contact-buttons">
|
||||||
|
<button class="contact-btn cancel-btn" @click="closeContactPopup">取消</button>
|
||||||
|
<button class="contact-btn copy-btn" @click="copyPhoneNumber">复制到剪切板</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -531,9 +544,61 @@ export default {
|
|||||||
goodsDetailView,
|
goodsDetailView,
|
||||||
nsGoodsPromotion
|
nsGoodsPromotion
|
||||||
},
|
},
|
||||||
mixins: [base, detail, scroll]
|
mixins: [base, detail, scroll],
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 发送商品信息到智能客服
|
||||||
|
* @param {Object} item 商品信息
|
||||||
|
*/
|
||||||
|
sendToAIChat(item) {
|
||||||
|
this.$refs.contactPopup.open();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转到智能客服页面
|
||||||
|
*/
|
||||||
|
goToAIChat() {
|
||||||
|
const productInfo = {
|
||||||
|
goods_id: this.goodsSkuDetail.goods_id || '',
|
||||||
|
goods_name: this.goodsSkuDetail.goods_name || '',
|
||||||
|
price: this.goodsSkuDetail.discount_price || this.goodsSkuDetail.member_price || this.goodsSkuDetail.price || '',
|
||||||
|
image: this.goodsSkuDetail.sku_image || '',
|
||||||
|
category_id: this.goodsSkuDetail.category_id || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
uni.setStorageSync('selectedProduct', productInfo);
|
||||||
|
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages_tool/ai-chat/index'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭联系电话弹窗
|
||||||
|
*/
|
||||||
|
closeContactPopup() {
|
||||||
|
this.$refs.contactPopup.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制电话号码到剪切板
|
||||||
|
*/
|
||||||
|
copyPhoneNumber() {
|
||||||
|
uni.setClipboardData({
|
||||||
|
data: '021-51815181',
|
||||||
|
success: () => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '复制成功',
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
|
this.closeContactPopup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '@/common/css/goods_detail.scss';
|
@import '@/common/css/goods_detail.scss';
|
||||||
@import './public/css/detail.scss';
|
@import './public/css/detail.scss';
|
||||||
@@ -545,6 +610,57 @@ export default {
|
|||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contact-popup {
|
||||||
|
width: 600rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-content {
|
||||||
|
padding: 60rpx 40rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333333;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-buttons {
|
||||||
|
display: flex;
|
||||||
|
border-top: 1px solid #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 90rpx;
|
||||||
|
line-height: 90rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-btn::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
color: #333333;
|
||||||
|
background: #ffffff;
|
||||||
|
border-right: 1px solid #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn {
|
||||||
|
color: #ffffff;
|
||||||
|
background: #54c952;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
::v-deep .action-icon-wrap .iconfont.icon-shouye1 {
|
::v-deep .action-icon-wrap .iconfont.icon-shouye1 {
|
||||||
@@ -640,4 +756,5 @@ export default {
|
|||||||
height: 72rpx;
|
height: 72rpx;
|
||||||
line-height: 72rpx;
|
line-height: 72rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
<view class="goods-item margin-bottom" v-for="(item, index) in goodsList" :key="index"
|
<view class="goods-item margin-bottom" v-for="(item, index) in goodsList" :key="index"
|
||||||
@click="toDetail(item)">
|
@click="toDetail(item)">
|
||||||
<view class="goods-img">
|
<view class="goods-img">
|
||||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"></image>
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" :show-menu-by-longpress="true"></image>
|
||||||
<view class="color-base-bg goods-tag" v-if="goodsTag(item) != ''">{{ goodsTag(item) }}
|
<view class="color-base-bg goods-tag" v-if="goodsTag(item) != ''">{{ goodsTag(item) }}
|
||||||
</view>
|
</view>
|
||||||
<view class="sell-out" v-if="item.goods_stock <= 0">
|
<view class="sell-out" v-if="item.goods_stock <= 0">
|
||||||
@@ -75,68 +75,23 @@
|
|||||||
<text class="unit price-style small">.{{
|
<text class="unit price-style small">.{{
|
||||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="discount-price" v-else>
|
|
||||||
<text class="price price-style large">{{ langstatus ? $lang('Make') : '询底价' }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
|
|
||||||
<view class="member-price-tag"
|
|
||||||
v-if="item.member_price && item.member_price == showPrice(item)">
|
|
||||||
<image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix"></image>
|
|
||||||
</view>
|
|
||||||
<view class="member-price-tag" v-else-if="item.promotion_type == 1">
|
|
||||||
<image :src="$util.img('public/uniapp/index/discount.png')" mode="widthFix"></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="pro-info" v-if="item.isinformation == 0">
|
<view class="pro-info" v-if="item.isinformation == 0">
|
||||||
<view class="delete-price color-tip price-font" v-if="showMarketPrice(item)">
|
|
||||||
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
|
|
||||||
<text>{{ showMarketPrice(item) }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="block-wrap">
|
<view class="block-wrap">
|
||||||
<view class="sale color-tip" v-if="item.sale_show">已售{{ item.sale_num }}{{ item.unit
|
<view class="sale" v-if="item.sale_show">已售{{ item.sale_num }}{{ item.unit
|
||||||
? item.unit : '件' }}</view>
|
? item.unit : '件' }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="cart-action-wrap" v-if="config.control && item.is_virtual == 0">
|
<view class="cart-action-wrap" v-if="config.control && item.is_virtual == 0">
|
||||||
<!-- 购物车图标 -->
|
<view class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
||||||
<view v-if="config.style == 'icon-cart'" :style="{
|
|
||||||
color: config.theme == 'diy' ? config.textColor : '',
|
|
||||||
borderColor: config.theme == 'diy' ? config.textColor : ''
|
|
||||||
}" class="cart shopping-cart-btn iconfont icon-gouwuche click-wrap" :id="'goods-' + item.id"
|
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||||
|
购买
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<!--加号图标 -->
|
</view>
|
||||||
<view v-else-if="config.style == 'icon-add'" :style="{
|
<view class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
||||||
color: config.theme == 'diy' ? config.textColor : '',
|
<view class="ai-chat-btn" @click.stop="sendToAIChat(item)">
|
||||||
borderColor: config.theme == 'diy' ? config.textColor : ''
|
立即咨询
|
||||||
}" class="cart plus-sign-btn iconfont icon-add1 click-wrap" :id="'goods-' + item.id"
|
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
|
||||||
<view class="click-event"></view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 按钮 -->
|
|
||||||
<view v-else-if="config.style == 'button'" :style="{
|
|
||||||
backgroundColor: config.theme == 'diy' ? config.bgColor : '',
|
|
||||||
color: config.theme == 'diy' ? config.textColor : '',
|
|
||||||
fontWeight: config.theme == 'diy' ? (config.fontWeight ? 'bold' : 'normal') : '',
|
|
||||||
padding: config.theme == 'diy' ? '12rpx ' + config.padding * 2 + 'rpx' : ''
|
|
||||||
}" class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
|
||||||
{{ config.text }}
|
|
||||||
<view class="click-event"></view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!--自定义图标 -->
|
|
||||||
<view v-else-if="config.style == 'icon-diy'" :style="{
|
|
||||||
color: config.theme == 'diy' ? config.textColor : ''
|
|
||||||
}" class="icon-diy click-wrap" :id="'goods-' + item.id"
|
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
|
||||||
<view class="click-event"></view>
|
|
||||||
<diy-icon :icon="config.iconDiy.icon"
|
|
||||||
:value="config.iconDiy.style ? config.iconDiy.style : null"></diy-icon>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -147,7 +102,7 @@
|
|||||||
@click="toDetail(item)"
|
@click="toDetail(item)"
|
||||||
:style="{ left: listPosition[index] ? listPosition[index].left : '', top: listPosition[index] ? listPosition[index].top : '' }">
|
:style="{ left: listPosition[index] ? listPosition[index].left : '', top: listPosition[index] ? listPosition[index].top : '' }">
|
||||||
<view class="goods-img">
|
<view class="goods-img">
|
||||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"></image>
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" :show-menu-by-longpress="true"></image>
|
||||||
<view class="color-base-bg goods-tag" v-if="goodsTag(item) != ''">{{ goodsTag(item) }}
|
<view class="color-base-bg goods-tag" v-if="goodsTag(item) != ''">{{ goodsTag(item) }}
|
||||||
</view>
|
</view>
|
||||||
<view class="sell-out" v-if="item.stock <= 0">
|
<view class="sell-out" v-if="item.stock <= 0">
|
||||||
@@ -168,66 +123,23 @@
|
|||||||
<text class="unit price-style small">.{{
|
<text class="unit price-style small">.{{
|
||||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="discount-price" v-else>
|
|
||||||
<text class="price price-style large">{{ langstatus ? $lang('Make') : '询底价' }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="member-price-tag"
|
|
||||||
v-if="item.member_price && item.member_price == showPrice(item)">
|
|
||||||
<image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix"></image>
|
|
||||||
</view>
|
|
||||||
<view class="member-price-tag" v-else-if="item.promotion_type == 1">
|
|
||||||
<image :src="$util.img('public/uniapp/index/discount.png')" mode="widthFix"></image>
|
|
||||||
</view>
|
|
||||||
<view class="delete-price color-tip price-font" v-if="showMarketPrice(item)">
|
|
||||||
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
|
|
||||||
<text>{{ showMarketPrice(item) }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="pro-info" v-if="item.isinformation == 0">
|
<view class="pro-info" v-if="item.isinformation == 0">
|
||||||
<view class="block-wrap">
|
<view class="block-wrap">
|
||||||
<view class="sale color-tip" v-if="item.sale_show">已售{{ item.sale_num }}{{ item.unit
|
<view class="sale" v-if="item.sale_show">已售{{ item.sale_num }}{{ item.unit
|
||||||
? item.unit : '件' }}</view>
|
? item.unit : '件' }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="cart-action-wrap" v-if="config.control && item.is_virtual == 0">
|
<view class="cart-action-wrap" v-if="config.control && item.is_virtual == 0">
|
||||||
<!-- 购物车图标 -->
|
<view class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
||||||
<view v-if="config.style == 'icon-cart'" :style="{
|
|
||||||
color: config.theme == 'diy' ? config.textColor : '',
|
|
||||||
borderColor: config.theme == 'diy' ? config.textColor : ''
|
|
||||||
}" class="cart shopping-cart-btn iconfont icon-gouwuche click-wrap" :id="'goods-' + item.id"
|
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
||||||
|
购买
|
||||||
<view class="click-event"></view>
|
<view class="click-event"></view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<!--加号图标 -->
|
</view>
|
||||||
<view v-else-if="config.style == 'icon-add'" :style="{
|
<view class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
||||||
color: config.theme == 'diy' ? config.textColor : '',
|
<view class="ai-chat-btn" @click.stop="sendToAIChat(item)">
|
||||||
borderColor: config.theme == 'diy' ? config.textColor : ''
|
立即咨询
|
||||||
}" class="cart plus-sign-btn iconfont icon-add1 click-wrap" :id="'goods-' + item.id"
|
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
|
||||||
<view class="click-event"></view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 按钮 -->
|
|
||||||
<view v-else-if="config.style == 'button'" :style="{
|
|
||||||
backgroundColor: config.theme == 'diy' ? config.bgColor : '',
|
|
||||||
color: config.theme == 'diy' ? config.textColor : '',
|
|
||||||
fontWeight: config.theme == 'diy' ? (config.fontWeight ? 'bold' : 'normal') : '',
|
|
||||||
padding: config.theme == 'diy' ? '12rpx ' + config.padding * 2 + 'rpx' : ''
|
|
||||||
}" class="cart buy-btn click-wrap" :id="'goods-' + item.id"
|
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
|
||||||
{{ config.text }}
|
|
||||||
<view class="click-event"></view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!--自定义图标 -->
|
|
||||||
<view v-else-if="config.style == 'icon-diy'" :style="{
|
|
||||||
color: config.theme == 'diy' ? config.textColor : ''
|
|
||||||
}" class="icon-diy click-wrap" :id="'goods-' + item.id"
|
|
||||||
@click.stop="$refs.goodsSkuIndex.addCart(config.cartEvent, item, $event)">
|
|
||||||
<view class="click-event"></view>
|
|
||||||
<diy-icon :icon="config.iconDiy.icon"
|
|
||||||
:value="config.iconDiy.style ? config.iconDiy.style : null"></diy-icon>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -311,7 +223,14 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
mixins: [list]
|
mixins: [list],
|
||||||
|
methods: {
|
||||||
|
sendToAIChat(item) {
|
||||||
|
this.$util.redirectTo('/pages_goods/detail', {
|
||||||
|
goods_id: item.goods_id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -327,4 +246,24 @@ export default {
|
|||||||
::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||||
max-height: unset !important;
|
max-height: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-chat-btn-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-chat-btn {
|
||||||
|
background-color: #ff0000;
|
||||||
|
color: #fff;
|
||||||
|
padding: 12rpx 30rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -295,7 +295,8 @@
|
|||||||
|
|
||||||
.lineheight-clear {
|
.lineheight-clear {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 商品列表单列样式
|
// 商品列表单列样式
|
||||||
@@ -386,46 +387,30 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-top: 16rpx;
|
margin-top: 0;
|
||||||
|
|
||||||
background-color: var(--main-color);
|
|
||||||
border-radius: 35rpx;
|
|
||||||
padding: 12rpx 24rpx;
|
|
||||||
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
.unit {
|
.unit {
|
||||||
margin-right: 6rpx;
|
margin-right: 6rpx;
|
||||||
color: var(--price-color);
|
color: #ff4444;
|
||||||
}
|
}
|
||||||
.price {
|
.price {
|
||||||
color: var(--price-color);
|
color: #ff4444;
|
||||||
color: #fff !important;
|
font-size: 32rpx !important;
|
||||||
font-size: 27rpx !important;
|
|
||||||
font-weight: bold !important;
|
font-weight: bold !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pro-info {
|
.pro-info {
|
||||||
|
margin-top: 10rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: auto;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.delete-price {
|
|
||||||
text-decoration: line-through;
|
|
||||||
font-size: $font-size-tag !important;
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.unit {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.block-wrap {
|
.block-wrap {
|
||||||
flex: 1;
|
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-right: 20rpx;
|
|
||||||
.sale {
|
.sale {
|
||||||
font-size: $font-size-tag !important;
|
font-size: $font-size-tag !important;
|
||||||
|
color: #999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -543,6 +528,9 @@
|
|||||||
|
|
||||||
.lineheight-clear {
|
.lineheight-clear {
|
||||||
margin-top: 16rpx;
|
margin-top: 16rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.discount-price {
|
.discount-price {
|
||||||
@@ -552,24 +540,26 @@
|
|||||||
|
|
||||||
.unit {
|
.unit {
|
||||||
margin-right: 6rpx;
|
margin-right: 6rpx;
|
||||||
color: var(--price-color);
|
color: #ff4444;
|
||||||
}
|
}
|
||||||
.price {
|
.price {
|
||||||
color: var(--price-color);
|
color: #ff4444;
|
||||||
|
font-size: 32rpx !important;
|
||||||
|
font-weight: bold !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pro-info {
|
.pro-info {
|
||||||
|
margin-top: 10rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: auto;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.block-wrap {
|
.block-wrap {
|
||||||
flex: 1;
|
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-right: 20rpx;
|
|
||||||
.sale {
|
.sale {
|
||||||
font-size: $font-size-tag !important;
|
font-size: $font-size-tag !important;
|
||||||
|
color: #999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -644,9 +634,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.buy-btn {
|
.buy-btn {
|
||||||
background-color: $base-color;
|
background-color: #ff4444;
|
||||||
color: var(--btn-text-color);
|
color: #fff;
|
||||||
border-radius: 50rpx;
|
border-radius: 30rpx;
|
||||||
font-size: $font-size-tag;
|
font-size: $font-size-tag;
|
||||||
padding: 12rpx 30rpx;
|
padding: 12rpx 30rpx;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="discount-price" v-else>
|
<view class="discount-price" v-else>
|
||||||
<text class="price price-style large">{{ $lang('Make') ? $lang('Make') : '询底价'
|
<text class="price price-style large">{{ $lang('Make') ? $lang('Make') : '立即咨询'
|
||||||
}}</text>
|
}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="discount-price" v-else>
|
<view class="discount-price" v-else>
|
||||||
<text class="price price-style large">{{ $lang('Make') ? $lang('Make') : '询底价'
|
<text class="price price-style large">{{ $lang('Make') ? $lang('Make') : '立即咨询'
|
||||||
}}</text>
|
}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="member-price-tag"
|
<view class="member-price-tag"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -248,10 +248,12 @@ export default {
|
|||||||
latitude: 0,
|
latitude: 0,
|
||||||
longitude: 0,
|
longitude: 0,
|
||||||
},
|
},
|
||||||
personnel_bg: ''
|
personnel_bg: '',
|
||||||
|
mpShareData: null //小程序分享数据
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad(option) {
|
onLoad(option) {
|
||||||
|
this.$util.hideHomeButton();
|
||||||
this.$langConfig.refresh();
|
this.$langConfig.refresh();
|
||||||
this.$api.sendRequest({
|
this.$api.sendRequest({
|
||||||
url: '/api/member/personnel',
|
url: '/api/member/personnel',
|
||||||
@@ -301,6 +303,27 @@ export default {
|
|||||||
fail: res => { }
|
fail: res => { }
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onShow() {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.$util.getMpShare('/pages_tool/contact/contact').then(res => {
|
||||||
|
this.mpShareData = res;
|
||||||
|
}).catch(err => {
|
||||||
|
// 如果后台没配置,用默认值
|
||||||
|
this.mpShareData = {
|
||||||
|
appMessage: {
|
||||||
|
title: '联系我们',
|
||||||
|
path: '/pages_tool/contact/contact'
|
||||||
|
},
|
||||||
|
timeLine: {
|
||||||
|
title: '联系我们',
|
||||||
|
query: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
this.$util.hideHomeButton();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 分享文件
|
// 分享文件
|
||||||
shareFile(file) {
|
shareFile(file) {
|
||||||
@@ -445,9 +468,28 @@ export default {
|
|||||||
longitude: parseFloat(this.shop.longitude),
|
longitude: parseFloat(this.shop.longitude),
|
||||||
name: this.$lang('oneClickNavigation'),
|
name: this.$lang('oneClickNavigation'),
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
onShareAppMessage() {
|
||||||
|
return this.mpShareData?.appMessage || {
|
||||||
|
title: '联系我们',
|
||||||
|
path: '/pages_tool/contact/contact'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onShareTimeline() {
|
||||||
|
return this.mpShareData?.timeLine || {
|
||||||
|
title: '联系我们',
|
||||||
|
query: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onAddToFavorites() {
|
||||||
|
return {
|
||||||
|
title: '联系我们',
|
||||||
|
path: '/pages_tool/contact/contact'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -134,7 +134,8 @@ export default {
|
|||||||
levelId: 0,
|
levelId: 0,
|
||||||
levelInfo: {
|
levelInfo: {
|
||||||
bg_color: '#333'
|
bg_color: '#333'
|
||||||
}
|
},
|
||||||
|
mpShareData: null //小程序分享数据
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
@@ -161,7 +162,26 @@ export default {
|
|||||||
});
|
});
|
||||||
this.levelInfo = levelInfo;
|
this.levelInfo = levelInfo;
|
||||||
},
|
},
|
||||||
onShow() { },
|
onShow() {
|
||||||
|
//小程序分享
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.$util.getMpShare('/pages_tool/member/card').then(res => {
|
||||||
|
this.mpShareData = res;
|
||||||
|
}).catch(err => {
|
||||||
|
// 如果后台没配置,用默认值
|
||||||
|
this.mpShareData = {
|
||||||
|
appMessage: {
|
||||||
|
title: '专属会员权益,快来体验',
|
||||||
|
path: '/pages_tool/member/card'
|
||||||
|
},
|
||||||
|
timeLine: {
|
||||||
|
title: '专属会员权益,快来体验',
|
||||||
|
query: '/pages_tool/member/card'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
headimgError() {
|
headimgError() {
|
||||||
this.memberInfo.headimg = this.$util.getDefaultImage().head;
|
this.memberInfo.headimg = this.$util.getDefaultImage().head;
|
||||||
@@ -185,6 +205,24 @@ export default {
|
|||||||
}
|
}
|
||||||
this.$util.redirectTo(this.$util.MEMBER_PAGE_URL);
|
this.$util.redirectTo(this.$util.MEMBER_PAGE_URL);
|
||||||
return true;
|
return true;
|
||||||
|
},
|
||||||
|
onShareAppMessage() {
|
||||||
|
return this.mpShareData?.appMessage || {
|
||||||
|
title: '专属会员权益,快来体验',
|
||||||
|
path: '/pages_tool/member/card'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onShareTimeline() {
|
||||||
|
return this.mpShareData?.timeLine || {
|
||||||
|
title: '专属会员权益,快来体验',
|
||||||
|
query: '/pages_tool/member/card'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onAddToFavorites() {
|
||||||
|
return {
|
||||||
|
title: '专属会员权益,快来体验',
|
||||||
|
path: '/pages_tool/member/card'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
@click.stop="toDetail(item)">
|
@click.stop="toDetail(item)">
|
||||||
<view class="pic">
|
<view class="pic">
|
||||||
<image :src="$util.img(item.goods_image.split(',')[0], { size: 'mid' })" mode="aspectFill"
|
<image :src="$util.img(item.goods_image.split(',')[0], { size: 'mid' })" mode="aspectFill"
|
||||||
@error="goodsImageError(index)"></image>
|
@error="goodsImageError(index)" :show-menu-by-longpress="true"></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="goods_info">
|
<view class="goods_info">
|
||||||
<view class="goods_name font-size-base">{{ item.sku_name }}</view>
|
<view class="goods_name font-size-base">{{ item.sku_name }}</view>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<text class="iconfont" :class="$util.inArray(item.id, idArr) != -1 ? 'icon-yuan_checked color-base-text' : 'icon-yuan_checkbox'"></text>
|
<text class="iconfont" :class="$util.inArray(item.id, idArr) != -1 ? 'icon-yuan_checked color-base-text' : 'icon-yuan_checkbox'"></text>
|
||||||
</view>
|
</view>
|
||||||
<view class="goods-img" @click="toDetail(item)">
|
<view class="goods-img" @click="toDetail(item)">
|
||||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"></image>
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" :show-menu-by-longpress="true"></image>
|
||||||
<view class="color-base-bg goods-tag" v-if="goodsTag(item) != ''">{{ goodsTag(item) }}</view>
|
<view class="color-base-bg goods-tag" v-if="goodsTag(item) != ''">{{ goodsTag(item) }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-wrap" @click="toDetail(item)">
|
<view class="info-wrap" @click="toDetail(item)">
|
||||||
|
|||||||
@@ -86,6 +86,12 @@ export default {
|
|||||||
nsNewGift
|
nsNewGift
|
||||||
},
|
},
|
||||||
mixins: [diyJs, indexJs],
|
mixins: [diyJs, indexJs],
|
||||||
|
onLoad() {
|
||||||
|
this.$util.hideHomeButton();
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
this.$util.hideHomeButton();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
tourl(url) {
|
tourl(url) {
|
||||||
|
|||||||
271
readme.md
271
readme.md
@@ -1,176 +1,155 @@
|
|||||||
# 小程序及快应用前端源码
|
# 小程序及快应用前端源码
|
||||||
|
|
||||||
来源于外包提供的源代码,"0731xcx20微信小程序(1).zip"
|
## 1. 📋 项目说明
|
||||||
|
|
||||||
|
该项目基于 **uni-app** 开发构建,请使用 [HBuilderX](https://www.dcloud.io/hbuilderx.html) 进行代码开发及构建发布。
|
||||||
|
|
||||||
## 项目说明
|
## 2. 🛠️ 开发说明
|
||||||
|
|
||||||
该项目基于 uniapp 开发构建,请使用(HBuilderX)[https://www.dcloud.io/hbuilderx.html] 进行代码开发及构建发布。
|
- 源码基于 **Vue2** 版本
|
||||||
|
- SCSS 采用 **dart-sass** 进行编译输出
|
||||||
|
|
||||||
## 开发说明
|
## 3. 🔧 开发调试说明
|
||||||
|
|
||||||
1. 源码基于Vue2版本,scss采用node-sass进行编译输出。
|
### 3.1 注意事项
|
||||||
|
|
||||||
|
- 应用访问等关键参数的配置来源于 `./common/js/config.js`
|
||||||
|
|
||||||
## 开发调试说明
|
### 3.2 本地调试
|
||||||
|
|
||||||
### 注意点
|
`.local.config.js.example` 是本地调试配置示例。
|
||||||
|
|
||||||
应用访问等关键参数的配置来源于 `./common/js/config.js`
|
拷贝 `.local.config.js.example` 为 `.local.config.js` 文件,默认开发调试模式会自动加载该文件
|
||||||
|
|
||||||
### 小程序调试
|
---
|
||||||
|
|
||||||
|
## 4. 📦 发布说明
|
||||||
|
|
||||||
|
### 4.1 小程序发布
|
||||||
|
|
||||||
## 发布说明
|
#### 4.1.1 基本操作步骤(通用版/定制化版)
|
||||||
|
|
||||||
### 小程序发布
|
##### 4.1.1.1 【前置准备】
|
||||||
|
1. 在项目根目录打开终端安装依赖:
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
*已有依赖可跳过此步骤*
|
||||||
|
|
||||||
基本操作步骤:
|
##### 4.1.1.2 【发布构建】
|
||||||
|
1. 使用 HBuilderX 打开项目(不用改manifest.json的web,只有H5要改 )
|
||||||
|
2. 选择菜单栏「发行」 → 「小程序-微信」→ 「发行」,等待构建完成
|
||||||
|
⚠️ **注意**:底部控制台弹出"请在微信小程序开发者工具中点击上传"后再执行下一步
|
||||||
|
3. 打开资源管理器→项目根目录,右键选择「在终端中打开」,执行命令:
|
||||||
|
```bash
|
||||||
|
npm run mp-weixin
|
||||||
|
```
|
||||||
|
4. 找到项目根目录 `/unpackage/dist/build` 下生成的 mp-weixin 压缩包
|
||||||
|
💡 **示例**:`mp-weixin-2026-01-23-1769152056146.zip`
|
||||||
|
*同时该目录下会生成未压缩的 `mp-weixin` 目录*
|
||||||
|
|
||||||
1. 使用HBuilderX打开项目
|
##### 4.1.1.3 【验证与重命名】
|
||||||
2. 选择菜单栏 "发行" -> "小程序-微信",进行发布构建
|
1. 打开未压缩的 `mp-weixin` 目录,找到 `site.js` 文件,将文件内的 `uniacid` 值改为当前客户编号(如:2812)并保存
|
||||||
3. 然后在终端进入项目根目录,执行 `npm run mp-weixin` 手动输出构建包。例如:mp-weixin-2025-10-31-1761881054836.zip(改id)
|
2. 打开微信开发者工具,导入「mp-weixin」目录,点击「编译」,在开发者工具控制台验证有无报错,以及能否返回对应客户的业务数据
|
||||||
4. 然后将mp-weixin-2025-10-31-1761881054836发给微信开发定制客户技术人员,
|
3. 确保无误后将生成的 mp-weixin 压缩包重命名
|
||||||
5. 定制客户技术人员可以修改解压后,修改项目根目录下的site.js,进行针对客户的信息配置,然后使用微信开发者工具打开发布后的代码进行上传发布
|
- **定制化版**格式:`定制化-客户编号-域名-mp-weixin-当前日期-生成编号.zip`
|
||||||
|
- **通用版**无需重命名
|
||||||
|
|
||||||
|
💡 **示例**:`custom-2812-xcx.aigc-quickapp.com-mp-weixin-2026-01-22-1769152056146.zip`
|
||||||
|
|
||||||
|
🚫 **禁止**:压缩包命名禁止包含 `/ \ : * ? " < > |` 等特殊字符
|
||||||
|
|
||||||
参照:`common\js\config.js` 文件内容说明:
|
##### 4.1.1.4 【交付与最终发布】🔍
|
||||||
|
1. 将重命名后的文件发送给技术人员
|
||||||
|
*📌通用版直接将生成的 mp-weixin 压缩包发送给技术人员*
|
||||||
|
2. **技术人员操作流程**:
|
||||||
|
- 解压压缩包
|
||||||
|
- 确认 `site.js` 中的 `uniacid` 为客户编号
|
||||||
|
- 用微信开发者工具导入解压后的代码目录
|
||||||
|
- 编译验证无误后,上传发布
|
||||||
|
##### 4.1.1.5 【本地设置】
|
||||||
|

|
||||||
|
#####
|
||||||
|
---
|
||||||
|
|
||||||
```js
|
### 4.2 快应用发布
|
||||||
// 发行版本,配置说明
|
|
||||||
let releaseCfg = undefined;
|
|
||||||
try {
|
|
||||||
if (site) {
|
|
||||||
releaseCfg = {
|
|
||||||
baseUrl: site.baseUrl,
|
|
||||||
imgDomain: site.baseUrl,
|
|
||||||
h5Domain: site.baseUrl,
|
|
||||||
uniacid: site.uniacid,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
// 调试版本,配置说明
|
#### 4.2.1 基本操作(通用版/定制化版)
|
||||||
const devCfg = {
|
|
||||||
// 商户ID
|
|
||||||
uniacid: 460, //825
|
|
||||||
|
|
||||||
//api请求地址
|
##### 4.2.1.1 【发布构建】
|
||||||
baseUrl: 'https://xcx30.5g-quickapp.com/',
|
1. 使用 HBuilderX 打开项目
|
||||||
|
2. 打开项目根目录的 `manifest.json` 文件,切换至可视化配置界面:
|
||||||
|
1. 依次点击「Web 配置」→「运行的基础配置」
|
||||||
|
2. 根据情况查看是否修改路径中/hwappx/????/的客户编号
|
||||||
|
📌 **通用版**保留原有 `/hwappx/common/`
|
||||||
|
📌 **测试版**保留原有 `/hwappx/test/`
|
||||||
|
💡 **个性化定制示例**:`/hwappx/2811/`,其中 2811 为定制化版客户编号
|
||||||
|
|
||||||
// 图片域名
|
3. 选择菜单栏「发行」 → 「自定义发行」 →(「H5-xcx.aigc-quickapp.com」查看.local.config.js中站点的网址前缀,站点的网址前缀是什么就选自定义发行中相同的格式)
|
||||||
imgDomain: 'https://xcx30.5g-quickapp.com/',
|
例如:网址是5g.aigc-quickapp.com,自定义发行就选H5-5g.aigc-quickapp.com
|
||||||
|
网址是dev.aigc-quickapp.com,自定义发行就选H5-xcx.aigc-quickapp.com
|
||||||
|
4. 修改以下配置:
|
||||||
|
1. **网站标题**:快应用
|
||||||
|
2. **网站域名**:当前客户域名(示例:xcx.aigc-quickapp.com或者5g.aigc-quickapp.com)
|
||||||
|
3. 确认后点击「发行」等待构建完成
|
||||||
|
|
||||||
// H5端域名
|
⚠️ **注意**:底部控制台弹出“项目 lucky_shop 导出Web成功,路径为:D:\项目文件\项目根目录\unpackage\dist\build\web”后再执行下一步
|
||||||
h5Domain: 'https://xcx30.5g-quickapp.com/',
|
💡 **示例**:`项目 lucky_shop 导出Web成功,路径为:D:\0.项目源码\lucky_shop\unpackage\dist\build\web`
|
||||||
|
5. 按控制台提示的路径找到 `web` 目录,将该目录下所有文件手动打包成一个 `.zip` 压缩包
|
||||||
|
*仅打包文件,不包含外层 web 目录*
|
||||||
|
|
||||||
// // api请求地址
|
##### 4.2.1.2 【重命名】
|
||||||
// baseUrl: 'https://tsaas.liveplatform.cn/',
|
1. 按版本类型规范重命名压缩包:
|
||||||
|
- **通用版**:`hwappx-common-域名-时间.zip`
|
||||||
|
💡 **示例**:`hwappx-common-xcx.aigc-quickapp.com-2026-01-24.zip`
|
||||||
|
|
||||||
|
- **定制化版**:`客户名称-定制化---hwappx-客户编号-域名-时间.zip`
|
||||||
|
💡 **示例**:`POCT检测分析平台-定制化---hwappx-2811-xcx.aigc-quickapp.com-2026-01-24.zip`
|
||||||
|
|
||||||
// // 图片域名
|
🚫 **禁止**:压缩包命名禁止包含 `/ \ : * ? " < > |` 等特殊字符
|
||||||
// imgDomain: 'https://tsaas.liveplatform.cn/',
|
|
||||||
|
|
||||||
// // H5端域名
|
##### 4.2.1.3 【交付与最终发布】🔍
|
||||||
// h5Domain: 'https://tsaas.liveplatform.cn/',
|
|
||||||
|
|
||||||
// api请求地址
|
1. 将重命名后的压缩包发送给运维人员
|
||||||
// baseUrl: 'http://saas.cn/',
|
2. **运维人员操作流程**:
|
||||||
|
1. 解压压缩包
|
||||||
// // 图片域名
|
2. 打开快应用开发者工具,导入解压后的代码目录
|
||||||
// imgDomain: 'http://saas.cn/',
|
3. 验证代码无报错后,执行上传发布操作
|
||||||
|
##### 4.2.1.3 【测试流程】
|
||||||
// // H5端域名
|
H5:打开自己的浏览器输入网址(https://5g.aigc-quickapp.com/hwappx/common/?uniacid=75)改站点
|
||||||
// h5Domain: 'http://saas.cn/',
|
如果是test就把hwappx/common/改为hwappx/test/----------改站点
|
||||||
};
|
|
||||||
|
|
||||||
var config = {
|
|
||||||
/**
|
|
||||||
* 1.开发调试模式
|
|
||||||
* 去掉注释 ...devCfg;
|
|
||||||
* 注释掉 ...releaseCfg,
|
|
||||||
* 2.发行/发布模式,例如通过`HBuilder>发行>小程序微信`的时候,原理
|
|
||||||
* 然后将 `import site from "../site.js";`追加到 `unpackage\dist\build\mp-weixin\common\vendor.js` 文件内容开头部分
|
|
||||||
* 然后将 site.js 文件放到 `unpackage\dist\build\mp-weixin\` 目录下面
|
|
||||||
*/
|
|
||||||
...(releaseCfg ?? devCfg),
|
|
||||||
|
|
||||||
|
|
||||||
// 腾讯地图key
|
|
||||||
mpKey: 'TUHBZ-CNWKU-UHAVP-GZQ26-HNZFO-3YBF4',
|
|
||||||
|
|
||||||
//客服地址
|
|
||||||
webSocket: '{{$webSocket}}',
|
|
||||||
|
|
||||||
//本地端主动给服务器ping的时间, 0 则不开启 , 单位秒
|
|
||||||
pingInterval: 1500,
|
|
||||||
|
|
||||||
// 版本号
|
|
||||||
version: '1.0'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default config;
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### 快应用发布
|
|
||||||
1. 使用HBuilderX打开项目
|
|
||||||
2. 点击项目中【⚙】manifest.jion--->web配置--->运行的基础路径--->/hwappx/改编号/
|
|
||||||
"h5" : {
|
|
||||||
"sdkConfigs" : {
|
|
||||||
"maps" : {
|
|
||||||
"qqmap" : {
|
|
||||||
"key" : "TUHBZ-CNWKU-UHAVP-GZQ26-HNZFO-3YBF4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"router" : {
|
|
||||||
"mode" : "history",
|
|
||||||
"base" : "/hwappx/2811/"
|
|
||||||
},
|
|
||||||
|
|
||||||
(编号可以在.local.config.js中找到需要的编号)
|
---
|
||||||
|
|
||||||
|
## 5. 📝 构建脚本说明
|
||||||
|
|
||||||
|
### 5.1 可用的 npm 脚本命令
|
||||||
|
|
||||||
|
| 命令 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `npm run mp-weixin` | 默认构建(production模式,包含ZIP文件) |
|
||||||
|
| `npm run mp-weixin:patch` | 只打补丁(production模式,不创建ZIP文件) |
|
||||||
|
| `npm run mp-weixin:dev` | 开发模式构建(development模式,包含ZIP文件) |
|
||||||
|
| `npm run mp-weixin:dev:patch` | 只打补丁(development模式,不创建ZIP文件) |
|
||||||
|
|
||||||
|
### 5.2 构建脚本功能
|
||||||
|
|
||||||
|
- 复制 `project.config.json` 和 `project.private.config.json` 文件到构建目录
|
||||||
|
- 复制 `site.js` 文件到构建目录
|
||||||
|
- 在 `vendor.js` 文件开头追加 `import site from "../site.js";` 语句
|
||||||
|
- 支持创建构建结果的 ZIP 压缩包
|
||||||
|
- 自动打开 ZIP 文件所在目录
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 🔄 版本历史
|
||||||
|
|
||||||
|
### 6.1 v1.3
|
||||||
|
- 修复微信小程序构建脚本,支持复制 `project.config.json` 和 `project.private.config.json` 文件
|
||||||
|
- 增强构建脚本功能,添加命令行参数支持
|
||||||
|
- 在 `package.json` 中添加相关 npm 脚本命令
|
||||||
|
- 优化脚本执行逻辑,提高可靠性和灵活性
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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',
|
|
||||||
},
|
|
||||||
})['2811']; // 选择要使用的环境配置
|
|
||||||
3. 选择菜单栏 "发行" ->自定义发行--->H5-xcx.aigc-quickapp.com "快应用",网站标题为"快应用" 域名为xcx.aigc-quickapp.com 进行发布构建
|
|
||||||
4. 在电脑本地文件夹里找到unpackage--->dist--->build--->h5中h5-xcx.aigc-quickapp.com--->进行手动打包,例如:static.zip
|
|
||||||
(压缩包改id 公版--例如 hwappx-common-xcx.aigc-quickapp.com-2026-01-09.zip
|
|
||||||
定制化--例如 POCT检测分析平台-定制化--- hwappx-2811-xcx.aigc-quickapp.com-2026-01-09.zip)
|
|
||||||
5. 然后将压缩包发给开发定制客户技术人员,
|
|
||||||
6. 使用快应用开发者工具打开发布后的代码进行上传发布
|
|
||||||
@@ -134,8 +134,9 @@ async function main() {
|
|||||||
// 2) 创建 ZIP 文件(如果未指定 --no-zip)
|
// 2) 创建 ZIP 文件(如果未指定 --no-zip)
|
||||||
if (!options.noZip) {
|
if (!options.noZip) {
|
||||||
const cwd = path.join(__dirname, '..');
|
const cwd = path.join(__dirname, '..');
|
||||||
const sourceDir = path.join(cwd, 'unpackage', 'dist', 'build', 'mp-weixin');
|
const buildDir = options.mode === 'production' ? 'build' : 'dev';
|
||||||
const destDir = path.join(cwd, 'unpackage', 'dist', 'build');
|
const sourceDir = path.join(cwd, 'unpackage', 'dist', buildDir, 'mp-weixin');
|
||||||
|
const destDir = path.join(cwd, 'unpackage', 'dist', buildDir);
|
||||||
const zipFilePath = await createZipWithSystemCommand(sourceDir, destDir);
|
const zipFilePath = await createZipWithSystemCommand(sourceDir, destDir);
|
||||||
console.log(`ZIP 文件路径: ${zipFilePath}`);
|
console.log(`ZIP 文件路径: ${zipFilePath}`);
|
||||||
|
|
||||||
|
|||||||
2
site.js
2
site.js
@@ -1,4 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
baseUrl: "https://xcx6.aigc-quickapp.com/",//修改域名
|
baseUrl: "https://xcx6.aigc-quickapp.com/",//修改域名
|
||||||
uniacid: 2811,//后台对应uniacid
|
uniacid: 2847,//后台对应uniacid
|
||||||
};
|
};
|
||||||
@@ -65,6 +65,7 @@ const store = new Vuex.Store({
|
|||||||
bottomNavHidden: false, // 底部导航是否隐藏,true:隐藏,false:显示
|
bottomNavHidden: false, // 底部导航是否隐藏,true:隐藏,false:显示
|
||||||
aiUnreadCount: 10, // AI未读消息数量
|
aiUnreadCount: 10, // AI未读消息数量
|
||||||
globalAIKefuConfig: null, // AI客服配置
|
globalAIKefuConfig: null, // AI客服配置
|
||||||
|
customerServiceType: 'ai',
|
||||||
globalStoreConfig: null, // 门店配置
|
globalStoreConfig: null, // 门店配置
|
||||||
globalStoreInfo: null, // 门店信息
|
globalStoreInfo: null, // 门店信息
|
||||||
defaultStoreInfo: null, // 默认门店
|
defaultStoreInfo: null, // 默认门店
|
||||||
@@ -159,6 +160,9 @@ const store = new Vuex.Store({
|
|||||||
state.globalAIKefuConfig = value;
|
state.globalAIKefuConfig = value;
|
||||||
uni.setStorageSync('globalAIKefuConfig', value); // 初始化数据调用
|
uni.setStorageSync('globalAIKefuConfig', value); // 初始化数据调用
|
||||||
},
|
},
|
||||||
|
setCustomerServiceType(state, type) {
|
||||||
|
state.customerServiceType = type;
|
||||||
|
},
|
||||||
setGlobalStoreConfig(state, value) {
|
setGlobalStoreConfig(state, value) {
|
||||||
state.globalStoreConfig = value;
|
state.globalStoreConfig = value;
|
||||||
uni.setStorageSync('globalStoreConfig', value); // 初始化数据调用
|
uni.setStorageSync('globalStoreConfig', value); // 初始化数据调用
|
||||||
|
|||||||
Reference in New Issue
Block a user