Compare commits
15 Commits
merge/tmp-
...
test/test-
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e480d35df | |||
| bc6d243362 | |||
| a285706112 | |||
| 9c04c031ab | |||
| 0ce929f8a1 | |||
| 61ab9f11bd | |||
| 2747cb49ae | |||
| 9c8ebf8d74 | |||
| e19fef785f | |||
| 92ae114c5c | |||
| b25c366a5b | |||
| b23c21d05b | |||
| 65a24f25bb | |||
| 2a0935b581 | |||
| b31197a8b4 |
@@ -41,19 +41,13 @@ const localDevConfig = ({
|
|||||||
'local-2': { // 测试平台
|
'local-2': { // 测试平台
|
||||||
uniacid: 2,
|
uniacid: 2,
|
||||||
domain: 'http://localhost:8050/',
|
domain: 'http://localhost:8050/',
|
||||||
},
|
'47': { // 修改弹窗
|
||||||
'100': {
|
uniacid: 47,
|
||||||
uniacid: 100,
|
domain: 'https://5g.aigc-quickapp.com/',
|
||||||
domain: 'https://5g.aigc-quickapp.com/',
|
},
|
||||||
},
|
'2075': { //
|
||||||
'1': {
|
uniacid: 2075,
|
||||||
uniacid: 1,
|
domain: 'https://xcx.aigc-quickapp.com/',
|
||||||
domain: 'https://5g.aigc-quickapp.com/',
|
},
|
||||||
},
|
})['47']; // 选择要使用的环境配置
|
||||||
'115': {
|
|
||||||
uniacid: 115,
|
|
||||||
domain: 'https://5g.aigc-quickapp.com/',
|
|
||||||
},
|
|
||||||
})['1']; // 选择要使用的环境配置
|
|
||||||
|
|
||||||
export default localDevConfig;
|
export default localDevConfig;
|
||||||
@@ -5,17 +5,6 @@ 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);
|
||||||
@@ -27,28 +16,12 @@ 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: {
|
||||||
@@ -58,38 +31,28 @@ 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('[AI Service] 发送请求到:', params.url);
|
console.log('Sending blocking request to:', params.url);
|
||||||
console.log('[AI Service] 请求参数:', JSON.stringify(params.data, null, 2));
|
console.log('Request data:', params.data);
|
||||||
|
|
||||||
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('[AI Service] Dify API请求失败,详细错误:', error);
|
console.error('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服务暂时不可用,请稍后重试');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -100,14 +63,10 @@ export default {
|
|||||||
async sendStreamMessage(message, onChunk, onComplete) {
|
async sendStreamMessage(message, onChunk, onComplete) {
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const match = Config.baseUrl.match(/^(?:https?:\/\/|wss?:\/\/)([^\/\s:]+)/);
|
const socketTask = wx.connectSocket({
|
||||||
const domain = match ? match[1] : '';
|
url: 'wss://dev.aigc-quickapp.com/ws/aikefu',
|
||||||
const wssUrl = `wss://${domain}/ws/aikefu`;
|
header: {}
|
||||||
console.log(`wssUrl = ${wssUrl}`);
|
});
|
||||||
const socketTask = wx.connectSocket({
|
|
||||||
url: wssUrl,
|
|
||||||
header: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
let content = '';
|
let content = '';
|
||||||
let conversationId = '';
|
let conversationId = '';
|
||||||
@@ -118,7 +77,7 @@ export default {
|
|||||||
socketTask.send({
|
socketTask.send({
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
action: 'auth',
|
action: 'auth',
|
||||||
uniacid: this.getUniacid(),
|
uniacid: store.state.uniacid || '1',
|
||||||
token: store.state.token || 'test_token',
|
token: store.state.token || 'test_token',
|
||||||
user_id: store.state.memberInfo?.id || 'anonymous'
|
user_id: store.state.memberInfo?.id || 'anonymous'
|
||||||
})
|
})
|
||||||
@@ -136,11 +95,10 @@ export default {
|
|||||||
socketTask.send({
|
socketTask.send({
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
action: 'chat',
|
action: 'chat',
|
||||||
uniacid: this.getUniacid(),
|
uniacid: store.state.uniacid || '1',
|
||||||
query: message,
|
query: message,
|
||||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||||
conversation_id: this.getConversationId() || '',
|
conversation_id: this.getConversationId() || ''
|
||||||
...getDomainParams()
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
} else if (data.type === 'auth_failed') {
|
} else if (data.type === 'auth_failed') {
|
||||||
@@ -152,20 +110,20 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理流式消息块
|
// 处理流式消息块
|
||||||
else if (data.event === 'message') {
|
else if (data.type === 'message' || data.event === 'message') {
|
||||||
const text = data.answer || data.content || data.text || '';
|
const text = data.answer || data.content || data.text || '';
|
||||||
content += text;
|
content += text;
|
||||||
if (onChunk) onChunk(text);
|
if (onChunk) onChunk(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理流结束
|
// 处理流结束
|
||||||
else if (data.event === 'message_end') {
|
else if (data.event === 'message_end' || data.type === 'message_end') {
|
||||||
conversationId = data.conversation_id || '';
|
conversationId = data.conversation_id || '';
|
||||||
if (conversationId) {
|
if (conversationId) {
|
||||||
this.setConversationId(conversationId);
|
this.setConversationId(conversationId);
|
||||||
}
|
}
|
||||||
if (onComplete) {
|
if (onComplete) {
|
||||||
onComplete({ content, conversation_id: conversationId });
|
onComplete({ content, conversation_id: conversationId });
|
||||||
}
|
}
|
||||||
resolve({ content, conversation_id: conversationId });
|
resolve({ content, conversation_id: conversationId });
|
||||||
socketTask.close();
|
socketTask.close();
|
||||||
@@ -217,14 +175,12 @@ export default {
|
|||||||
'Accept': 'text/event-stream',
|
'Accept': 'text/event-stream',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
uniacid: this.getUniacid(),
|
uniacid: store.state.uniacid || '1',
|
||||||
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()
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -358,19 +314,17 @@ export default {
|
|||||||
* 生成新会话(如需)
|
* 生成新会话(如需)
|
||||||
*/
|
*/
|
||||||
async generateConversationId() {
|
async generateConversationId() {
|
||||||
const params = {
|
const params = {
|
||||||
url: '/api/kefu/createConversation',
|
url: '/api/kefu/createConversation',
|
||||||
data: {
|
data: {
|
||||||
uniacid: this.getUniacid(),
|
uniacid: store.state.uniacid,
|
||||||
token: store.state.token || 'test_token',
|
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
member_id: store.state.memberInfo?.id || '',
|
||||||
member_id: store.state.memberInfo?.id || '',
|
},
|
||||||
...getDomainParams()
|
header: {
|
||||||
},
|
'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
|
||||||
@@ -388,7 +342,6 @@ 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 {
|
||||||
@@ -410,10 +363,7 @@ 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: {
|
data: { conversation_id: conversationId },
|
||||||
conversation_id: conversationId,
|
|
||||||
...getDomainParams()
|
|
||||||
},
|
|
||||||
async: false
|
async: false
|
||||||
});
|
});
|
||||||
return response.success;
|
return response.success;
|
||||||
@@ -432,14 +382,13 @@ export default {
|
|||||||
throw new Error('会话ID(conversation_id)是必填参数');
|
throw new Error('会话ID(conversation_id)是必填参数');
|
||||||
}
|
}
|
||||||
const requestData = {
|
const requestData = {
|
||||||
uniacid: params.uniacid || this.getUniacid(),
|
uniacid: params.uniacid || store.state.uniacid || '1',
|
||||||
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',
|
||||||
@@ -478,15 +427,13 @@ export default {
|
|||||||
if (window.currentEventSource) {
|
if (window.currentEventSource) {
|
||||||
window.currentEventSource.close();
|
window.currentEventSource.close();
|
||||||
}
|
}
|
||||||
const paramsObj = {
|
const params = new URLSearchParams({
|
||||||
uniacid: this.getUniacid(),
|
uniacid: store.state.uniacid || '1',
|
||||||
user_id: store.state.memberInfo?.id,
|
user_id: store.state.memberInfo?.id || '123456',
|
||||||
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,8 +2,6 @@
|
|||||||
* 客服统一处理服务
|
* 客服统一处理服务
|
||||||
* 整合各种客服方式,提供统一的调用接口
|
* 整合各种客服方式,提供统一的调用接口
|
||||||
*/
|
*/
|
||||||
import IMAGE_CONFIG from './image-config.js';
|
|
||||||
|
|
||||||
export class CustomerService {
|
export class CustomerService {
|
||||||
constructor(vueInstance, externalConfig = null) {
|
constructor(vueInstance, externalConfig = null) {
|
||||||
this.vm = vueInstance;
|
this.vm = vueInstance;
|
||||||
@@ -473,11 +471,13 @@ export class CustomerService {
|
|||||||
const shopInfo = this.vm.shopInfo || {};
|
const shopInfo = this.vm.shopInfo || {};
|
||||||
const config = this.getPlatformConfig();
|
const config = this.getPlatformConfig();
|
||||||
|
|
||||||
// 优先使用指定的智能客服头像
|
if (config?.type === 'aikefu') {
|
||||||
if (config?.type === 'aikefu' || config?.type === 'wxwork' || config?.type === 'qyweixin') {
|
return shopInfo.aiAgentimg || '';
|
||||||
return this.vm.$util.img(IMAGE_CONFIG.aiAvatar);
|
} else if (config?.type === 'wxwork' || config?.type === 'qyweixin') {
|
||||||
|
return shopInfo.aiAgentimg || '';
|
||||||
|
} else if (config?.type === 'third') {
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return shopInfo.kefuimg || this.vm.$util?.getDefaultImage()?.kefu || '';
|
return shopInfo.kefuimg || this.vm.$util?.getDefaultImage()?.kefu || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* 图片配置文件
|
|
||||||
* 将大图片上传到服务器后,请在此处配置网络URL
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 替换为你上传后的实际图片URL
|
|
||||||
const IMAGE_CONFIG = {
|
|
||||||
// AI客服头像
|
|
||||||
aiAvatar: 'public/static/img/s-agent.jpg',
|
|
||||||
|
|
||||||
// 用户默认头像
|
|
||||||
userAvatar: 'public/static/img/s-user.jpg'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default IMAGE_CONFIG;
|
|
||||||
@@ -30,12 +30,12 @@ function processRoutePath(route) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ---- 处理页面目录映射 <end>----
|
// ---- 处理页面目录映射 <end>----
|
||||||
|
|
||||||
// 去掉pages目录,只保留子目录
|
// 去掉pages目录,只保留子目录
|
||||||
if (routeParts[0] === 'pages') {
|
if (routeParts[0] === 'pages') {
|
||||||
routeParts = routeParts.slice(1);
|
routeParts = routeParts.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return routeParts.join("/");
|
return routeParts.join("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,11 +54,14 @@ function loadLangPackSync(lang, path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当前本地语言
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
function getCurrentLocale() {
|
function getCurrentLocale() {
|
||||||
return uni.getStorageSync('lang') || "zh-cn";
|
return uni.getStorageSync('lang') || "zh-cn";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
langList: langConfig.langList,
|
langList: langConfig.langList,
|
||||||
|
|
||||||
@@ -77,18 +80,18 @@ export default {
|
|||||||
if (!_page) return;
|
if (!_page) return;
|
||||||
|
|
||||||
const locale = getCurrentLocale(); // 获得当前本地语言
|
const locale = getCurrentLocale(); // 获得当前本地语言
|
||||||
|
|
||||||
let value = ''; // 存放解析后的语言值
|
let value = ''; // 存放解析后的语言值
|
||||||
let langPath = ''; // 存放当前页面语言包路径
|
let langPath = ''; // 存放当前页面语言包路径
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//公共语言包(同步加载)
|
//公共语言包(同步加载)
|
||||||
var lang = loadLangPackSync(locale, 'common');
|
var lang = loadLangPackSync(locale, 'common');
|
||||||
|
|
||||||
//当前页面语言包(同步加载)
|
//当前页面语言包(同步加载)
|
||||||
let route = _page.route;
|
let route = _page.route;
|
||||||
langPath = processRoutePath(route);
|
langPath = processRoutePath(route);
|
||||||
|
|
||||||
// 加载当前页面语言包
|
// 加载当前页面语言包
|
||||||
let currentPageLang = loadLangPackSync(locale, langPath);
|
let currentPageLang = loadLangPackSync(locale, langPath);
|
||||||
|
|
||||||
@@ -113,7 +116,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
value = mergedLang[field] !== undefined ? mergedLang[field] : field;
|
value = mergedLang[field] !== undefined ? mergedLang[field] : field;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('解析语言包失败:', e, { langPath, field, locale });
|
console.error('解析语言包失败:', e, { langPath, field, locale });
|
||||||
value = field;
|
value = field;
|
||||||
@@ -129,7 +132,7 @@ export default {
|
|||||||
|
|
||||||
// 多语言调试,注释后可以关闭控制台输出
|
// 多语言调试,注释后可以关闭控制台输出
|
||||||
if (field == value) {
|
if (field == value) {
|
||||||
console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
|
console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -165,7 +168,7 @@ export default {
|
|||||||
if (!_page) return;
|
if (!_page) return;
|
||||||
|
|
||||||
const locale = getCurrentLocale();
|
const locale = getCurrentLocale();
|
||||||
|
|
||||||
this.title(this.lang("title"));
|
this.title(this.lang("title"));
|
||||||
|
|
||||||
//设置tabbar的文字语言
|
//设置tabbar的文字语言
|
||||||
@@ -215,4 +218,4 @@ export default {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,10 +82,10 @@
|
|||||||
<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" @tap.stop="toDetail(item)">
|
<view class="goods-img" @tap.stop="toDetail(item)">
|
||||||
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" :show-menu-by-longpress="true" />
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" />
|
||||||
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}
|
<view 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" @tap.stop="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>
|
||||||
@@ -99,6 +99,9 @@
|
|||||||
<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)">
|
||||||
@@ -117,12 +120,6 @@
|
|||||||
<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" @tap.stop="toDetail(item)">立即购买</view>
|
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||||
@@ -177,24 +174,28 @@
|
|||||||
: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" @tap.stop="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" :show-menu-by-longpress="true" />
|
:lazy-load="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" @tap.stop="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>
|
||||||
</view>
|
<block v-else>
|
||||||
|
<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" />
|
||||||
@@ -211,12 +212,6 @@
|
|||||||
<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" @tap.stop="toDetail(item)">立即购买</view>
|
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||||
@@ -723,15 +718,6 @@ 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));
|
||||||
@@ -1398,25 +1384,4 @@ 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>
|
||||||
@@ -8,8 +8,7 @@
|
|||||||
<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>
|
||||||
@@ -118,7 +117,7 @@
|
|||||||
<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" :show-menu-by-longpress="true" />
|
:lazy-load="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>
|
||||||
@@ -185,7 +184,7 @@
|
|||||||
<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" :show-menu-by-longpress="true" />
|
@error="imgError(dataIndex)" :lazy-load="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>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<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" :show-menu-by-longpress="true" />
|
@error="imgError(index, dataIndex)" :lazy-load="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>
|
||||||
|
|||||||
@@ -913,7 +913,7 @@ export default {
|
|||||||
// ===== 主容器样式 =====
|
// ===== 主容器样式 =====
|
||||||
.tab-diy-component-preview-container {
|
.tab-diy-component-preview-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 0px;
|
min-height: 300px;
|
||||||
display: flex;
|
display: flex;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid #e0e0e0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|||||||
@@ -53,19 +53,9 @@
|
|||||||
|
|
||||||
<!-- 视频播放弹窗 -->
|
<!-- 视频播放弹窗 -->
|
||||||
<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="popupVideoStyle">
|
<view class="video-container" style="position:fixed;top:30%;width:100%;left:0;">
|
||||||
<video
|
<video class="adaptive-video" :autoPauseIfNavigate="true" :autoPauseIfOpenNative="true"
|
||||||
ref="popupVideoRef"
|
:autoplay="false" :enableAutoRotation="true" id="myVideo" :src="video_url" :controls="true"></video>
|
||||||
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>
|
||||||
@@ -136,38 +126,12 @@ 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();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -175,39 +139,6 @@ 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,36 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="video-container" :style="containerStyle">
|
<video data-component-name="diy-video" class="diy-video" :src="$util.img(value.videoUrl)"
|
||||||
<!-- H5端使用原生video标签 -->
|
:poster="$util.img(value.imageUrl)" :style="videoWarpCss" objectFit="cover"
|
||||||
<!-- #ifdef H5 -->
|
@tap="handlerClick(value.videoUrl)"></video>
|
||||||
<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>
|
||||||
@@ -44,160 +15,27 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {};
|
||||||
videoRatio: null, // 视频比例:'landscape'(横屏)或 'portrait'(竖屏)
|
|
||||||
videoUrl: '',
|
|
||||||
posterUrl: ''
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.initVideoData();
|
|
||||||
},
|
},
|
||||||
|
created() { },
|
||||||
mixins: [DiyMinx],
|
mixins: [DiyMinx],
|
||||||
watch: {
|
watch: {
|
||||||
value: {
|
// 组件刷新监听
|
||||||
immediate: true,
|
componentRefresh: function (nval) { }
|
||||||
handler(newVal) {
|
|
||||||
if (newVal) {
|
|
||||||
this.initVideoData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
videoWarpCss: function () {
|
videoWarpCss: function () {
|
||||||
var obj = '';
|
var obj = '';
|
||||||
if (this.value && this.value.componentAngle == 'round') {
|
if (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) => {
|
||||||
@@ -210,32 +48,11 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.video-container {
|
video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: #000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 基础样式 */
|
.diy-video>>>.uni-video-container {
|
||||||
.diy-video {
|
background-color: transparent;
|
||||||
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>
|
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
v-if="fixBtnShow && hasValidKefuConfig && isWeappOfficialKefu"
|
v-if="fixBtnShow && hasValidKefuConfig && isWeappOfficialKefu"
|
||||||
class="btn-item common-bg"
|
class="btn-item common-bg"
|
||||||
open-type="contact"
|
open-type="contact"
|
||||||
|
:style="{ backgroundImage: currentKefuImg ? `url(${currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||||||
>
|
>
|
||||||
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
||||||
</button>
|
</button>
|
||||||
@@ -27,13 +28,8 @@
|
|||||||
v-if="fixBtnShow && hasValidKefuConfig && !isWeappOfficialKefu && !showWeappSystemKefu"
|
v-if="fixBtnShow && hasValidKefuConfig && !isWeappOfficialKefu && !showWeappSystemKefu"
|
||||||
class="btn-item common-bg"
|
class="btn-item common-bg"
|
||||||
@click="handleUnifiedKefuClick"
|
@click="handleUnifiedKefuClick"
|
||||||
|
:style="{ backgroundImage: currentKefuImg ? `url(${currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||||||
>
|
>
|
||||||
<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="isAIKefu && !currentKefuImg">🤖</text>
|
||||||
<text class="ai-icon" v-if="isWxworkKefu && !currentKefuImg">💬</text>
|
<text class="ai-icon" v-if="isWxworkKefu && !currentKefuImg">💬</text>
|
||||||
<text class="ai-icon" v-if="!isAIKefu && !isWxworkKefu && !currentKefuImg">👤</text>
|
<text class="ai-icon" v-if="!isAIKefu && !isWxworkKefu && !currentKefuImg">👤</text>
|
||||||
@@ -44,13 +40,8 @@
|
|||||||
v-if="fixBtnShow && hasValidKefuConfig && !isWeappOfficialKefu && showWeappSystemKefu"
|
v-if="fixBtnShow && hasValidKefuConfig && !isWeappOfficialKefu && showWeappSystemKefu"
|
||||||
class="btn-item common-bg"
|
class="btn-item common-bg"
|
||||||
@click="handleUnifiedKefuClick"
|
@click="handleUnifiedKefuClick"
|
||||||
|
:style="{ backgroundImage: currentKefuImg ? `url(${currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||||||
>
|
>
|
||||||
<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="isAIKefu && !currentKefuImg">🤖</text>
|
||||||
<text class="ai-icon" v-if="isWxworkKefu && !currentKefuImg">💬</text>
|
<text class="ai-icon" v-if="isWxworkKefu && !currentKefuImg">💬</text>
|
||||||
<text class="ai-icon" v-if="!isAIKefu && !isWxworkKefu && !currentKefuImg">👤</text>
|
<text class="ai-icon" v-if="!isAIKefu && !isWxworkKefu && !currentKefuImg">👤</text>
|
||||||
@@ -61,6 +52,7 @@
|
|||||||
v-if="fixBtnShow && hasValidKefuConfig && showWeappSystemKefu"
|
v-if="fixBtnShow && hasValidKefuConfig && showWeappSystemKefu"
|
||||||
class="btn-item common-bg"
|
class="btn-item common-bg"
|
||||||
open-type="contact"
|
open-type="contact"
|
||||||
|
:style="{ backgroundImage: currentKefuImg ? `url(${currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||||||
>
|
>
|
||||||
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
||||||
</button>
|
</button>
|
||||||
@@ -312,13 +304,6 @@ 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;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -53,15 +53,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// 检查配置,决定是否显示隐私协议
|
this.listenPrivacySettingChange()
|
||||||
const shopInfo = uni.getStorageSync('shopInfo');
|
this.curPageShow()
|
||||||
if (shopInfo?.ischina == 1 && shopInfo?.index_login_auth == 1) {
|
|
||||||
this.listenPrivacySettingChange()
|
|
||||||
this.curPageShow()
|
|
||||||
} else {
|
|
||||||
// 如果不需要显示隐私协议,直接触发同意事件
|
|
||||||
this.$emit('agree');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
try {
|
try {
|
||||||
@@ -159,14 +152,6 @@ 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({
|
||||||
|
|||||||
@@ -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,14 +71,11 @@
|
|||||||
"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" ],
|
||||||
@@ -107,7 +104,7 @@
|
|||||||
},
|
},
|
||||||
"router" : {
|
"router" : {
|
||||||
"mode" : "history",
|
"mode" : "history",
|
||||||
"base" : "/hwappx/test/"
|
"base" : "/hwappx/common/"
|
||||||
},
|
},
|
||||||
"title" : "",
|
"title" : "",
|
||||||
"devServer" : {
|
"devServer" : {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
{
|
{
|
||||||
"path": "detail",
|
"path": "detail",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "商品详情"
|
"navigationBarTitleText": "资源详情"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,10 +17,6 @@
|
|||||||
}}</view>
|
}}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- <view class="page-header" v-if="diyData.global && diyData.global.navBarSwitch" :style="{ backgroundImage: bgImg }">
|
|
||||||
<ns-navbar :title-color="textNavColor" :data="diyData.global" :scrollTop="scrollTop" :isBack="false"/>
|
|
||||||
</view> -->
|
|
||||||
|
|
||||||
<diy-index-page v-if="topIndexValue" ref="indexPage" :value="topIndexValue" :bgUrl="bgUrl"
|
<diy-index-page v-if="topIndexValue" ref="indexPage" :value="topIndexValue" :bgUrl="bgUrl"
|
||||||
:scrollTop="scrollTop" :diyGlobal="diyData.global" class="diy-index-page">
|
:scrollTop="scrollTop" :diyGlobal="diyData.global" class="diy-index-page">
|
||||||
<template v-slot:components>
|
<template v-slot:components>
|
||||||
@@ -43,35 +39,17 @@
|
|||||||
<view @touchmove.prevent.stop>
|
<view @touchmove.prevent.stop>
|
||||||
<uni-popup ref="uniPopupWindow" type="center" class="wap-floating" :maskClick="false">
|
<uni-popup ref="uniPopupWindow" type="center" class="wap-floating" :maskClick="false">
|
||||||
<view class="small-bot">
|
<view class="small-bot">
|
||||||
<!-- <view class="adver-time" wx:if="{{startadv.params.style=='default'&&startadv.params.canclose==1}}">
|
|
||||||
<view bindtap="adverclose">跳过</view>
|
|
||||||
<view class="time">{{clock}}s</view>
|
|
||||||
</view>
|
|
||||||
<view class="adver-time" wx:if="{{startadv.params.style=='default'&&startadv.params.canclose==0}}">
|
|
||||||
<view class="time" style="line-height: 64rpx;">{{clock}}s</view>
|
|
||||||
</view> -->
|
|
||||||
<swiper autoplay="true" :circular="true" indicator-active-color="#fff"
|
<swiper autoplay="true" :circular="true" indicator-active-color="#fff"
|
||||||
indicator-color="rgba(255,255,255,0.6)" :indicator-dots="true" interval="3000">
|
indicator-color="rgba(255,255,255,0.6)" :indicator-dots="true" interval="3000">
|
||||||
<swiper-item v-for="(item, index) in adv.list" :key="index">
|
<swiper-item v-for="(item, index) in adv.list" :key="index">
|
||||||
<image class="slide-image" @click="$util.diyRedirectTo(item.link)" height="100%"
|
<image class="slide-image" @click="$util.diyRedirectTo(item.link)" height="100%"
|
||||||
:src="$util.img(item.imageUrl)" width="100%"></image>
|
:src="$util.img(item.imageUrl)" width="100%"></image>
|
||||||
<!-- <image bindtap="adverclose" class="slide-image" height="100%" src="{{item.imgurl}}" width="100%" wx:if="{{item.click==1}}"></image> -->
|
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
<view bindtap="adverclose" class="small-bot-close" @click="closePopupWindow">
|
<view bindtap="adverclose" class="small-bot-close" @click="closePopupWindow">
|
||||||
<i class="iconfont icon-round-close" style="color:#fff"></i>
|
<i class="iconfont icon-round-close" style="color:#fff"></i>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- <view class="image-wrap">
|
|
||||||
<swiper class="swiper" style="width:100%;height: 1200rpx;" :autoplay="true" interval="3000" circular="true" :indicator-dots="true" indicator-color="#000" indicator-active-color="red">
|
|
||||||
<swiper-item class="swiper-item" v-for="(item, index) in adv.list" :key="index" v-if="item.imageUrl" @click="$util.diyRedirectTo(item.link)">
|
|
||||||
<view class="item">
|
|
||||||
<image :src="$util.img(item.imageUrl)" mode="aspectFit" :show-menu-by-longpress="true"/>
|
|
||||||
</view>
|
|
||||||
</swiper-item>
|
|
||||||
</swiper>
|
|
||||||
</view>
|
|
||||||
<text class="iconfont icon-round-close" @click="closePopupWindow"></text> -->
|
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -101,7 +79,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
|
|
||||||
<!-- 选择门店弹出框,定位当前位置,展示最近的一个门店 -->
|
<!-- 选择门店弹出框 -->
|
||||||
<view @touchmove.prevent.stop class="choose-store">
|
<view @touchmove.prevent.stop class="choose-store">
|
||||||
<uni-popup ref="chooseStorePopup" type="center" :maskClick="false" class="choose-store">
|
<uni-popup ref="chooseStorePopup" type="center" :maskClick="false" class="choose-store">
|
||||||
<view class="choose-store-popup">
|
<view class="choose-store-popup">
|
||||||
@@ -136,8 +114,27 @@
|
|||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<hover-nav :need="true"></hover-nav>
|
<hover-nav :need="true"></hover-nav>
|
||||||
<!-- 隐私协议 -->
|
|
||||||
|
<!-- 隐私协议弹窗 UI (新增) -->
|
||||||
|
<view v-if="showPrivacyModal" class="privacy-modal-mask" @touchmove.prevent>
|
||||||
|
<view class="privacy-modal-container">
|
||||||
|
<view class="modal-header">用户隐私保护提示</view>
|
||||||
|
<view class="modal-body">
|
||||||
|
<text>感谢您使用本应用,在使用前您应当阅读并同意</text>
|
||||||
|
<text class="link" @click="viewPrivacy('privacy')">《隐私条款》</text>
|
||||||
|
<text class="link" @click="viewPrivacy('agreement')">《用户服务协议》</text>
|
||||||
|
<text>,当点击同意并继续时,即表示您已理解并同意该条款内容,该条款将对您产生法律约束力;如您不同意,将无法继续使用相关功能。</text>
|
||||||
|
</view>
|
||||||
|
<view class="modal-footer">
|
||||||
|
<view class="btn btn-disagree" @click="handleDisagree">不同意</view>
|
||||||
|
<view class="btn btn-agree" @click="handleAgree">同意并继续</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 隐私协议组件 (原有) -->
|
||||||
<privacy-popup ref="privacyPopup"></privacy-popup>
|
<privacy-popup ref="privacyPopup"></privacy-popup>
|
||||||
<to-top v-if="showTop" @toTop="scrollToTopNative()"></to-top>
|
<to-top v-if="showTop" @toTop="scrollToTopNative()"></to-top>
|
||||||
<ns-login ref="login"></ns-login>
|
<ns-login ref="login"></ns-login>
|
||||||
@@ -146,14 +143,132 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
||||||
import diyJs from '@/common/js/diy.js';
|
import diyJs from '@/common/js/diy.js';
|
||||||
import scroll from '@/common/js/scroll-view.js';
|
import scroll from '@/common/js/scroll-view.js';
|
||||||
import indexJs from './public/js/index.js';
|
import indexJs from './public/js/index.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [diyJs, scroll, indexJs]
|
mixins: [diyJs, scroll, indexJs],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
minScrollTop: 100,
|
||||||
|
wechatQrcode: '',
|
||||||
|
diyRoute: '/pages/index/index',
|
||||||
|
showPrivacyModal: false // 新增:控制隐私弹窗显示
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad(option) {
|
||||||
|
// #ifdef H5
|
||||||
|
if (option.module && option.module == 'locationPicker') {
|
||||||
|
option.name = '';
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.name = option.name || 'DIY_VIEW_INDEX';
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
this.getFollowQrcode();
|
||||||
|
// 页面显示时检查隐私设置
|
||||||
|
this.checkPrivacySetting();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.unsubscribe = this.$eventBus?.onMany([
|
||||||
|
'rubik-cube-tap',
|
||||||
|
'picture-tap',
|
||||||
|
'text-tap',
|
||||||
|
'goods-list-tap',
|
||||||
|
'presale-tap',
|
||||||
|
'notes-tap',
|
||||||
|
'merch-list-tap',
|
||||||
|
'map-tap',
|
||||||
|
'img-ads-tap',
|
||||||
|
'many-goods-list-tap',
|
||||||
|
'search-tap',
|
||||||
|
], this._handleDiyGroupInteractionEvent);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.unsubscribe) this.unsubscribe();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 检查隐私弹窗逻辑
|
||||||
|
checkPrivacySetting() {
|
||||||
|
// 模拟检查本地存储,看用户是否已经同意过
|
||||||
|
// 实际项目中请替换为你真实的存储逻辑
|
||||||
|
const hasAgreed = uni.getStorageSync('HAS_AGREED_PRIVACY');
|
||||||
|
if (!hasAgreed) {
|
||||||
|
// 延迟显示,防止遮挡页面渲染
|
||||||
|
setTimeout(() => {
|
||||||
|
this.showPrivacyModal = true;
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 用户点击同意
|
||||||
|
handleAgree() {
|
||||||
|
// 保存同意状态
|
||||||
|
uni.setStorageSync('HAS_AGREED_PRIVACY', true);
|
||||||
|
this.showPrivacyModal = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 用户点击不同意
|
||||||
|
handleDisagree() {
|
||||||
|
// 微信小程序环境下,不同意通常退出小程序
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.exitMiniProgram();
|
||||||
|
// #endif
|
||||||
|
// H5 或 App 下可以提示或直接不显示内容
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
uni.showToast({
|
||||||
|
title: '您已拒绝协议,无法使用',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
// 这里可以选择关闭页面或保持弹窗
|
||||||
|
// this.showPrivacyModal = false;
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查看具体条款(可选功能)
|
||||||
|
viewPrivacy(type) {
|
||||||
|
// 这里可以跳转到具体的条款页面,或者使用你现有的 privacy-popup 组件
|
||||||
|
// 假设你有现成的组件逻辑:
|
||||||
|
if (this.$refs.privacyPopup) {
|
||||||
|
// 假设 privacy-popup 组件有一个 show 方法
|
||||||
|
// this.$refs.privacyPopup.show(type);
|
||||||
|
}
|
||||||
|
uni.showToast({
|
||||||
|
title: '请在此处实现查看条款逻辑',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getFollowQrcode() {
|
||||||
|
if (!this.$util.isWeiXin()) return;
|
||||||
|
this.$api.sendRequest({
|
||||||
|
url: '/wechat/api/wechat/followqrcode',
|
||||||
|
success: res => {
|
||||||
|
if (res.code >= 0 && res.data) {
|
||||||
|
this.wechatQrcode = res.data.qrcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
officialAccountsOpen() {
|
||||||
|
this.$refs.officialAccountsPopup.open();
|
||||||
|
},
|
||||||
|
officialAccountsClose() {
|
||||||
|
this.$refs.officialAccountsPopup.close();
|
||||||
|
},
|
||||||
|
_handleDiyGroupInteractionEvent(payload) {
|
||||||
|
// #ifdef H5
|
||||||
|
return true;
|
||||||
|
// #endif
|
||||||
|
if (this.storeToken) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.$refs.login?.open();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -199,6 +314,74 @@ export default {
|
|||||||
.small-bot-close i {
|
.small-bot-close i {
|
||||||
font-size: 60rpx;
|
font-size: 60rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 新增:隐私弹窗样式 */
|
||||||
|
.privacy-modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6); // 半透明背景
|
||||||
|
z-index: 9999; // 确保层级最高
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.privacy-modal-container {
|
||||||
|
width: 80%;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
padding: 40rpx 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
color: #007aff; // 蓝色链接
|
||||||
|
margin: 0 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 15rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-disagree {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-agree {
|
||||||
|
background-color: #07c160; // 微信绿
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.swiper ::v-deep .uni-swiper-dots-horizontal {
|
.swiper ::v-deep .uni-swiper-dots-horizontal {
|
||||||
|
|||||||
@@ -1,98 +1,95 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
minScrollTop: 100, // 设置回到顶端按钮显示要求,最小页面滚动距离
|
minScrollTop: 100, // 设置回到顶端按钮显示要求,最小页面滚动距离
|
||||||
wechatQrcode: '', // 公众号二维码
|
wechatQrcode: "", // 公众号二维码
|
||||||
diyRoute: '/pages/index/index',
|
diyRoute: "/pages/index/index",
|
||||||
shopInfo: null // 店铺信息
|
};
|
||||||
};
|
},
|
||||||
},
|
onLoad(option) {
|
||||||
onLoad(option) {
|
// #ifdef H5
|
||||||
// #ifdef H5
|
// H5地图选择位置回调数据
|
||||||
// H5地图选择位置回调数据
|
if (option.module && option.module == "locationPicker") {
|
||||||
if (option.module && option.module == 'locationPicker') {
|
option.name = ""; // 清空地址
|
||||||
option.name = ''; // 清空地址
|
}
|
||||||
}
|
// #endif
|
||||||
// #endif
|
this.name = option.name || "DIY_VIEW_INDEX"; // 根据店铺运营模式,打开平台(shop)或者连锁门店(stroe)页面,接口会自行判断
|
||||||
this.name = option.name || 'DIY_VIEW_INDEX'; // 根据店铺运营模式,打开平台(shop)或者连锁门店(stroe)页面,接口会自行判断
|
},
|
||||||
|
onShow() {
|
||||||
|
// 获取关注公众号二维码
|
||||||
|
this.getFollowQrcode();
|
||||||
|
// 检查隐私设置并显示弹窗
|
||||||
|
this.checkPrivacySetting();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 监听图片、文字、商品列表等组件的点击事件
|
||||||
|
this.unsubscribe = this.$eventBus?.onMany(
|
||||||
|
[
|
||||||
|
"rubik-cube-tap",
|
||||||
|
"picture-tap",
|
||||||
|
"text-tap",
|
||||||
|
"goods-list-tap",
|
||||||
|
"presale-tap",
|
||||||
|
"notes-tap",
|
||||||
|
"merch-list-tap",
|
||||||
|
"map-tap",
|
||||||
|
"img-ads-tap",
|
||||||
|
"many-goods-list-tap",
|
||||||
|
"search-tap",
|
||||||
|
],
|
||||||
|
this._handleDiyGroupInteractionEvent,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
// 移除图片点击事件监听
|
||||||
|
if (this.unsubscribe) this.unsubscribe();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 检查隐私设置
|
||||||
|
checkPrivacySetting() {
|
||||||
|
// 延迟执行,确保组件已经挂载
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.$refs.privacyPopup) {
|
||||||
|
this.$refs.privacyPopup.proactive();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
},
|
||||||
|
// 关注公众号
|
||||||
|
getFollowQrcode() {
|
||||||
|
if (!this.$util.isWeiXin()) return;
|
||||||
|
this.$api.sendRequest({
|
||||||
|
url: "/wechat/api/wechat/followqrcode",
|
||||||
|
success: (res) => {
|
||||||
|
if (res.code >= 0 && res.data) {
|
||||||
|
this.wechatQrcode = res.data.qrcode;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
officialAccountsOpen() {
|
||||||
|
this.$refs.officialAccountsPopup.open();
|
||||||
|
},
|
||||||
|
officialAccountsClose() {
|
||||||
|
this.$refs.officialAccountsPopup.close();
|
||||||
|
},
|
||||||
|
// 统一处理点击及触摸事件
|
||||||
|
_handleDiyGroupInteractionEvent(payload) {
|
||||||
|
// #ifdef H5
|
||||||
|
// 如果是 H5 环境,直接返回 true 继续传播
|
||||||
|
return true;
|
||||||
|
// #endif
|
||||||
|
|
||||||
// 获取店铺信息
|
// 如果已登录,直接返回 true 继续传播
|
||||||
this.shopInfo = uni.getStorageSync('shopInfo');
|
if (this.storeToken) {
|
||||||
},
|
return true;
|
||||||
onShow() {
|
}
|
||||||
// 获取关注公众号二维码
|
|
||||||
this.getFollowQrcode();
|
|
||||||
|
|
||||||
// 重新获取店铺信息
|
|
||||||
this.shopInfo = uni.getStorageSync('shopInfo');
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
// 监听图片、文字、商品列表等组件的点击事件
|
|
||||||
this.unsubscribe = this.$eventBus?.onMany([
|
|
||||||
'rubik-cube-tap',
|
|
||||||
'picture-tap',
|
|
||||||
'text-tap',
|
|
||||||
'goods-list-tap',
|
|
||||||
'presale-tap',
|
|
||||||
'notes-tap',
|
|
||||||
'merch-list-tap',
|
|
||||||
'map-tap',
|
|
||||||
'img-ads-tap',
|
|
||||||
'many-goods-list-tap',
|
|
||||||
'search-tap',
|
|
||||||
], this._handleDiyGroupInteractionEvent);
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
// 移除图片点击事件监听
|
|
||||||
if (this.unsubscribe) this.unsubscribe();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 关注公众号
|
|
||||||
getFollowQrcode() {
|
|
||||||
if (!this.$util.isWeiXin()) return;
|
|
||||||
this.$api.sendRequest({
|
|
||||||
url: '/wechat/api/wechat/followqrcode',
|
|
||||||
success: res => {
|
|
||||||
if (res.code >= 0 && res.data) {
|
|
||||||
this.wechatQrcode = res.data.qrcode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
officialAccountsOpen() {
|
|
||||||
this.$refs.officialAccountsPopup.open();
|
|
||||||
},
|
|
||||||
officialAccountsClose() {
|
|
||||||
this.$refs.officialAccountsPopup.close();
|
|
||||||
},
|
|
||||||
// 判断是否需要登录授权
|
|
||||||
_needLoginAuth() {
|
|
||||||
// 检查 index_login_auth 都开启时才需要登录授权
|
|
||||||
return this.shopInfo?.index_login_auth == 1;
|
|
||||||
},
|
|
||||||
// 统一处理点击及触摸事件
|
|
||||||
_handleDiyGroupInteractionEvent(payload) {
|
|
||||||
// #ifdef H5
|
|
||||||
// 如果是 H5 环境,直接返回 true 继续传播
|
|
||||||
return true;
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// 如果不需要登录授权,直接返回 true 继续传播
|
// 打开登录弹窗
|
||||||
if (!this._needLoginAuth()) {
|
// console.log('==> _handleDiyGroupInteractionEvent, 未登录,打开登录弹窗', { payload })
|
||||||
return true;
|
this.$refs.login?.open();
|
||||||
}
|
|
||||||
|
|
||||||
// 如果已登录,直接返回 true 继续传播
|
// 阻止事件继续传播
|
||||||
if (this.storeToken) {
|
return false;
|
||||||
return true;
|
},
|
||||||
}
|
},
|
||||||
|
};
|
||||||
// 打开登录弹窗
|
|
||||||
// console.log('==> _handleDiyGroupInteractionEvent, 未登录,打开登录弹窗', { payload })
|
|
||||||
this.$refs.login?.open();
|
|
||||||
|
|
||||||
// 阻止事件继续传播
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
<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"
|
||||||
@@ -22,7 +17,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" :show-menu-by-longpress="true" />
|
mode="aspectFit" />
|
||||||
</view>
|
</view>
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
@@ -463,8 +458,6 @@
|
|||||||
// 商品详情视图
|
// 商品详情视图
|
||||||
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';
|
||||||
|
|
||||||
@@ -481,15 +474,6 @@ 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>
|
||||||
@@ -497,36 +481,4 @@ 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 scoped></style>
|
||||||
.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,8 +26,7 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
diyData: null,
|
diyData: null
|
||||||
mpShareData: null //小程序分享数据
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
@@ -39,25 +38,6 @@ export default {
|
|||||||
onShow() {
|
onShow() {
|
||||||
this.$util.hideHomeButton();
|
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();
|
||||||
@@ -89,24 +69,6 @@ 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" @aiChatClick="sendToAIChat(goodsSkuDetail)">
|
<goods-detail-view :goodsSkuDetail="goodsSkuDetail" ref="goodsDetailView">
|
||||||
<!-- 价格区域 -->
|
<!-- 价格区域 -->
|
||||||
<template v-slot:price>
|
<template v-slot:price>
|
||||||
<!-- 限时折扣 -->
|
<!-- 限时折扣 -->
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
</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>
|
||||||
@@ -460,12 +461,11 @@
|
|||||||
<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 == 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 == 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" /> -->
|
|
||||||
|
|
||||||
|
<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="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,19 +515,6 @@
|
|||||||
|
|
||||||
<!-- 隐私弹窗 -->
|
<!-- 隐私弹窗 -->
|
||||||
<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>
|
||||||
|
|
||||||
@@ -544,61 +531,9 @@ 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';
|
||||||
@@ -610,57 +545,6 @@ 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 {
|
||||||
@@ -756,5 +640,4 @@ 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)" :show-menu-by-longpress="true"></image>
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"></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,23 +75,68 @@
|
|||||||
<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" v-if="item.sale_show">已售{{ item.sale_num }}{{ item.unit
|
<view class="sale color-tip" 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 class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
<view v-else-if="config.style == 'icon-add'" :style="{
|
||||||
<view class="ai-chat-btn" @click.stop="sendToAIChat(item)">
|
color: config.theme == 'diy' ? config.textColor : '',
|
||||||
立即咨询
|
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>
|
||||||
@@ -102,7 +147,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)" :show-menu-by-longpress="true"></image>
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"></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">
|
||||||
@@ -123,23 +168,66 @@
|
|||||||
<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" v-if="item.sale_show">已售{{ item.sale_num }}{{ item.unit
|
<view class="sale color-tip" 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 class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
<view v-else-if="config.style == 'icon-add'" :style="{
|
||||||
<view class="ai-chat-btn" @click.stop="sendToAIChat(item)">
|
color: config.theme == 'diy' ? config.textColor : '',
|
||||||
立即咨询
|
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>
|
||||||
@@ -223,14 +311,7 @@ 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>
|
||||||
|
|
||||||
@@ -246,24 +327,4 @@ 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,8 +295,7 @@
|
|||||||
|
|
||||||
.lineheight-clear {
|
.lineheight-clear {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 商品列表单列样式
|
// 商品列表单列样式
|
||||||
@@ -387,30 +386,46 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-top: 0;
|
margin-top: 16rpx;
|
||||||
|
|
||||||
|
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: #ff4444;
|
color: var(--price-color);
|
||||||
}
|
}
|
||||||
.price {
|
.price {
|
||||||
color: #ff4444;
|
color: var(--price-color);
|
||||||
font-size: 32rpx !important;
|
color: #fff !important;
|
||||||
|
font-size: 27rpx !important;
|
||||||
font-weight: bold !important;
|
font-weight: bold !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pro-info {
|
.pro-info {
|
||||||
margin-top: 10rpx;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
margin-top: auto;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -528,9 +543,6 @@
|
|||||||
|
|
||||||
.lineheight-clear {
|
.lineheight-clear {
|
||||||
margin-top: 16rpx;
|
margin-top: 16rpx;
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.discount-price {
|
.discount-price {
|
||||||
@@ -540,26 +552,24 @@
|
|||||||
|
|
||||||
.unit {
|
.unit {
|
||||||
margin-right: 6rpx;
|
margin-right: 6rpx;
|
||||||
color: #ff4444;
|
color: var(--price-color);
|
||||||
}
|
}
|
||||||
.price {
|
.price {
|
||||||
color: #ff4444;
|
color: var(--price-color);
|
||||||
font-size: 32rpx !important;
|
|
||||||
font-weight: bold !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pro-info {
|
.pro-info {
|
||||||
margin-top: 10rpx;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
margin-top: auto;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -634,9 +644,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.buy-btn {
|
.buy-btn {
|
||||||
background-color: #ff4444;
|
background-color: $base-color;
|
||||||
color: #fff;
|
color: var(--btn-text-color);
|
||||||
border-radius: 30rpx;
|
border-radius: 50rpx;
|
||||||
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
@@ -1,17 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container" :style="wrapperPageStyle">
|
<view class="container" :style="wrapperPageStyle">
|
||||||
<!--自定义导航头部 - 只在微信小程序显示,H5端隐藏 -->
|
<!--自定义导航头部 -->
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<view class="custom-navbar" ref="pageHeader" v-if="showCustomNavbar">
|
<view class="custom-navbar" ref="pageHeader" v-if="showCustomNavbar">
|
||||||
<view class="header-left">
|
<view class="header-left">
|
||||||
<button class="back-btn" v-show="showBackButton" @click="goBack">
|
<button class="back-btn" v-show="showBackButton" @click="goBack">
|
||||||
<text class="iconfont icon-back"></text>
|
<text class="iconfont icon-back"></text>
|
||||||
</button>
|
</button>
|
||||||
<!-- 占位元素,确保布局平衡 -->
|
<!-- 占位元素,确保布局平衡 -->
|
||||||
|
<view v-show="!showBackButton" class="placeholder"></view>
|
||||||
|
</view>
|
||||||
|
<view class="header-center">
|
||||||
|
<text class="header-subtitle">在线为您服务</text>
|
||||||
|
</view>
|
||||||
|
<view class="header-right">
|
||||||
|
<button class="menu-btn" v-show="showMenuButton" @click="showMenu">
|
||||||
|
<text>⚙️</text>
|
||||||
|
</button>
|
||||||
|
<!-- 占位元素,确保布局平衡 -->
|
||||||
<view v-show="!showMenuButton" class="placeholder"></view>
|
<view v-show="!showMenuButton" class="placeholder"></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- #endif -->
|
|
||||||
|
|
||||||
<!-- 聊天内容区域 -->
|
<!-- 聊天内容区域 -->
|
||||||
<view class="chat-content"
|
<view class="chat-content"
|
||||||
@@ -79,7 +87,6 @@ import { mapGetters, mapMutations } from 'vuex'
|
|||||||
import navigationHelper from '@/common/js/navigation';
|
import navigationHelper from '@/common/js/navigation';
|
||||||
import { EventSafety } from '@/common/js/event-safety';
|
import { EventSafety } from '@/common/js/event-safety';
|
||||||
import aiChatMessage from './ai-chat-message.vue';
|
import aiChatMessage from './ai-chat-message.vue';
|
||||||
import IMAGE_CONFIG from '@/common/js/image-config.js';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -94,6 +101,10 @@ export default {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
content: '您好!我是AI智能客服,很高兴为您服务!\n\n我可以帮您:\n• 解答产品相关问题\n• 处理订单问题\n• 提供技术支持\n• 推荐相关商品\n\n请告诉我您需要什么帮助?',
|
content: '您好!我是AI智能客服,很高兴为您服务!\n\n我可以帮您:\n• 解答产品相关问题\n• 处理订单问题\n• 提供技术支持\n• 推荐相关商品\n\n请告诉我您需要什么帮助?',
|
||||||
timestamp: Date.now() - 60000,
|
timestamp: Date.now() - 60000,
|
||||||
|
actions: [
|
||||||
|
{ type: 'like', icon: 'icon-dianzan1', text: '喜欢', count: 0 },
|
||||||
|
{ type: 'dislike', icon: 'icon-dianzan1', text: '不喜欢', count: 0 }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -110,9 +121,6 @@ export default {
|
|||||||
// --- 聊天内容区域 ---
|
// --- 聊天内容区域 ---
|
||||||
scrollViewHeight: '0px',
|
scrollViewHeight: '0px',
|
||||||
|
|
||||||
// --- 键盘高度 ---
|
|
||||||
keyboardHeight: 0,
|
|
||||||
|
|
||||||
// 事件处理器引用(用于清理)
|
// 事件处理器引用(用于清理)
|
||||||
safeEventHandlers: new Map()
|
safeEventHandlers: new Map()
|
||||||
}
|
}
|
||||||
@@ -125,10 +133,10 @@ export default {
|
|||||||
|
|
||||||
/// ---- 关于AI客服的配置,支持远程配置 ----
|
/// ---- 关于AI客服的配置,支持远程配置 ----
|
||||||
userAvatar() {
|
userAvatar() {
|
||||||
return this.globalAIKefuConfig?.userAvatar || this.$util.img(IMAGE_CONFIG.userAvatar)
|
return this.globalAIKefuConfig?.userAvatar || '/static/images/user-avatar.png'
|
||||||
},
|
},
|
||||||
aiAvatar() {
|
aiAvatar() {
|
||||||
return this.globalAIKefuConfig?.aiAvatar || this.$util.img(IMAGE_CONFIG.aiAvatar)
|
return this.globalAIKefuConfig?.aiAvatar || '/static/images/ai-avatar.png'
|
||||||
},
|
},
|
||||||
/// ---- others ----
|
/// ---- others ----
|
||||||
containerHeight() {
|
containerHeight() {
|
||||||
@@ -146,21 +154,10 @@ export default {
|
|||||||
return ``
|
return ``
|
||||||
},
|
},
|
||||||
wrapperChatContentStyle() {
|
wrapperChatContentStyle() {
|
||||||
// #ifdef H5
|
|
||||||
// H5端没有自定义导航栏,不需要paddingTop
|
|
||||||
return {
|
|
||||||
height: this.containerHeight,
|
|
||||||
paddingTop: '0'
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
// 微信小程序端根据导航栏显示情况决定
|
|
||||||
return {
|
return {
|
||||||
height: this.containerHeight,
|
height: this.containerHeight,
|
||||||
paddingTop: this.showCustomNavbar ? '0' : (this.navBarHeight + 'px')
|
paddingTop: this.showCustomNavbar ? '0' : (this.navBarHeight + 'px')
|
||||||
}
|
}
|
||||||
// #endif
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -181,23 +178,11 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
// 监听键盘高度变化
|
// 可在此补充逻辑(如刷新未读数)
|
||||||
uni.onKeyboardHeightChange((res) => {
|
|
||||||
console.log('键盘高度变化:', res.height);
|
|
||||||
this.keyboardHeight = res.height;
|
|
||||||
if (this.$refs.chat && this.$refs.chat.updateKeyboardHeight) {
|
|
||||||
this.$refs.chat.updateKeyboardHeight(res.height);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onHide() {
|
onHide() {
|
||||||
// 取消监听键盘高度变化
|
// 页面隐藏时可暂停音频等
|
||||||
uni.offKeyboardHeightChange();
|
|
||||||
this.keyboardHeight = 0;
|
|
||||||
if (this.$refs.chat && this.$refs.chat.updateKeyboardHeight) {
|
|
||||||
this.$refs.chat.updateKeyboardHeight(0);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload() {
|
onUnload() {
|
||||||
@@ -272,20 +257,6 @@ export default {
|
|||||||
// ========== 初始化页面 ==========
|
// ========== 初始化页面 ==========
|
||||||
initChat() {
|
initChat() {
|
||||||
console.log('AI聊天页面初始化');
|
console.log('AI聊天页面初始化');
|
||||||
|
|
||||||
// 检查是否有从商品分类传递过来的商品信息
|
|
||||||
const selectedProduct = uni.getStorageSync('selectedProduct')
|
|
||||||
if (selectedProduct) {
|
|
||||||
console.log('检测到选择的商品:', selectedProduct)
|
|
||||||
|
|
||||||
// 清除存储的商品信息,避免重复发送
|
|
||||||
uni.removeStorageSync('selectedProduct')
|
|
||||||
|
|
||||||
// 延迟发送商品信息,确保聊天组件已经初始化
|
|
||||||
setTimeout(() => {
|
|
||||||
this.sendProductToAI(selectedProduct)
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async initNavigation() {
|
async initNavigation() {
|
||||||
@@ -511,20 +482,6 @@ export default {
|
|||||||
onVideoPause(message) {
|
onVideoPause(message) {
|
||||||
console.log('视频暂停:', message);
|
console.log('视频暂停:', message);
|
||||||
},
|
},
|
||||||
|
|
||||||
sendProductToAI(product) {
|
|
||||||
if (!this.$refs.chat) {
|
|
||||||
console.error('聊天组件未初始化')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const productContent = `我想了解以下商品的详细信息:\n商品名称:${product.goods_name}\n价格:¥${product.price}\n商品ID:${product.goods_id}`
|
|
||||||
|
|
||||||
console.log('商品信息已发送到AI客服:', productContent)
|
|
||||||
|
|
||||||
// 使用sendMessageWithContent方法发送商品信息
|
|
||||||
this.$refs.chat.sendMessageWithContent(productContent)
|
|
||||||
},
|
|
||||||
|
|
||||||
onLinkOpen(message) {
|
onLinkOpen(message) {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
@@ -614,8 +571,8 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 20rpx 30rpx;
|
padding: 20rpx 30rpx;
|
||||||
background-color: white; /* 白色 */
|
background-color: #c4e0ff; /* 浅蓝色 */
|
||||||
border-bottom: 1rpx solid #e5e5e5;
|
border-bottom: 2rpx solid #eeeeee;
|
||||||
|
|
||||||
.header-left {
|
.header-left {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|||||||
@@ -248,8 +248,7 @@ export default {
|
|||||||
latitude: 0,
|
latitude: 0,
|
||||||
longitude: 0,
|
longitude: 0,
|
||||||
},
|
},
|
||||||
personnel_bg: '',
|
personnel_bg: ''
|
||||||
mpShareData: null //小程序分享数据
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad(option) {
|
onLoad(option) {
|
||||||
@@ -304,24 +303,6 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
onShow() {
|
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();
|
this.$util.hideHomeButton();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -468,28 +449,9 @@ 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,8 +134,7 @@ export default {
|
|||||||
levelId: 0,
|
levelId: 0,
|
||||||
levelInfo: {
|
levelInfo: {
|
||||||
bg_color: '#333'
|
bg_color: '#333'
|
||||||
},
|
}
|
||||||
mpShareData: null //小程序分享数据
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
@@ -162,26 +161,7 @@ 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;
|
||||||
@@ -205,24 +185,6 @@ 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)" :show-menu-by-longpress="true"></image>
|
@error="goodsImageError(index)"></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)" :show-menu-by-longpress="true"></image>
|
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"></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)">
|
||||||
|
|||||||
30
readme.md
30
readme.md
@@ -37,7 +37,7 @@
|
|||||||
*已有依赖可跳过此步骤*
|
*已有依赖可跳过此步骤*
|
||||||
|
|
||||||
##### 4.1.1.2 【发布构建】
|
##### 4.1.1.2 【发布构建】
|
||||||
1. 使用 HBuilderX 打开项目(不用改manifest.json的web,只有H5要改 )
|
1. 使用 HBuilderX 打开项目
|
||||||
2. 选择菜单栏「发行」 → 「小程序-微信」→ 「发行」,等待构建完成
|
2. 选择菜单栏「发行」 → 「小程序-微信」→ 「发行」,等待构建完成
|
||||||
⚠️ **注意**:底部控制台弹出"请在微信小程序开发者工具中点击上传"后再执行下一步
|
⚠️ **注意**:底部控制台弹出"请在微信小程序开发者工具中点击上传"后再执行下一步
|
||||||
3. 打开资源管理器→项目根目录,右键选择「在终端中打开」,执行命令:
|
3. 打开资源管理器→项目根目录,右键选择「在终端中打开」,执行命令:
|
||||||
@@ -67,9 +67,7 @@
|
|||||||
- 确认 `site.js` 中的 `uniacid` 为客户编号
|
- 确认 `site.js` 中的 `uniacid` 为客户编号
|
||||||
- 用微信开发者工具导入解压后的代码目录
|
- 用微信开发者工具导入解压后的代码目录
|
||||||
- 编译验证无误后,上传发布
|
- 编译验证无误后,上传发布
|
||||||
##### 4.1.1.5 【本地设置】
|
|
||||||

|
|
||||||
#####
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 4.2 快应用发布
|
### 4.2 快应用发布
|
||||||
@@ -80,22 +78,20 @@
|
|||||||
1. 使用 HBuilderX 打开项目
|
1. 使用 HBuilderX 打开项目
|
||||||
2. 打开项目根目录的 `manifest.json` 文件,切换至可视化配置界面:
|
2. 打开项目根目录的 `manifest.json` 文件,切换至可视化配置界面:
|
||||||
1. 依次点击「Web 配置」→「运行的基础配置」
|
1. 依次点击「Web 配置」→「运行的基础配置」
|
||||||
2. 根据情况查看是否修改路径中/hwappx/????/的客户编号
|
2. 修改路径中的客户编号
|
||||||
📌 **通用版**保留原有 `/hwappx/common/`
|
3. 📌 **通用版**保留原有 `/hwappx/common/`
|
||||||
📌 **测试版**保留原有 `/hwappx/test/`
|
|
||||||
💡 **个性化定制示例**:`/hwappx/2811/`,其中 2811 为定制化版客户编号
|
💡 **示例**:`/hwappx/2811/`,其中 2811 为定制化版客户编号
|
||||||
|
|
||||||
3. 选择菜单栏「发行」 → 「自定义发行」 →(「H5-xcx.aigc-quickapp.com」查看.local.config.js中站点的网址前缀,站点的网址前缀是什么就选自定义发行中相同的格式)
|
3. 选择菜单栏「发行」 → 「自定义发行」 →「H5-xcx.aigc-quickapp.com」,修改以下配置:
|
||||||
例如:网址是5g.aigc-quickapp.com,自定义发行就选H5-5g.aigc-quickapp.com
|
|
||||||
网址是dev.aigc-quickapp.com,自定义发行就选H5-xcx.aigc-quickapp.com
|
|
||||||
4. 修改以下配置:
|
|
||||||
1. **网站标题**:快应用
|
1. **网站标题**:快应用
|
||||||
2. **网站域名**:当前客户域名(示例:xcx.aigc-quickapp.com或者5g.aigc-quickapp.com)
|
2. **网站域名**:当前客户域名(示例:xcx.aigc-quickapp.com)
|
||||||
3. 确认后点击「发行」等待构建完成
|
3. 确认后点击「发行」等待构建完成
|
||||||
|
|
||||||
⚠️ **注意**:底部控制台弹出“项目 lucky_shop 导出Web成功,路径为:D:\项目文件\项目根目录\unpackage\dist\build\web”后再执行下一步
|
⚠️ **注意**:底部控制台弹出“项目 lucky_shop 导出Web成功,路径为:D:\项目文件\项目根目录\unpackage\dist\build\web”后再执行下一步
|
||||||
💡 **示例**:`项目 lucky_shop 导出Web成功,路径为:D:\0.项目源码\lucky_shop\unpackage\dist\build\web`
|
💡 **示例**:`项目 lucky_shop 导出Web成功,路径为:D:\0.项目源码\lucky_shop\unpackage\dist\build\web`
|
||||||
5. 按控制台提示的路径找到 `web` 目录,将该目录下所有文件手动打包成一个 `.zip` 压缩包
|
|
||||||
|
4. 按控制台提示的路径找到 `web` 目录,将该目录下所有文件手动打包成一个 `.zip` 压缩包
|
||||||
*仅打包文件,不包含外层 web 目录*
|
*仅打包文件,不包含外层 web 目录*
|
||||||
|
|
||||||
##### 4.2.1.2 【重命名】
|
##### 4.2.1.2 【重命名】
|
||||||
@@ -109,16 +105,12 @@
|
|||||||
🚫 **禁止**:压缩包命名禁止包含 `/ \ : * ? " < > |` 等特殊字符
|
🚫 **禁止**:压缩包命名禁止包含 `/ \ : * ? " < > |` 等特殊字符
|
||||||
|
|
||||||
##### 4.2.1.3 【交付与最终发布】🔍
|
##### 4.2.1.3 【交付与最终发布】🔍
|
||||||
|
|
||||||
1. 将重命名后的压缩包发送给运维人员
|
1. 将重命名后的压缩包发送给运维人员
|
||||||
2. **运维人员操作流程**:
|
2. **运维人员操作流程**:
|
||||||
1. 解压压缩包
|
1. 解压压缩包
|
||||||
2. 打开快应用开发者工具,导入解压后的代码目录
|
2. 打开快应用开发者工具,导入解压后的代码目录
|
||||||
3. 验证代码无报错后,执行上传发布操作
|
3. 验证代码无报错后,执行上传发布操作
|
||||||
##### 4.2.1.3 【测试流程】
|
|
||||||
H5:打开自己的浏览器输入网址(https://5g.aigc-quickapp.com/hwappx/common/?uniacid=75)改站点
|
|
||||||
如果是test就把hwappx/common/改为hwappx/test/----------改站点
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. 📝 构建脚本说明
|
## 5. 📝 构建脚本说明
|
||||||
|
|||||||
@@ -134,9 +134,8 @@ 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 buildDir = options.mode === 'production' ? 'build' : 'dev';
|
const sourceDir = path.join(cwd, 'unpackage', 'dist', 'build', 'mp-weixin');
|
||||||
const sourceDir = path.join(cwd, 'unpackage', 'dist', buildDir, 'mp-weixin');
|
const destDir = path.join(cwd, 'unpackage', 'dist', 'build');
|
||||||
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}`);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user