Compare commits

..

14 Commits

342 changed files with 14761 additions and 24186 deletions

1
.gitignore vendored
View File

@@ -2,4 +2,3 @@
/.hbuilderx
/.idea
/node_modules
/iconfont-preview.html

View File

@@ -1,66 +0,0 @@
// 本地调试配置示例文件
// 复制此文件并重命名为 local.config.js 以使用自定义本地配置
const localDevConfig = ({
'460': { // 制氧设备平台
uniacid: 460,
domain: 'https://xcx30.5g-quickapp.com/',
},
'576-xcx30.5g': { // 活性石灰装备
uniacid: 576,
domain: 'https://xcx30.5g-quickapp.com/',
},
'2285': { // 数码喷墨墨水
uniacid: 2285,
domain: 'https://xcx.aigc-quickapp.com/',
},
'2811': { // POCT检测分析平台
uniacid: 2811,
domain: 'https://xcx6.aigc-quickapp.com/',
},
'2724': { // 生物菌肥
uniacid: 2724,
domain: 'https://xcx.aigc-quickapp.com/',
},
'2505': { // 煤矿钻机
uniacid: 2505,
domain: 'https://xcx.aigc-quickapp.com/',
},
'2777': { // 养老服务
uniacid: 2777,
domain: 'https://xcx.aigc-quickapp.com/',
},
'1': { // 开发平台
uniacid: 1,
domain: 'https://dev.aigc-quickapp.com',
},
'1-test': { // 测试平台
uniacid: 1,
domain: 'https://test.aigc-quickapp.com',
},
'local-2': { // 测试平台
uniacid: 2,
domain: 'http://localhost:8050/',
},
'100': {
uniacid: 100,
domain: 'https://5g.aigc-quickapp.com/',
},
'1': {
uniacid: 1,
domain: 'https://5g.aigc-quickapp.com/',
},
'115': {
uniacid: 115,
domain: 'https://5g.aigc-quickapp.com/',
},
'47': { // 修改弹窗
uniacid: 47,
domain: 'https://5g.aigc-quickapp.com/',
},
'2075': { //
uniacid: 2075,
domain: 'https://xcx.aigc-quickapp.com/',
},
})['1']; // 选择要使用的环境配置
export default localDevConfig;

View File

@@ -6,34 +6,10 @@ const localDevConfig = ({
uniacid: 460,
domain: 'https://xcx30.5g-quickapp.com/',
},
'576-xcx30.5g': { // 活性石灰装备
uniacid: 576,
domain: 'https://xcx30.5g-quickapp.com/',
},
'2285': { // 数码喷墨墨水
uniacid: 2285,
domain: 'https://xcx.aigc-quickapp.com/',
},
'2811': { // POCT检测分析平台
uniacid: 2811,
domain: 'https://xcx6.aigc-quickapp.com/',
},
'2812': { // IVD数商模式
uniacid: 2812,
domain: 'https://xcx6.aigc-quickapp.com/',
},
'2724': { // 生物菌肥
uniacid: 2724,
domain: 'https://xcx.aigc-quickapp.com/',
},
'2505': { // 煤矿钻机
uniacid: 2505,
domain: 'https://xcx.aigc-quickapp.com/',
},
'2777': { // 养老服务
uniacid: 2777,
domain: 'https://xcx.aigc-quickapp.com/',
},
'1': { // 开发平台
uniacid: 1,
domain: 'https://dev.aigc-quickapp.com',
@@ -42,14 +18,6 @@ const localDevConfig = ({
uniacid: 1,
domain: 'https://test.aigc-quickapp.com',
},
'local-2': { // 测试平台
uniacid: 2,
domain: 'http://localhost:8050/',
},
'local-2-dev': { // 本地开发测试平台
uniacid: 2,
domain: 'http://localhost:8050/',
},
})['2812']; // 选择要使用的环境配置
})['2285']; // 选择要使用的环境配置
export default localDevConfig;

10
App.vue
View File

@@ -8,7 +8,7 @@
export default {
mixins: [auth],
onLaunch: async function(options) {
onLaunch: function(options) {
// 方式:支持快应用,从url中query部分获取uniacid,或useragent中获取uniacid
if(options.query.uniacid){
uni.setStorageSync('uniacid', options.query.uniacid);
@@ -40,7 +40,7 @@
// #endif
// #ifdef H5
if (this.$util.getDeviceInfo().platform == 'ios') {
if (uni.getSystemInfoSync().platform == 'ios') {
uni.setStorageSync('initUrl', location.href);
}
// #endif
@@ -61,8 +61,7 @@
// 主题风格
if (uni.getStorageSync('themeStyle')) {
const themeData = await configExternal.loadTheme(uni.getStorageSync('themeStyle'));
this.$store.commit('setThemeStyle', themeData);
this.$store.commit('setThemeStyle', configExternal.loadThemeSync(uni.getStorageSync('themeStyle')));
this.$store.dispatch('themeColorSet');
}
@@ -266,6 +265,7 @@
imgUrl: this.$util.img(share_data.imgUrl)
},
res => {
console.log(res);
}
);
}
@@ -313,7 +313,7 @@
@import './common/css/iconfont.css';
@import './common/css/icondiy.css'; // 自定义图标库
@import './common/css/icon/extend.css'; // 扩展图标库
page {
page{
background: #f4f6fa;
}
</style>

View File

@@ -123,7 +123,7 @@ image {
}
.choose-store {
::v-deep .uni-popup__wrapper{
/deep/ .uni-popup__wrapper{
background: none!important;
}
}

View File

@@ -870,13 +870,13 @@
// 海报
// .uni-popup__wrapper-box
.poster-layer {
::v-deep .uni-popup__wrapper.center {
/deep/ .uni-popup__wrapper.center {
width: 100vw!important;
height: 100vh!important;
background: none!important;
}
::v-deep .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
/deep/ .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
max-width: 100vw!important;
max-height: 100vh!important;
background: none!important;

View File

@@ -559,7 +559,7 @@ scroll-view ::-webkit-scrollbar {
background-color: transparent;
}
::v-deep ::-webkit-scrollbar {
/deep/::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
@@ -609,7 +609,7 @@ scroll-view ::-webkit-scrollbar {
font-weight: 500!important;
}
::v-deep .reward-popup .uni-popup__wrapper-box {
/deep/ .reward-popup .uni-popup__wrapper-box {
background: none !important;
max-width: unset !important;
max-height: unset !important;
@@ -618,7 +618,7 @@ scroll-view ::-webkit-scrollbar {
// #ifdef H5
// 下拉加载动画【页面】
::v-deep body uni-page-refresh div{
/deep/ body uni-page-refresh div{
width: 14rpx !important;
height: 14rpx !important;
background-color: #ccc;
@@ -626,7 +626,7 @@ scroll-view ::-webkit-scrollbar {
clip: rect(-152rpx, 90rpx, 90rpx, -30rpx) !important;
animation:.6s backgroundChange linear infinite;
}
::v-deep body uni-page-refresh div::after{
/deep/ body uni-page-refresh div::after{
content: "";
position: absolute;
left: -22rpx;
@@ -636,7 +636,7 @@ scroll-view ::-webkit-scrollbar {
background-color: #ccc;
animation:.5s backgroundChange linear infinite;
}
::v-deep body uni-page-refresh div::before{
/deep/ body uni-page-refresh div::before{
content: "";
position: absolute;
right: -22rpx;
@@ -646,15 +646,15 @@ scroll-view ::-webkit-scrollbar {
background-color: #ccc;
animation:.7s backgroundChange linear infinite;
}
::v-deep body uni-page-refresh > div > div{
/deep/ body uni-page-refresh > div > div{
display: none !important;
}
// 下拉加载动画【scroll-view】
::v-deep body .uni-scroll-view-refresher{
/deep/ body .uni-scroll-view-refresher{
background-color: transparent !important;
}
::v-deep body .uni-scroll-view-refresher div{
/deep/ body .uni-scroll-view-refresher div{
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
@@ -666,7 +666,7 @@ scroll-view ::-webkit-scrollbar {
clip: rect(-152rpx, 90rpx, 90rpx, -30rpx) !important;
animation:.6s backgroundChange linear infinite;
}
::v-deep body .uni-scroll-view-refresher div::after{
/deep/ body .uni-scroll-view-refresher div::after{
content: "";
position: absolute;
left: -22rpx;
@@ -676,7 +676,7 @@ scroll-view ::-webkit-scrollbar {
background-color: #ccc;
animation:.5s backgroundChange linear infinite;
}
::v-deep body .uni-scroll-view-refresher div::before{
/deep/ body .uni-scroll-view-refresher div::before{
content: "";
position: absolute;
right: -22rpx;
@@ -686,7 +686,7 @@ scroll-view ::-webkit-scrollbar {
background-color: #ccc;
animation:.7s backgroundChange linear infinite;
}
::v-deep body .uni-scroll-view-refresher > div > div{
/deep/ body .uni-scroll-view-refresher > div > div{
display: none !important;
}
@keyframes backgroundChange {

View File

@@ -1,4 +1,4 @@
// 修复图片垂直对齐问题,解决两张图片上下有空白缝隙问题
::v-deep ._img {
/deep/ ._img {
vertical-align: top;
}

View File

@@ -377,7 +377,7 @@ view {
}
}
::v-deep .goods-form {
/deep/ .goods-form {
display: flex;
align-items: center;
position: relative;
@@ -1354,7 +1354,7 @@ view {
border-bottom: 2rpx solid #F4F4F6;
}
::v-deep .form-wrap {
/deep/ .form-wrap {
margin: 0 24rpx;
.icon-right {

View File

@@ -5,17 +5,6 @@ import store from '@/store/index.js'
let currentConversationId = null;
const CONVERSATION_KEY = 'ai_conversation_id';
/**
* 获取域名配置参数(避免重复代码)
*/
function getDomainParams() {
return {
imgDomain: Config.imgDomain,
h5Domain: Config.h5Domain,
baseUrl: Config.baseUrl
};
}
// 初始化时从本地读取会话ID
try {
const saved = uni.getStorageSync(CONVERSATION_KEY);
@@ -27,19 +16,12 @@ try {
}
export default {
/**
* 获取uniacid
* @returns {number} uniacid
*/
getUniacid() {
return uni.getStorageSync('uniacid') || Config.uniacid; // 从缓存中获取uniacid,或使用默认uniacid
},
/**
* 发送普通消息(blocking 模式)
*/
async sendMessage(message, options = {}) {
try {
const aiConfig = store.getters.globalAIKefuConfig;
const params = {
url: '/api/kefu/chat',
data: {
@@ -49,14 +31,16 @@ export default {
query: message,
response_mode: 'blocking', // 强制 blocking
user: store.state.memberInfo?.id || 'anonymous',
conversation_id: this.getConversationId() || '',
...getDomainParams()
conversation_id: this.getConversationId() || ''
},
header: {
'Content-Type': 'application/json'
}
};
console.log('Sending blocking request to:', params.url);
console.log('Request data:', params.data);
const response = await http.sendRequest({
...params,
async: false
@@ -68,14 +52,7 @@ export default {
}
return result;
} catch (error) {
console.error('[AI Service] AiChat API请求失败,详细错误:', error);
console.error('[AI Service] 错误堆栈:', error.stack);
// 打印更多信息帮助调试
console.error('[AI Service] store 状态:', {
memberInfo: store.state.memberInfo,
uniacid: this.getUniacid(),
token: store.state.token
});
console.error('Dify API请求失败:', error);
throw new Error('AI服务暂时不可用,请稍后重试');
}
},
@@ -83,136 +60,55 @@ export default {
/**
* 流式消息入口(自动适配平台)
*/
async sendStreamMessage(message, onChunk, onComplete) {
// #ifdef MP-WEIXIN
return new Promise((resolve, reject) => {
const match = Config.baseUrl.match(/^(?:https?:\/\/|wss?:\/\/)([^\/\s:]+)/);
const domain = match ? match[1] : '';
async sendStreamMessage(message, onChunk, onComplete) {
// #ifdef MP-WEIXIN
// 微信小程序:降级为普通请求 + 前端打字模拟
try {
const result = await this.sendMessage(message);
const content = result.content || '';
const conversationId = result.conversationId || '';
// 修复 5:Domain 提取失败时提前拒绝
if (!domain) {
const errorMsg = 'WebSocket 域名配置无效';
console.error(errorMsg);
reject(new Error(errorMsg));
if (onComplete) onComplete({ error: errorMsg });
return;
}
// 保存会话ID(确保连续对话)
if (conversationId) {
this.setConversationId(conversationId);
}
const wssUrl = `wss://${domain}/ws/aikefu`;
const socketTask = wx.connectSocket({
url: wssUrl,
header: {}
});
let content = '';
let conversationId = '';
let isAuthenticated = false;
let closedNormally = false;
let settled = false;
// 安全地拒绝(防止重复调用)
function safeReject(error) {
if (settled) return;
settled = true;
clearTimeout(timeout);
reject(error);
}
// 安全地完成
function safeResolve(result) {
if (settled) return;
settled = true;
clearTimeout(timeout);
resolve(result);
}
// 安全地触发 onComplete
function safeComplete(result) {
if (onComplete) onComplete(result);
}
socketTask.onOpen(() => {
socketTask.send({
data: JSON.stringify({
action: 'auth',
uniacid: this.getUniacid(),
token: store.state.token || 'test_token',
user_id: store.state.memberInfo?.id || 'anonymous'
})
});
});
socketTask.onMessage((res) => {
try {
const data = JSON.parse(res.data);
if (data.type === 'auth_success') {
isAuthenticated = true;
socketTask.send({
data: JSON.stringify({
action: 'chat',
uniacid: this.getUniacid(),
query: message,
user_id: store.state.memberInfo?.id || 'anonymous',
conversation_id: this.getConversationId() || '',
...getDomainParams()
})
});
} else if (data.type === 'auth_failed') {
const errorMsg = '认证失败,请重新登录';
console.error(errorMsg, data);
safeComplete({ error: errorMsg });
safeReject(new Error(errorMsg));
socketTask.close();
}
// 处理流式消息块
else if (data.event === 'message') {
const text = data.answer || data.content || data.text || '';
content += text;
if (onChunk) onChunk(text);
}
// 处理流结束
else if (data.event === 'message_end') {
conversationId = data.conversation_id || '';
if (conversationId) {
this.setConversationId(conversationId);
}
closedNormally = true;
safeComplete({ content, conversation_id: conversationId });
safeResolve({ content, conversation_id: conversationId });
socketTask.close();
}
// 可选:处理 done
else if (data.type === 'done') {
}
} catch (e) {
console.error('WebSocket 消息解析失败:', e, '原始数据:', res.data);
}
});
socketTask.onError((err) => {
const errorMsg = 'WebSocket 连接失败';
console.error(errorMsg, err);
safeComplete({ error: errorMsg });
safeReject(new Error(errorMsg));
});
socketTask.onClose(() => {
if (!closedNormally && !settled) {
const errorMsg = 'WebSocket 连接意外关闭';
console.error(errorMsg);
safeComplete({ error: errorMsg });
safeReject(new Error(errorMsg));
}
});
});
// 模拟打字效果
let index = 0;
const chunkSize = 2; // 每次显示2个字符
return new Promise((resolve) => {
const timer = setInterval(() => {
if (index < content.length) {
const chunk = content.substring(index, index + chunkSize);
index += chunkSize;
if (onChunk) onChunk(chunk);
} else {
clearInterval(timer);
if (onComplete) {
onComplete({
content: content,
conversation_id: conversationId
});
}
resolve({ content, conversation_id: conversationId });
}
}, 80); // 打字速度:80ms/次
});
} catch (error) {
console.error('小程序流式消息降级失败:', error);
if (onComplete) {
onComplete({ error: error.message || '发送失败' });
}
throw error;
}
// #endif
},
// #ifdef H5
// H5:使用真实流式(EventSource / Fetch)
return this.sendHttpStream(message, onChunk, onComplete);
// #endif
},
/**
* HTTP 流式请求(仅 H5 使用)
*/
@@ -227,85 +123,72 @@ export default {
'Accept': 'text/event-stream',
},
body: JSON.stringify({
uniacid: this.getUniacid(),
token: store.state.token || 'test_token',
uniacid: store.state.uniacid || '1',
inputs: {},
query: message,
response_mode: 'streaming',
user_id: store.state.memberInfo?.id || 'anonymous',
conversation_id: this.getConversationId() || '',
...getDomainParams()
conversation_id: this.getConversationId() || ''
})
});
if (!response.ok || !response.body) {
throw new Error('无效响应');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
if (!response.body) {
throw new Error('响应体不可用');
}
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = '';
let content = '';
let conversationId = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// 按行分割,保留不完整的最后一行
const lines = buffer.split('\n');
buffer = lines.pop() || ''; // 未完成的行留到下次
function processBuffer(buf, callback) {
const lines = buf.split('\n');
buf = lines.pop() || '';
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith('data:')) {
try {
const jsonStr = trimmed.slice(5).trim();
if (jsonStr && jsonStr !== '[DONE]') {
const jsonStr = trimmed.slice(5).trim();
if (jsonStr) {
try {
const data = JSON.parse(jsonStr);
if (data.event === 'message') {
const text = data.answer || data.text || '';
content += text;
if (onChunk) onChunk(text);
callback(text);
}
if (data.conversation_id) {
conversationId = data.conversation_id;
}
if (data.event === 'message_end') {
// 可提前结束
// 可选:提前完成
}
} catch (e) {
console.warn('解析流数据失败:', e);
}
} catch (e) {
console.warn('解析失败:', e, line);
}
}
}
return buf;
}
// 处理最后残留的 buffer(如果有)
if (buffer.trim().startsWith('data:')) {
try {
const jsonStr = buffer.trim().slice(5);
if (jsonStr) {
const data = JSON.parse(jsonStr);
if (data.event === 'message') {
const text = data.answer || '';
content += text;
if (onChunk) onChunk(text);
}
if (data.conversation_id) {
conversationId = data.conversation_id;
}
}
} catch (e) {
console.warn('最后 buffer 解析失败:', e);
}
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
buffer = processBuffer(buffer, (chunk) => {
if (onChunk) onChunk(chunk);
});
}
if (onComplete) {
onComplete({ content, conversation_id: conversationId });
onComplete({
content,
conversation_id: conversationId
});
}
return { content, conversation_id: conversationId };
} catch (error) {
@@ -313,6 +196,11 @@ export default {
throw error;
}
// #endif
// #ifdef MP-WEIXIN
// 理论上不会执行到这里,但防止 fallback
return this.sendStreamMessage(message, onChunk, onComplete);
// #endif
},
/**
@@ -368,19 +256,17 @@ export default {
* 生成新会话(如需)
*/
async generateConversationId() {
const params = {
url: '/api/kefu/createConversation',
data: {
uniacid: this.getUniacid(),
token: store.state.token || 'test_token',
user_id: store.state.memberInfo?.id || 'anonymous',
member_id: store.state.memberInfo?.id || 'anonymous',
...getDomainParams()
},
header: {
'Content-Type': 'application/json'
}
};
const params = {
url: '/api/kefu/createConversation',
data: {
uniacid: store.state.uniacid,
user_id: store.state.memberInfo?.id || 'anonymous',
member_id: store.state.memberInfo?.id || '',
},
header: {
'Content-Type': 'application/json'
}
};
const response = await http.sendRequest({
...params,
async: false
@@ -419,10 +305,7 @@ export default {
try {
const response = await http.sendRequest({
url: '/api/kefu/clear-conversation',
data: {
conversation_id: conversationId,
...getDomainParams()
},
data: { conversation_id: conversationId },
async: false
});
return response.success;
@@ -441,14 +324,13 @@ export default {
throw new Error('会话ID(conversation_id)是必填参数');
}
const requestData = {
uniacid: params.uniacid || this.getUniacid(),
uniacid: params.uniacid || store.state.uniacid || '1',
conversation_id: params.conversation_id,
user_id: params.user_id || store.state.memberInfo?.id || 'anonymous',
limit: params.limit || 20,
offset: params.offset || 0,
member_id: params.member_id || store.state.memberInfo?.id || 'anonymous',
token: params.token || '',
...getDomainParams()
member_id: params.member_id || store.state.memberInfo?.id || '',
token: params.token || ''
};
const response = await http.sendRequest({
url: '/api/kefu/getHistory',
@@ -487,17 +369,13 @@ export default {
if (window.currentEventSource) {
window.currentEventSource.close();
}
const paramsObj = {
uniacid: this.getUniacid(),
user_id: store.state.memberInfo?.id || 'anonymous',
member_id: store.state.memberInfo?.id || 'anonymous',
token: store.state.token || 'test_token',
const params = new URLSearchParams({
uniacid: store.state.uniacid || '1',
user_id: store.state.memberInfo?.id || '123456',
query: message,
conversation_id: conversationId || '',
stream: 'true',
...getDomainParams()
};
const params = new URLSearchParams(paramsObj);
stream: 'true'
});
const url = `${Config.baseUrl}/api/kefu/chat?${params.toString()}`;
try {
const eventSource = new EventSource(url);
@@ -553,4 +431,4 @@ export default {
return null;
// #endif
}
};
};

View File

@@ -14,7 +14,7 @@ export const langConfig = {
// 主题配置
export const themeConfig = {
// 主题列表
themeList: ['default', 'red', 'green', 'blue', 'pink', 'gold', 'purple', 'yellow', 'black'],
themeList: ['default', 'red', 'green', 'blue'],
// 默认主题
defaultTheme: 'default'
};
@@ -98,6 +98,28 @@ class ConfigExternal {
return this.loadPromises[key];
}
/**
* 加载主题配置(同步方式)
* @param {string} theme - 主题名称
* @returns {object} - 主题配置
*/
loadThemeSync(theme = themeConfig.defaultTheme) {
if (this.loadedConfigs[`theme_${theme}`]) {
return this.loadedConfigs[`theme_${theme}`];
}
try {
// 动态加载主题配置
const themeData = require(`@/common/js/style_color.js`)['default'][theme];
console.log('sync themeData => ', themeData);
this.loadedConfigs[`theme_${theme}`] = themeData;
return themeData;
} catch (error) {
console.error(`加载主题 ${theme} 失败:`, error);
return {};
}
}
/**
* 加载主题配置(异步方式)
* @param {string} theme - 主题名称
@@ -116,7 +138,7 @@ class ConfigExternal {
try {
// 动态加载主题配置
const themeData = require(`@/common/js/style_color.js`)['default'][theme];
// console.log('async themeData => ', themeData);
console.log('async themeData => ', themeData);
this.loadedConfigs[`theme_${theme}`] = themeData;
resolve(themeData);
} catch (error) {

View File

@@ -18,15 +18,18 @@ try {
// 线上版本部署域名, 注意: 必须以 '/' 结尾,适用于小程序/H5/快应用等场景
// 默认域名, 自定义发行时可以修改
let defaultDomain = '';
let defaultDomain = '';
// #ifdef H5
// 域名由 vue.config.js 中 DefinePlugin 注入的 process.env.UNI_APP_DOMAIN 传入
try {
if (process.env.UNI_APP_DOMAIN) {
defaultDomain = process.env.UNI_APP_DOMAIN;
}
} catch (e) {}
// #ifdef H5_XCX_AIGC_QUICKAPP_COM
defaultDomain = 'https://xcx.aigc-quickapp.com/';
// #endif
// #ifdef H5_5G_AIGC_QUICKAPP_COM
defaultDomain = 'https://5g.aigc-quickapp.com/';
// #endif
// #ifdef H5_TEST_AIGC_QUICKAPP_COM
defaultDomain = 'https://test.aigc-quickapp.com/';
// #endif
// 确保域名以 '/' 结尾
@@ -40,20 +43,19 @@ let localDevConfig = { uniacid: 0, domain: defaultDomain };
// #ifndef PRODUCTION
// 尝试动态加载本地配置文件
if (process?.env?.NODE_ENV === 'development') {
try {
// 尝试从项目根目录加载本地配置文件
// 使用相对路径的方式,确保在不同平台下都能正确解析
let customConfig = require('@/.local.config.js').default;
if (customConfig) {
localDevConfig = customConfig;
}
} catch (e) {
// 如果本地配置文件不存在或加载失败,保持使用默认配置
// 只在开发模式下输出提示信息
// #ifdef WEB
// #endif
try {
// 尝试从项目根目录加载本地配置文件
// 使用相对路径的方式,确保在不同平台下都能正确解析
let customConfig = require('@/.local.config.js').default;
if (customConfig) {
localDevConfig = customConfig;
}
} catch (e) {
// 如果本地配置文件不存在或加载失败,保持使用默认配置
// 只在开发模式下输出提示信息
// #ifdef WEB
console.log('本地配置文件 .local.config.js 不存在,使用默认配置');
// #endif
}
// #endif

View File

@@ -2,8 +2,6 @@
* 客服统一处理服务
* 整合各种客服方式,提供统一的调用接口
*/
import IMAGE_CONFIG from './image-config.js';
export class CustomerService {
constructor(vueInstance, externalConfig = null) {
this.vm = vueInstance;
@@ -30,28 +28,28 @@ export class CustomerService {
return this.latestPlatformConfig;
}
// 优先级:外部传入 > vuex store > 空对象
// 优先级:外部传入的最新配置 > vuex配置 > 空对象
const servicerConfig = this.externalConfig || this.vm.$store.state.servicerConfig || {};
console.log(`【实时客服配置】`, servicerConfig);
let platformConfig = null;
// #ifdef H5
platformConfig = servicerConfig.h5 && typeof servicerConfig.h5 === 'object' ? servicerConfig.h5 : null;
platformConfig = servicerConfig.h5 ? (typeof servicerConfig.h5 === 'object' ? servicerConfig.h5 : null) : null;
// #endif
// #ifdef MP-WEIXIN
platformConfig = servicerConfig.weapp && typeof servicerConfig.weapp === 'object' ? servicerConfig.weapp : null;
platformConfig = servicerConfig.weapp ? (typeof servicerConfig.weapp === 'object' ? servicerConfig.weapp : null) : null;
// #endif
// #ifdef MP-ALIPAY
platformConfig = servicerConfig.aliapp && typeof servicerConfig.aliapp === 'object' ? servicerConfig.aliapp : null;
platformConfig = servicerConfig.aliapp ? (typeof servicerConfig.aliapp === 'object' ? servicerConfig.aliapp : null) : null;
// #endif
// #ifdef PC
platformConfig = servicerConfig.pc && typeof servicerConfig.pc === 'object' ? servicerConfig.pc : null;
platformConfig = servicerConfig.pc ? (typeof servicerConfig.pc === 'object' ? servicerConfig.pc : null) : null;
// #endif
// 防止空数组被当作有效配置
// 处理空数组情况(你的配置中pc/aliapp是空数组,转为null)
if (Array.isArray(platformConfig)) {
platformConfig = null;
}
@@ -77,15 +75,6 @@ export class CustomerService {
return config && typeof config === 'object' && config.type;
}
/**
* 检查是否有有效的客服配置(用于判断是否显示客服按钮)
* @returns {Boolean}
*/
hasValidKefuConfig() {
const config = this.getPlatformConfig();
return config && typeof config === 'object' && config.type && config.type !== 'none';
}
/**
* 验证客服配置完整性
* @returns {Object} 验证结果
@@ -93,25 +82,39 @@ export class CustomerService {
validateConfig() {
const config = this.getPlatformConfig();
const wxworkConfig = this.getWxworkConfig();
const result = {
isValid: true,
errors: [],
warnings: []
};
if (!config || !config.type) {
if (!config) {
result.isValid = false;
result.errors.push('客服类型未配置');
result.errors.push('客服配置不存在');
return result;
}
if (config.type === 'aikefu') {
return result;
}
if (!config.type) {
result.isValid = false;
result.errors.push('客服类型未配置');
}
if (config.type === 'wxwork') {
if (!wxworkConfig || !wxworkConfig.enable) {
result.warnings.push('企业微信未启用');
}
if (!wxworkConfig.contact_url) {
result.warnings.push('企业微信活码链接未配置');
if (!wxworkConfig) {
result.isValid = false;
result.errors.push('企业微信配置不存在');
} else {
if (!wxworkConfig.enable) {
result.warnings.push('企业微信功能未启用');
}
if (!wxworkConfig.contact_url) {
result.warnings.push('企业微信活码链接未配置,将使用原有客服方式');
}
}
}
@@ -119,39 +122,40 @@ export class CustomerService {
}
/**
* 跳转到 AI智能客服页面(AiChat)
* 跳转到Dify客服页面
*/
openAiChatService() {
openDifyService() {
try {
// 清除未读数(如果存在)
if (typeof this.vm.setAiUnreadCount === 'function') {
if (this.vm.setAiUnreadCount) {
this.vm.setAiUnreadCount(0);
}
// ✅ 修正路径:必须与 pages.json 中注册的路径一致
const aiChatUrl = '/pages_tool/ai-chat/index';
// ✅ 使用 navigateTo 保留返回栈(体验更好)
uni.navigateTo({
url: aiChatUrl,
// 强制跳转,忽略框架层的封装
uni.redirectTo({
url: '/pages_tool/ai-chat/index',
fail: (err) => {
console.error('跳转 AI智能客服失败:', err);
// H5 兜底
// 兜底:使用window.location跳转(H5)
// #ifdef H5
window.location.href = aiChatUrl;
window.location.href = '/pages_tool/ai-chat/index';
// #endif
uni.showToast({ title: '打开客服失败', icon: 'none' });
console.error('跳转Dify客服失败:', err);
uni.showToast({
title: '跳转客服失败',
icon: 'none'
});
}
});
} catch (e) {
console.error('跳转 AI智能客服异常:', e);
uni.showToast({ title: '打开客服失败', icon: 'none' });
console.error('跳转Dify客服异常:', e);
uni.showToast({
title: '跳转客服失败',
icon: 'none'
});
}
}
/**
* 处理客服点击事件(统一入口)
* @param {Object} options 选项参数(用于消息卡片等)
* 处理客服点击事件
* @param {Object} options 选项参数
*/
handleCustomerClick(options = {}) {
const validation = this.validateConfig();
@@ -166,7 +170,6 @@ export class CustomerService {
}
const config = this.getPlatformConfig();
const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
if (config.type === 'none') {
@@ -174,10 +177,10 @@ export class CustomerService {
return;
}
// 核心路由:根据 type 决定行为
// 核心分支:根据最新的type处理
switch (config.type) {
case 'aikefu':
this.openAiChatService();
this.openDifyService();
break;
case 'wxwork':
this.openWxworkService(false, config, options);
@@ -185,9 +188,6 @@ export class CustomerService {
case 'third':
this.openThirdService(config);
break;
case 'miniprogram':
this.openThirdService(config);
break;
case 'niushop':
this.openNiushopService(niushop);
break;
@@ -198,40 +198,36 @@ export class CustomerService {
this.openAliappService(config);
break;
default:
console.error('【未知客服类型】', config.type);
this.makePhoneCall();
}
}
// ================== 各类型客服实现 ==================
/**
* 打开企业微信客服
* @param {boolean} useOriginalService 是否使用原有客服方式
* @param {Object} servicerConfig 客服配置
* @param {Object} options 选项参数
*/
openWxworkService(useOriginalService = false, servicerConfig = null, options = {}) {
const config = servicerConfig || this.getPlatformConfig();
const wxworkConfig = this.getWxworkConfig();
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
// #ifdef MP-WEIXIN
if (!useOriginalService && wxworkConfig?.enable && wxworkConfig?.contact_url) {
if (wxworkConfig?.enable && wxworkConfig?.contact_url && !useOriginalService) {
wx.navigateToMiniProgram({
appId: 'wxeb490c6f9b154ef9',
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig.contact_url)}`,
success: () => {},
success: () => console.log('跳转企业微信成功'),
fail: (err) => {
console.error('跳转企业微信失败:', err);
this.fallbackToOriginalService();
}
});
} else {
// 检查是否有企业微信配置
if (!config.wxwork_url && !config.corpid) {
console.error('企业微信配置不完整,缺少 wxwork_url 或 corpid');
uni.showToast({ title: '企业微信配置不完整', icon: 'none' });
this.fallbackToPhoneCall();
return;
}
wx.openCustomerServiceChat({
extInfo: { url: config.wxwork_url || '' },
corpId: config.corpid || '',
extInfo: { url: config.wxwork_url },
corpId: config.corpid,
showMessageCard: true,
sendMessageTitle,
sendMessagePath,
@@ -241,176 +237,224 @@ export class CustomerService {
// #endif
// #ifdef H5
if (!useOriginalService && wxworkConfig?.enable && wxworkConfig?.contact_url) {
if (wxworkConfig?.enable && wxworkConfig?.contact_url) {
window.location.href = wxworkConfig.contact_url;
} else if (config.wxwork_url) {
window.location.href = config.wxwork_url;
location.href = config.wxwork_url;
} else {
this.fallbackToPhoneCall();
}
// #endif
}
/**
* 打开第三方客服
* @param {Object} config 客服配置
*/
openThirdService(config) {
// 支持多种可能的字段名
const miniAppId = config.mini_app_id || config.miniAppId || config.appid || config.appId || config.app_id;
const miniAppPath = config.mini_app_path || config.miniAppPath || config.path || config.page_path || '';
// 优先处理第三方微信小程序客服
if (miniAppId) {
// #ifdef MP-WEIXIN
wx.navigateToMiniProgram({
appId: miniAppId,
path: miniAppPath,
success: () => {
},
fail: (err) => {
console.error('【跳转第三方小程序失败】', err);
uni.showToast({ title: '跳转失败,请稍后重试', icon: 'none' });
}
});
// #endif
// #ifdef H5
uni.showToast({ title: '第三方小程序客服仅在微信小程序中可用', icon: 'none' });
// #endif
return;
}
// 处理第三方链接客服
if (config.third_url) {
// #ifdef H5
window.location.href = config.third_url;
// #endif
// #ifdef MP-WEIXIN
uni.setClipboardData({
data: config.third_url,
success: () => {
uni.showToast({ title: '链接已复制,请在浏览器打开', icon: 'none' });
}
});
// #endif
} else {
console.error('【第三方客服配置不完整】缺少 mini_app_id 或 third_url');
this.fallbackToPhoneCall();
}
}
/**
* 打开牛商客服
* @param {Object} niushop 牛商参数
*/
openNiushopService(niushop) {
if (Object.keys(niushop).length > 0 && this.vm.$util?.redirectTo) {
if (Object.keys(niushop).length > 0) {
this.vm.$util.redirectTo('/pages_tool/chat/room', niushop);
} else {
this.makePhoneCall();
}
}
/**
* 打开微信小程序客服
* @param {Object} config 客服配置
* @param {Object} options 选项参数
*/
openWeappService(config, options = {}) {
// 如果 useOfficial 为 true 或 undefined,则使用原生系统客服(由 button open-type="contact" 触发)
// 此方法仅用于自定义跳转(如 useOfficial: false)
if (config.useOfficial !== false) {
// 不做任何事,应由 <button open-type="contact"> 触发
if (!this.shouldUseCustomService(config)) {
console.log('使用官方微信小程序客服');
return;
}
console.log('使用自定义微信小程序客服');
this.handleCustomWeappService(config, options);
}
/**
* 处理自定义微信小程序客服
* @param {Object} config 客服配置
* @param {Object} options 选项参数
*/
handleCustomWeappService(config, options = {}) {
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
if (config.customServiceUrl) {
let url = config.customServiceUrl;
const params = [];
const { sendMessageTitle, sendMessagePath, sendMessageImg } = options;
if (sendMessageTitle) params.push(`title=${encodeURIComponent(sendMessageTitle)}`);
if (sendMessagePath) params.push(`path=${encodeURIComponent(sendMessagePath)}`);
if (sendMessageImg) params.push(`img=${encodeURIComponent(sendMessageImg)}`);
if (params.length > 0) {
url += (url.includes('?') ? '&' : '?') + params.join('&');
}
uni.navigateTo({ url });
uni.navigateTo({
url: url,
fail: (err) => {
console.error('跳转自定义客服页面失败:', err);
this.tryThirdPartyService(config, options);
}
});
return;
}
this.tryThirdPartyService(config, options);
}
/**
* 尝试使用第三方客服
* @param {Object} config 客服配置
* @param {Object} options 选项参数
*/
tryThirdPartyService(config, options = {}) {
// 支持第三方微信小程序客服
if (config.thirdPartyMiniAppId || config.mini_app_id) {
// #ifdef MP-WEIXIN
wx.navigateToMiniProgram({
appId: config.thirdPartyMiniAppId || config.mini_app_id,
path: config.thirdPartyMiniAppPath || config.mini_app_path || ''
});
// #endif
return;
}
// 支持第三方链接客服
if (config.thirdPartyServiceUrl || config.third_url) {
const serviceUrl = config.thirdPartyServiceUrl || config.third_url;
if (config.thirdPartyServiceUrl) {
// #ifdef H5
window.open(serviceUrl, '_blank');
window.open(config.thirdPartyServiceUrl, '_blank');
// #endif
// #ifdef MP-WEIXIN
uni.setClipboardData({ data: serviceUrl });
uni.showToast({ title: '客服链接已复制', icon: 'none' });
if (config.thirdPartyMiniAppId) {
wx.navigateToMiniProgram({
appId: config.thirdPartyMiniAppId,
path: config.thirdPartyMiniAppPath || '',
fail: (err) => {
console.error('跳转第三方小程序失败:', err);
this.fallbackToPhoneCall();
}
});
} else {
uni.setClipboardData({
data: config.thirdPartyServiceUrl,
success: () => {
uni.showModal({
title: '客服链接已复制',
content: '客服链接已复制到剪贴板,请在浏览器中粘贴访问',
showCancel: false
});
}
});
}
// #endif
return;
}
this.fallbackToPhoneCall();
}
/**
* 降级到电话客服
*/
fallbackToPhoneCall() {
uni.showModal({
title: '联系客服',
content: '在线客服暂时不可用,是否拨打电话联系客服?',
success: (res) => {
if (res.confirm) {
this.makePhoneCall();
}
}
});
}
/**
* 打开支付宝小程序客服
* @param {Object} config 客服配置
*/
openAliappService(config) {
if (config.type === 'aikefu') {
this.openAiChatService();
} else if (config.type === 'third') {
this.openThirdService(config);
} else {
// 支付宝原生客服由 button open-type="contact" 触发,此处不处理
console.log('支付宝小程序客服', config);
switch (config.type) {
case 'aikefu':
this.openDifyService();
break;
case 'third':
this.openThirdService(config);
break;
default:
console.log('使用支付宝官方客服');
break;
}
}
// ================== 辅助方法 ==================
/**
* 拨打电话
*/
makePhoneCall() {
this.vm.$api.sendRequest({
url: '/api/site/shopcontact',
success: res => {
if (res.code === 0 && res.data?.mobile) {
uni.makePhoneCall({ phoneNumber: res.data.mobile });
uni.makePhoneCall({
phoneNumber: res.data.mobile
});
} else {
uni.showToast({ title: '暂无客服电话', icon: 'none' });
uni.showToast({
title: '暂无客服电话',
icon: 'none'
});
}
},
fail: () => {
uni.showToast({ title: '获取客服电话失败', icon: 'none' });
uni.showToast({
title: '获取客服电话失败',
icon: 'none'
});
}
});
}
/**
* 显示无客服弹窗
*/
showNoServicePopup() {
const siteInfo = this.vm.$store.state.siteInfo || {};
const message = siteInfo?.site_tel
? `请联系客服,客服电话是 ${siteInfo.site_tel}`
? `请联系客服,客服电话是${siteInfo.site_tel}`
: '抱歉,商家暂无客服,请线下联系';
uni.showModal({ title: '联系客服', content: message, showCancel: false });
}
showConfigErrorPopup(errors) {
uni.showModal({
title: '客服配置错误',
content: `配置有误:\n${errors.join('\n')}`,
title: '联系客服',
content: message,
showCancel: false
});
}
/**
* 显示配置错误弹窗
* @param {Array} errors 错误列表
*/
showConfigErrorPopup(errors) {
const message = errors.join('\n');
uni.showModal({
title: '配置错误',
content: `客服配置有误:\n${message}`,
showCancel: false
});
}
/**
* 降级处理:使用原有客服方式
*/
fallbackToOriginalService() {
uni.showModal({
title: '提示',
content: '无法直接添加企业微信,是否使用其他方式联系客服?',
content: '无法直接添加企业微信客服,是否使用其他方式联系客服?',
success: (res) => {
if (res.confirm) {
this.openWxworkService(true);
@@ -419,19 +463,9 @@ export class CustomerService {
});
}
fallbackToPhoneCall() {
uni.showModal({
title: '提示',
content: '在线客服不可用,是否拨打电话联系客服?',
success: (res) => {
if (res.confirm) this.makePhoneCall();
}
});
}
/**
* 获取按钮配置(用于 template 中 v-if / open-type 判断)
* @returns {Object}
* 获取客服按钮配置
* @returns {Object} 按钮配置
*/
getButtonConfig() {
const config = this.getPlatformConfig();
@@ -439,10 +473,11 @@ export class CustomerService {
let openType = '';
// #ifdef MP-WEIXIN
if (config.type === 'weapp' && config.useOfficial !== false) {
openType = 'contact';
if (config.type === 'weapp') {
openType = config.useOfficial !== false ? 'contact' : '';
}
// #endif
// #ifdef MP-ALIPAY
if (config.type === 'aliapp') openType = 'contact';
// #endif
@@ -451,234 +486,25 @@ export class CustomerService {
}
/**
* 获取客服按钮图标
* @returns {String} 图标URL
* 判断是否应该使用自定义客服处理
* @param {Object} config 客服配置
* @returns {boolean} 是否使用自定义客服
*/
getKefuButtonIcon() {
const shopInfo = this.vm.shopInfo || {};
const config = this.getPlatformConfig();
// 优先使用指定的智能客服头像
if (config?.type === 'aikefu' || config?.type === 'wxwork' || config?.type === 'qyweixin') {
return this.vm.$util.img(IMAGE_CONFIG.aiAvatar);
}
return shopInfo.kefuimg || this.vm.$util?.getDefaultImage()?.kefu || '';
}
/**
* 判断是否为微信官方客服
* @returns {Boolean}
*/
isWeappOfficialKefu() {
const config = this.getPlatformConfig();
return config?.type === 'weapp';
}
/**
* 判断是否为智能客服
* @returns {Boolean}
*/
isAIKefu() {
const config = this.getPlatformConfig();
return config?.type === 'aikefu';
}
/**
* 判断是否为企业微信客服
* @returns {Boolean}
*/
isWxworkKefu() {
const config = this.getPlatformConfig();
return config?.type === 'wxwork' || config?.type === 'qyweixin';
}
/**
* 判断是否为第三方客服
* @returns {Boolean}
*/
isThirdKefu() {
const config = this.getPlatformConfig();
return config?.type === 'third';
}
/**
* 判断是否需要同时显示小程序系统客服
* @returns {Boolean}
*/
shouldShowExtraWeappSystemKefu() {
const config = this.getPlatformConfig();
return (config?.show_system_service === true || config?.show_system_service === '1') && config?.type !== 'weapp';
}
/**
* 计算容器高度
* @param {Boolean} isLanguageSwitchEnabled 是否启用语言切换
* @param {Boolean} showWeappSystemKefu 是否显示小程序系统客服
* @param {Boolean} fixBtnShow 是否显示按钮
* @returns {String} 高度值(px)
*/
getContainerHeight(isLanguageSwitchEnabled, showWeappSystemKefu, fixBtnShow) {
if (!fixBtnShow) return '160px';
let buttonCount = 1;
if (isLanguageSwitchEnabled) buttonCount++;
if (showWeappSystemKefu) buttonCount++;
const totalRpx = 94 * buttonCount - 14;
const pxValue = Math.round(totalRpx * 0.5);
return `${pxValue}px`;
}
/**
* 获取未读消息数量
* @returns {Number}
*/
getUnreadCount() {
return this.vm.$store?.state?.aiUnreadCount || 0;
}
/**
* 拨打电话联系客服
* @param {String} phoneNumber 电话号码
*/
makePhoneCallByNumber(phoneNumber) {
if (phoneNumber) {
uni.makePhoneCall({ phoneNumber });
} else {
this.makePhoneCall();
}
}
/**
* 打开 AI 智能助手
*/
openAIChat() {
try {
if (typeof this.vm.setAiUnreadCount === 'function') {
this.vm.setAiUnreadCount(0);
}
const aiChatUrl = '/pages_tool/ai-chat/index';
uni.navigateTo({
url: aiChatUrl,
fail: (err) => {
console.error('跳转 AI智能客服失败:', err);
// #ifdef H5
window.location.href = aiChatUrl;
// #endif
uni.showToast({ title: '打开客服失败', icon: 'none' });
}
});
} catch (e) {
console.error('跳转 AI智能客服异常:', e);
uni.showToast({ title: '打开客服失败', icon: 'none' });
}
}
/**
* 打开客服选择对话框(预留方法)
*/
openCustomerSelectPopupDialog() {
uni.showToast({ title: '客服选择功能开发中', icon: 'none' });
}
/**
* 打开客服选择弹出层(ActionSheet)
* @param {Array} kefuList 客服列表
*/
openKefuSelectPopup(kefuList) {
const kefuNames = kefuList.map(item => item.name);
uni.showActionSheet({
itemList: kefuNames,
success: (res) => {
const selectedKefu = kefuList[res.tapIndex];
const cs = createCustomerService(this.vm, selectedKefu);
if (selectedKefu.isOfficial) {
uni.openCustomerServiceConversation({
sessionFrom: 'weapp',
showMessageCard: true
});
} else if (selectedKefu.id === 'qyweixin-kefu') {
if (uni.getSystemInfoSync().platform === 'wechat') {
uni.navigateTo({
url: '/pages_tool/qyweixin-kefu/index'
});
} else {
const qyweixinUrl = this.vm.shopInfo?.qyweixinUrl;
if (qyweixinUrl) {
window.location.href = qyweixinUrl;
} else {
uni.showToast({ title: '企业微信客服未配置', icon: 'none' });
}
}
} else {
cs.handleCustomerClick();
}
}
});
}
/**
* 核心方法:统一客服入口(带验证和配置检查)
* @param {Object} options 选项参数
*/
handleUnifiedKefuClick(options = {}) {
const validation = this.validateConfig();
if (!validation.isValid) {
console.error('客服配置无效:', validation.errors);
uni.showToast({ title: '客服暂不可用', icon: 'none' });
return;
}
if (validation.warnings.length > 0) {
console.warn('客服配置警告:', validation.warnings);
}
const platformConfig = this.getPlatformConfig();
// 检查企业微信配置
if (platformConfig.type === 'wxwork') {
const wxworkConfig = this.getWxworkConfig();
// #ifdef MP-WEIXIN
if (!wxworkConfig?.enable || !wxworkConfig?.contact_url) {
console.warn('企业微信配置不完整,使用原生客服');
uni.showToast({ title: '企业微信配置不完整', icon: 'none' });
}
// #endif
// #ifdef H5
if (!wxworkConfig?.contact_url && !platformConfig.wxwork_url) {
console.error('企业微信链接未配置');
uni.showToast({ title: '企业微信链接未配置', icon: 'none' });
return;
}
// #endif
}
// 直接调用统一处理方法,由 CustomerService 内部根据配置路由
try {
this.handleCustomerClick({
sendMessageTitle: options.sendMessageTitle || '来自悬浮按钮的咨询',
sendMessagePath: options.sendMessagePath || '/pages/index/index'
});
} catch (error) {
console.error('客服处理失败:', error);
uni.showToast({ title: '打开客服失败', icon: 'none' });
shouldUseCustomService(config) {
// #ifdef MP-WEIXIN
if (config?.type === 'weapp') {
return config.useOfficial === false;
}
// #endif
return true;
}
}
/**
* 创建客服服务实例
* @param {Object} vueInstance Vue 实例(通常是 this)
* @param {Object} externalConfig 可选:外部传入的最新配置(如从 DIY 数据中提取)
* @returns {CustomerService}
* @param {Object} vueInstance Vue实例
* @param {Object} externalConfig 外部最新配置
* @returns {CustomerService} 客服服务实例
*/
export function createCustomerService(vueInstance, externalConfig = null) {
return new CustomerService(vueInstance, externalConfig);

View File

@@ -1,9 +1,7 @@
import WxMap from 'common/js/map-wx-jssdk.js';
import Config from '@/common/js/config.js';
import util from '@/common/js/util.js';
let systemInfo = util.getDeviceInfo();
let systemInfo = uni.getSystemInfoSync();
export default {
data() {
return {
@@ -200,6 +198,7 @@ export default {
},
methods: {
play(){
console.log(123)
},
async init() {
@@ -608,10 +607,10 @@ export default {
},
// 分享给好友
onShareAppMessage() {
return this.mpShareData?.appMessage;
return this.mpShareData.appMessage;
},
// 分享到朋友圈
onShareTimeline() {
return this.mpShareData?.timeLine;
return this.mpShareData.timeLine;
}
}

View File

@@ -7,7 +7,7 @@ export default {
computed: {
// 是否是英文环境
isEnEnv() {
return this.$langConfig.getCurrentLocale() === 'en-us';
return uni.getStorageSync('lang') === 'en-us';
},
themeStyle() {
return this.$store.state.themeStyle;
@@ -65,18 +65,10 @@ export default {
componentRefresh() {
return this.$store.state.componentRefresh;
},
// AI客服配置
globalAIKefuConfig() {
return this.$store.state.globalAIKefuConfig;
},
// 客服配置
servicerConfig() {
return this.$store.state.servicerConfig;
},
// 企业微信配置
wxworkConfig() {
return this.$store.state.wxworkConfig;
},
diySeckillInterval() {
return this.$store.state.diySeckillInterval;
},
@@ -153,7 +145,7 @@ export default {
if (isJump && route != 'pages/index/index') {
uni.setStorageSync('manual_change_store', true); // 手动切换门店
this.$store.dispatch('getCartNumber'); //重新获取购物车数据
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
this.$util.redirectTo('/pages/index/index');
}
}
},

View File

@@ -164,6 +164,7 @@ export default {
// 商品详情
if (this.goodsSkuDetail.goods_content) this.goodsSkuDetail.goods_content = (this.goodsSkuDetail.goods_content);
console.log(this.goodsSkuDetail.goods_content)
// if (this.goodsSkuDetail.goods_content) this.goodsSkuDetail.goods_content = htmlParser(this.goodsSkuDetail.goods_content);
//商品服务
@@ -239,7 +240,7 @@ export default {
},
goHome() {
if (this.preview) return; // 开启预览,禁止任何操作和跳转
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
this.$util.redirectTo('/pages/index/index');
},
goCart() {
if (this.preview) return; // 开启预览,禁止任何操作和跳转

View File

@@ -316,9 +316,11 @@ function replaceVideo(html){
let rep = `<video style="width:100% !important;display:block;max-width: ${screenWidth} !important;"`;
var html = html.replace(/\\/g, '').replace(/<video/g, rep);
console.log(html)
html = html.replace(/<video [^>]*src=['"]([^'"]+)[^>]*>/gi, (match, capture) => {
return rep + ' src="' + util.img(capture) + '"/>';
});
// console.log(html)
return html;
}

View File

@@ -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;

View File

@@ -1,8 +1,8 @@
import { langConfig } from './config-external.js';
var locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
// 缓存已加载的语言包
const loadedLangPacks = {};
var loadedLangPacks = {};
// 处理页面目录映射
function processRoutePath(route) {
@@ -30,12 +30,12 @@ function processRoutePath(route) {
}
}
// ---- 处理页面目录映射 <end>----
// 去掉pages目录,只保留子目录
if (routeParts[0] === 'pages') {
routeParts = routeParts.slice(1);
}
}
return routeParts.join("/");
}
@@ -54,44 +54,26 @@ function loadLangPackSync(lang, path) {
}
}
/**
* 获得当前本地语言
* @returns
*/
function getCurrentLocale() {
return uni.getStorageSync('lang') || "zh-cn";
}
export default {
langList: langConfig.langList,
/**
* 获得当前本地语言
* @returns
*/
getCurrentLocale,
/**
* * 解析多语言
* @param {Object} field
*/
lang(field) {
let _page = getCurrentPages()[getCurrentPages().length - 1];
if (!_page) return;
const locale = getCurrentLocale(); // 获得当前本地语言
let value = ''; // 存放解析后的语言值
let langPath = ''; // 存放当前页面语言包路径
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
var value = '';
try {
//公共语言包(同步加载)
var lang = loadLangPackSync(locale, 'common');
//当前页面语言包(同步加载)
let route = _page.route;
langPath = processRoutePath(route);
let route = _this.route;
let langPath = processRoutePath(route);
// console.log(`当前页面语言包路径: ${langPath}`);
// 加载当前页面语言包
let currentPageLang = loadLangPackSync(locale, langPath);
@@ -116,9 +98,9 @@ export default {
} else {
value = mergedLang[field] !== undefined ? mergedLang[field] : field;
}
} catch (e) {
console.error('解析语言包失败:', e, { langPath, field, locale });
console.error('解析语言包失败:', e);
value = field;
}
@@ -131,10 +113,7 @@ export default {
if (value == undefined || (value == 'title' && field == 'title')) value = ''; // field
// 多语言调试,注释后可以关闭控制台输出
if (field == value) {
console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
}
// console.log(`字段: ${field}, 值: ${value}`)
return value;
},
/**
@@ -143,18 +122,14 @@ export default {
* @param {String} url 切换后跳转的页面url
*/
change(value, url = '/pages_tool/member/index') {
let _page = getCurrentPages()[getCurrentPages().length - 1];
if (!_page) return;
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
uni.setStorageSync("lang", value);
const locale = getCurrentLocale();
locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
// 清空已加载的语言包缓存
for (let key in loadedLangPacks) {
if (!key.startsWith(locale)) {
delete loadedLangPacks[key];
}
}
loadedLangPacks = {};
this.refresh();
@@ -164,11 +139,10 @@ export default {
},
//刷新标题、tabbar
refresh() {
let _page = getCurrentPages()[getCurrentPages().length - 1];
if (!_page) return;
const locale = getCurrentLocale();
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
this.title(this.lang("title"));
//设置tabbar的文字语言

View File

@@ -1,4 +1,3 @@
import util from '@/common/js/util.js'
import TransformCoordinate from './transformCoordinate.js'
function openMapByDefault(latitude, longitude, name) {
@@ -86,16 +85,18 @@ export default {
openMap(latitude, longitude, name, coord_type = 'gcj02') {
let arr = getCoordByType(longitude, latitude, coord_type)
// #ifdef APP-PLUS
let platform = util.getDeviceInfo().platform;
switch (platform) {
switch (uni.getSystemInfoSync().platform) {
case 'android':
console.log('运行Android上')
openMapByAndroid(arr[1], arr[0], name)
break;
case 'ios':
console.log('运行iOS上')
openMapByIos(arr[1], arr[0], name)
break;
default:
openMapByDefault(arr[1], arr[0], name)
console.log('运行在开发者工具上')
break;
}
// #endif

View File

@@ -1,5 +1,4 @@
import { EventSafety } from '@/common/js/event-safety.js'
import util from '@/common/js/util.js'
import { EventSafety } from './event-safety'
export class NavigationHelper {
constructor() {
@@ -43,6 +42,7 @@ export class NavigationHelper {
query.select('.uni-page-head').boundingClientRect((rect) => {
if (rect && rect.height > 0) {
console.log('直接查询导航栏高度成功:', rect.height)
resolve(rect.height)
} else {
console.warn('未找到 uni-page-head 元素或高度为0')
@@ -59,10 +59,11 @@ export class NavigationHelper {
// 微信小程序精确计算
try {
const menuButtonInfo = wx.getMenuButtonBoundingClientRect()
let systemInfo = util.getDeviceInfo();
const systemInfo = uni.getSystemInfoSync()
const height = menuButtonInfo.bottom +
(menuButtonInfo.top - systemInfo.statusBarHeight)
console.log('微信小程序导航栏高度:', height)
resolve(height)
} catch (error) {
console.error('微信小程序高度计算失败:', error)
@@ -118,7 +119,7 @@ export class NavigationHelper {
// 获取状态栏高度
getStatusBarHeight() {
// #ifdef MP-WEIXIN
let systemInfo = util.getDeviceInfo();
const systemInfo = uni.getSystemInfoSync()
return systemInfo.statusBarHeight || 20
// #endif
// #ifdef H5
@@ -137,7 +138,7 @@ export class NavigationHelper {
// 获取安全区域
getSafeAreaInsets() {
try {
let systemInfo = util.getDeviceInfo();
const systemInfo = uni.getSystemInfoSync()
return systemInfo.safeArea || {
top: 0,
bottom: 0,
@@ -172,6 +173,7 @@ export class NavigationHelper {
// 处理服务请求
async handleServiceRequest(event, component) {
console.log('处理导航相关服务请求:', event.type)
// 安全检查事件目标
if (this.shouldProcessNavigationRequest(event)) {
@@ -275,6 +277,7 @@ export class NavigationHelper {
// 清理缓存
clearCache() {
this.navigationCache.clear()
console.log('导航缓存已清理')
}
}

View File

@@ -1,100 +0,0 @@
// 文件分享工具函数
export default {
/**
* 生成文件预览链接
* @param {Object} file - 文件对象,包含 name 和 url 属性
* @returns {string} - 生成的文件预览链接
*/
generateFilePreviewUrl(file) {
// 推断文件类型
let fileType = '';
if (file.name) {
const ext = file.name.split('.').pop().toLowerCase();
if (['pdf'].includes(ext)) {
fileType = 'pdf';
} else if (['doc', 'docx'].includes(ext)) {
fileType = 'word';
} else if (['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'].includes(ext)) {
fileType = 'video';
}
}
// 构建文件预览链接
const previewUrl = `/pages_tool/file-preview/file-preview?fileName=${encodeURIComponent(file.name)}&fileUrl=${encodeURIComponent(file.url || '')}&fileType=${encodeURIComponent(fileType)}`;
return previewUrl;
},
/**
* 分享文件
* @param {Object} file - 文件对象,包含 name 和 url 属性
* @param {string} title - 分享标题,默认使用文件名
* @param {string} desc - 分享描述,默认使用固定文案
*/
shareFile(file, title = file.name, desc = '查看企业文件:' + file.name) {
// 生成文件预览链接
const filePreviewUrl = this.generateFilePreviewUrl(file);
// #ifdef H5
// H5 平台分享
if (navigator.share) {
// 使用 Web Share API
navigator.share({
title: title,
text: desc,
url: filePreviewUrl
}).catch(err => {
console.error('分享失败:', err);
uni.showToast({ title: '分享失败', icon: 'none' });
});
} else {
// 不支持 Web Share API 的浏览器
uni.setClipboardData({
data: filePreviewUrl,
success: () => {
uni.showToast({ title: '链接已复制,请粘贴分享', icon: 'success' });
},
fail: () => {
uni.showToast({ title: '复制失败', icon: 'none' });
}
});
}
// #endif
// #ifdef MP-WEIXIN
// 微信小程序分享
uni.showActionSheet({
itemList: ['发送给朋友', '分享到朋友圈'],
success: (res) => {
if (res.tapIndex === 0) {
// 发送给朋友
uni.shareAppMessage({
title: title,
path: filePreviewUrl,
success: () => {
uni.showToast({ title: '分享成功', icon: 'success' });
},
fail: () => {
uni.showToast({ title: '分享失败', icon: 'none' });
}
});
} else if (res.tapIndex === 1) {
// 分享到朋友圈
uni.shareTimeline({
title: desc,
path: filePreviewUrl,
success: () => {
uni.showToast({ title: '分享成功', icon: 'success' });
},
fail: () => {
uni.showToast({ title: '分享失败', icon: 'none' });
}
});
}
},
fail: () => {
// 用户取消分享
}
});
// #endif
}
};

View File

@@ -21,35 +21,53 @@ export default {
methods: {
// 判断是否已连接
checkOpenSocket() {
console.log('判断是否已连接');
// alert('判断是否已连接')
let self = this;
uni.sendSocketMessage({
data: 'ping',
success: (res) => {
console.log('连接成功,检查');
// alert('连接成功,检查')
// self.getChatList();
},
fail: (err) => { // 未连接打开websocket连接
console.log('连接失败');
// alert('连接失败')
self.openConnection();
}
});
},
openConnection() { // 打开连接
console.log('打开连接');
// alert('打开连接')
// uni.closeSocket(); // 确保已经关闭后再重新打开
uni.connectSocket({
url: config.webSocket,
method: 'POST',
success(res) {
console.log('连接成功 connectSocket=', res);
// alert('连接成功 connectSocket=', res);
},
fail(err) {
console.log('连接失败 connectSocket=', err);
}
});
// uni.onSocketOpen((res) => {
// console.log('连接成功', res);
// });
this.onSocketMessage(); // 打开成功监听服务器返回的消息
},
// 打开成功监听服务器返回的消息
onSocketMessage() { // 消息
console.log("开始监听");
let that = this;
this.pingInterval = config.pingInterval;
this.timeoutObj = null;
uni.onSocketMessage((res) => { //type:init,connect,close,string,order,goods
let msg = JSON.parse(res.data);
console.log("监听该服务器消息", res);
if (msg.type == 'close') {
clearInterval(that.timeoutObj);
that.timeoutObj = null;
@@ -123,18 +141,22 @@ export default {
},
// 检测心跳reset
reset() {
console.log("检测心跳");
clearInterval(this.timeoutObj);
this.start(); // 启动心跳
},
// 启动心跳 start
start() {
console.log("启动心跳");
let self = this;
this.timeoutObj = setInterval(function () {
uni.sendSocketMessage({
data: 'ping',
success: (res) => {
console.log('连接中....');
},
fail: (err) => {
console.log('连接失败重新连接....');
self.openConnection();
}
});

View File

@@ -1,460 +1,419 @@
/**
* 颜色配置
* 包含默认颜色和其他颜色
* 特别注意:
* 1. 分组不会被计算成Key,分组下的属性会被计算成Key
* 2. 分组下的属性如果有相同的Key,会被覆盖
* 3. 例如:hoverNav,hoverNav_bg_color和hoverNav_text_color, 不会生成hoverNav_hoverNav_bg_color和hoverNav_hoverNav_text_color
* 问题原因:历史遗留
*/
export default {
'default': {
//红色
name: 'default',
main_color: '#F4391c',
aux_color: '#F7B500',
bg_color: '#FF4646',//主题背景
bg_color_shallow: '#FF4646',//主题背景渐变浅色
promotion_color: '#FF4646',//活动背景
promotion_aux_color: '#F7B500',//活动背景辅色
main_color_shallow: '#FFF4F4',//淡背景
price_color: 'rgb(252,82,39)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
...{
goods_price: 'rgb(252,82,39,1)',//价格
promotion_tag: '#FF4646',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#FF4646',//按钮颜色
goods_btn_color_shallow: '#F7B500',//副按钮颜色
},
...{
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
...{
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
...{
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
...{
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
...{
hover_nav_bg_color: '#FFFC', //背景色: 红色 '#c6251b', 白色: '#FFFC'
hover_nav_text_color: '#000' // 文字颜色: 白色 '#FFFFFF', 黑色: '#000'
},
},
'green': {
name: 'green',
main_color: '#19C650',
aux_color: '#FA6400',
bg_color: '#19C650',
bg_color_shallow: '#19C650',
promotion_color: '#19C650',
promotion_aux_color: '#FA6400',
main_color_shallow: '#F0FFF5',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
...{
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#19C650',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#19C650',//按钮颜色
goods_btn_color_shallow: '#FA6400',//副按钮颜色
},
...{
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
...{
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
...{
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
...{
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
...{
hover_nav_bg_color: '#19C650',//背景色
hover_nav_text_color: '#FFFFFF'
},
},
'blue': {
name: 'blue',
main_color: '#36ABFF',
aux_color: '#FA6400',
bg_color: '#36ABFF',
bg_color_shallow: '#36ABFF',
promotion_color: '#36ABFF ',
promotion_aux_color: '#FA6400',
main_color_shallow: '#E2F3FF',
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
...{
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#36ABFF',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#36ABFF',//按钮颜色
goods_btn_color_shallow: '#FA6400',//副按钮颜色
},
...{
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
...{
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
...{
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
...{
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
...{
hover_nav_bg_color: '#36ABFF',//背景色
hover_nav_text_color: '#FFFFFF'
},
},
'pink': {
name: 'pink',
main_color: '#FF407E',
aux_color: '#F7B500',
bg_color: '#FF407E',//主题背景
bg_color_shallow: '#FF407E',//主题背景渐变浅色
promotion_color: '#FF407E',//活动背景
promotion_aux_color: '#F7B500',//活动背景辅色
main_color_shallow: '#FFF5F8',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
...{
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#FF407E',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#FF407E',//按钮颜色
goods_btn_color_shallow: '#F7B500',//副按钮颜色
},
...{
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
...{
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
...{
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
...{
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
...{
hover_nav_bg_color: '#FF407E',//背景色
hover_nav_text_color: '#FFFFFF'
},
},
'gold': {
name: 'gold',
main_color: '#CFAF70',
aux_color: '#444444',
bg_color: '#CFAF70',//主题背景
bg_color_shallow: '#CFAF70',//主题背景渐变浅色
promotion_color: '#CFAF70',//活动背景
promotion_aux_color: '#444444',//活动背景辅色
main_color_shallow: '#FFFAF1',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
...{
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#CFAF70',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#CFAF70',//按钮颜色
goods_btn_color_shallow: '#444444',//副按钮颜色
},
...{
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
...{
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
...{
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
...{
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
...{
hover_nav_bg_color: '#CFAF70',//背景色
hover_nav_text_color: '#FFFFFF'
},
},
'purple': {
name: 'purple',
main_color: '#A253FF',
aux_color: '#222222',
bg_color: '#A253FF',//主题背景
bg_color_shallow: '#A253FF',//主题背景渐变浅色
promotion_color: '#A253FF',//活动背景
promotion_aux_color: '#222222',//活动背景辅色
main_color_shallow: '#F8F3FF',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
...{
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#A253FF',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#A253FF',//按钮颜色
goods_btn_color_shallow: '#222222',//副按钮颜色
},
...{
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
...{
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
...{
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
...{
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
...{
hover_nav_bg_color: '#A253FF',//背景色
hover_nav_text_color: '#FFFFFF'
},
},
'yellow': {
name: 'yellow',
main_color: '#FFD009',
aux_color: '#1D262E',
bg_color: '#FFD009',//主题背景
bg_color_shallow: '#FFD009',//主题背景渐变浅色
promotion_color: '#FFD009',//活动背景
promotion_aux_color: '#1D262E',//活动背景辅色
main_color_shallow: '#FFFBEF',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#303133',//按钮文字颜色
...{
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#FFD009',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#FFD009',//按钮颜色
goods_btn_color_shallow: '#1D262E',//副按钮颜色
},
...{
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
...{
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
...{
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
...{
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
...{
hover_nav_bg_color: '#FFD009',//背景色
hover_nav_text_color: '#303133'
},
},
'black': {
name: 'black',
main_color: '#222222',
aux_color: '#FFFFFF',
bg_color: '#222222',//主题背景
bg_color_shallow: '#333333',//主题背景渐变浅色
promotion_color: '#222222',//活动背景
promotion_aux_color: '#FA8B00',//活动背景辅色
main_color_shallow: '#efefef',//淡背景
price_color: 'rgba(255,0,0,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
...{
goods_price: 'rgba(255,0,0,1)',//价格
promotion_tag: '#222222',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#222222',
goods_cart_num_corner: '#FF0000',//购物车数量角标
goods_btn_color: '#222222',//按钮颜色
goods_btn_color_shallow: '#FA8B00',//副按钮颜色
},
...{
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
...{
super_member_start_bg: '#fadcb5',
super_member_end_bg: '#f6bd74',
super_member_start_text_color: '#ab6126',
super_member_end_text_color: '#d19336',
},
...{
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
...{
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
...{
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
...{
hover_nav_bg_color: '#222222',//背景色
hover_nav_text_color: '#FFFFFF'
},
}
}
export default {
'default': {
//红色
name: 'default',
main_color: '#F4391c',
aux_color: '#F7B500',
bg_color: '#FF4646',//主题背景
bg_color_shallow: '#FF4646',//主题背景渐变浅色
promotion_color: '#FF4646',//活动背景
promotion_aux_color: '#F7B500',//活动背景辅色
main_color_shallow: '#FFF4F4',//淡背景
price_color: 'rgb(252,82,39)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
goods_detail: {
goods_price: 'rgb(252,82,39,1)',//价格
promotion_tag: '#FF4646',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#FF4646',//按钮颜色
goods_btn_color_shallow: '#F7B500',//副按钮颜色
},
pintuan: {
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
super_member: {
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
bargain: {
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
seckill: {
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
giftcard: {
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
groupby: {
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
},
'green': {
name: 'green',
main_color: '#19C650',
aux_color: '#FA6400',
bg_color: '#19C650',
bg_color_shallow: '#19C650',
promotion_color: '#19C650',
promotion_aux_color: '#FA6400',
main_color_shallow: '#F0FFF5',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
goods_detail: {
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#19C650',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#19C650',//按钮颜色
goods_btn_color_shallow: '#FA6400',//副按钮颜色
},
pintuan: {
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
super_member: {
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
bargain: {
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
seckill: {
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
giftcard: {
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
groupby: {
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
},
'blue': {
name: 'blue',
main_color: '#36ABFF',
aux_color: '#FA6400',
bg_color: '#36ABFF',
bg_color_shallow: '#36ABFF',
promotion_color: '#36ABFF ',
promotion_aux_color: '#FA6400',
main_color_shallow: '#E2F3FF',
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
goods_detail: {
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#36ABFF',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#36ABFF',//按钮颜色
goods_btn_color_shallow: '#FA6400',//副按钮颜色
},
pintuan: {
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
super_member: {
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
bargain: {
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
seckill: {
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
giftcard: {
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
groupby: {
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
},
'pink': {
name: 'pink',
main_color: '#FF407E',
aux_color: '#F7B500',
bg_color: '#FF407E',//主题背景
bg_color_shallow: '#FF407E',//主题背景渐变浅色
promotion_color: '#FF407E',//活动背景
promotion_aux_color: '#F7B500',//活动背景辅色
main_color_shallow: '#FFF5F8',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
goods_detail: {
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#FF407E',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#FF407E',//按钮颜色
goods_btn_color_shallow: '#F7B500',//副按钮颜色
},
pintuan: {
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
super_member: {
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
bargain: {
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
seckill: {
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
giftcard: {
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
groupby: {
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
},
'gold': {
name: 'gold',
main_color: '#CFAF70',
aux_color: '#444444',
bg_color: '#CFAF70',//主题背景
bg_color_shallow: '#CFAF70',//主题背景渐变浅色
promotion_color: '#CFAF70',//活动背景
promotion_aux_color: '#444444',//活动背景辅色
main_color_shallow: '#FFFAF1',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
goods_detail: {
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#CFAF70',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#CFAF70',//按钮颜色
goods_btn_color_shallow: '#444444',//副按钮颜色
},
pintuan: {
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
super_member: {
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
bargain: {
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
seckill: {
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
giftcard: {
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
groupby: {
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
},
'purple': {
name: 'purple',
main_color: '#A253FF',
aux_color: '#222222',
bg_color: '#A253FF',//主题背景
bg_color_shallow: '#A253FF',//主题背景渐变浅色
promotion_color: '#A253FF',//活动背景
promotion_aux_color: '#222222',//活动背景辅色
main_color_shallow: '#F8F3FF',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
goods_detail: {
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#A253FF',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#A253FF',//按钮颜色
goods_btn_color_shallow: '#222222',//副按钮颜色
},
pintuan: {
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
super_member: {
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
bargain: {
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
seckill: {
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
giftcard: {
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
groupby: {
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
},
'yellow': {
name: 'yellow',
main_color: '#FFD009',
aux_color: '#1D262E',
bg_color: '#FFD009',//主题背景
bg_color_shallow: '#FFD009',//主题背景渐变浅色
promotion_color: '#FFD009',//活动背景
promotion_aux_color: '#1D262E',//活动背景辅色
main_color_shallow: '#FFFBEF',//淡背景
price_color: 'rgba(252,82,39,1)',//价格颜色
btn_text_color: '#303133',//按钮文字颜色
goods_detail: {
goods_price: 'rgba(252,82,39,1)',//价格
promotion_tag: '#FFD009',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#FC5227',
goods_cart_num_corner: '#FC5227',//购物车数量角标
goods_btn_color: '#FFD009',//按钮颜色
goods_btn_color_shallow: '#1D262E',//副按钮颜色
},
pintuan: {
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
super_member: {
super_member_start_bg: '#7c7878',
super_member_end_bg: '#201a18',
super_member_start_text_color: '#FFDBA6',
super_member_end_text_color: '#FFEBCA',
},
bargain: {
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
seckill: {
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
giftcard: {
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
groupby: {
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
},
'black': {
name: 'black',
main_color: '#222222',
aux_color: '#FFFFFF',
bg_color: '#222222',//主题背景
bg_color_shallow: '#333333',//主题背景渐变浅色
promotion_color: '#222222',//活动背景
promotion_aux_color: '#FA8B00',//活动背景辅色
main_color_shallow: '#efefef',//淡背景
price_color: 'rgba(255,0,0,1)',//价格颜色
btn_text_color: '#FFFFFF',//按钮文字颜色
goods_detail: {
goods_price: 'rgba(255,0,0,1)',//价格
promotion_tag: '#222222',
goods_card_bg: '#201A18',//会员卡背景
goods_card_bg_shallow: '#7C7878',//会员卡背景浅色
goods_card_color: '#FFD792',
goods_coupon: '#222222',
goods_cart_num_corner: '#FF0000',//购物车数量角标
goods_btn_color: '#222222',//按钮颜色
goods_btn_color_shallow: '#FA8B00',//副按钮颜色
},
pintuan: {
pintuan_label_bg: '#F7B500',
pintuan_label_color: '#FFFFFF',
pintuan_color: '#FA6400',
pintuan_promotion_color: '#FA3A1D',//活动背景
pintuan_promotion_aux_color: '#FD9A01',//活动背景辅色
},
super_member: {
super_member_start_bg: '#fadcb5',
super_member_end_bg: '#f6bd74',
super_member_start_text_color: '#ab6126',
super_member_end_text_color: '#d19336',
},
bargain: {
bargain_promotion_color: '#F0353E',//活动背景
bargain_promotion_aux_color: '#FD9A01',//活动辅色
},
seckill: {
seckill_promotion_color: '#F83530',//活动背景
seckill_promotion_aux_color: '#FD9A01',//活动辅色
},
giftcard: {
giftcard_promotion_color: '#FF3369',//活动背景
giftcard_promotion_aux_color: '#F7B500',//活动辅色
},
groupby: {
groupby_promotion_color: '#E64136',//活动背景
groupby_promotion_aux_color: '#F7B500',//活动辅色
},
}
}

View File

@@ -1,147 +0,0 @@
/**
* 将常用的Uniapp提供的函数,存放到这里,按需引用
*/
/**
* 显示错误信息
* @param {Exception} err
* @param {Boolean} useModal
*/
const showError = (err, useModal = false) => {
const content = err?.message || err?.errMsg || err?.toString();
if (!useModal) {
uni.showToast({
title: content,
icon: 'none',
duration: 3000
});
} else {
uni.showModal({
title: '错误提示',
content,
showCancel: false,
})
}
}
/**
* 打电话
* @param {string} mobile 电话号码
*/
export const makePhoneCall = (mobile) => {
try {
uni.makePhoneCall({
phoneNumber: `${mobile}`,
success(e) {
}
});
} catch (err) {
showError(err);
}
}
/**
* 拷贝文本(返回 Promise)
* @param {*} text
* @param {*} options
* @returns {Promise} 返回 Promise,成功时 resolve,失败时 reject
*/
export const copyTextAsync = (text, { copySuccess = '', copyFailed = '' } = {}) => {
return new Promise((resolve, reject) => {
// 输入验证
if (!text && text !== '') {
const error = new Error('复制文本不能为空');
showError(error);
reject(error);
return;
}
// 超时监测
const timeoutId = setTimeout(() => {
let error = new Error('复制操作长时间无响应,请检查相关权限及配置是否正确');
// #ifdef MP-WEIXIN
error = new Error([
'复制操作长时间无响应!',
'原因:',
'1.微信平台->用户隐私保护指引->"剪贴板"功能未添加或审核未通过;',
'2.微信平台对剪贴板API调用频率有限制'
].join('\r\n'));
// #endif
showError(error, true);
reject(error);
}, 5000);
try {
uni.setClipboardData({
data: `${text}`,
success: (res) => {
clearTimeout(timeoutId);
try {
if (copySuccess) {
uni.showToast({
title: copySuccess,
icon: 'success',
duration: 2000
});
}
} catch (e) {
showError(e);
}
resolve(res);
},
fail: (err) => {
clearTimeout(timeoutId);
try {
uni.showToast({
title: err.message || err.errMsg || copyFailed || '复制失败',
icon: 'none',
duration: 2000
});
} catch (e) {
showError(e);
}
reject(err);
}
});
} catch (err) {
clearTimeout(timeoutId);
showError(err);
reject(err);
}
});
}
/**
* 拷贝文本(回调形式,兼容旧代码)
* @param {*} text
* @param {*} options
* @param {Function} callback 回调函数,接收 (success, error) 参数
*/
export const copyText = (text, options = {}, callback) => {
copyTextAsync(text, options)
.then(res => {
if (callback) callback(true, null);
})
.catch(err => {
if (callback) callback(false, err);
});
}
/**
* 打开定位
* @param {Object} options
*/
export const openLocation = ({ latitude, longitude, name } = {}) => {
try {
uni.openLocation({
latitude,
longitude,
name,
});
} catch (err) {
showError(err);
}
}

View File

@@ -7,20 +7,15 @@ import {
// 关于页面路径,使用常量导出
// 首页路径
export const INDEX_PAGE_URL = '/pages/index/index';
export const CATEGORY_PAGE_URL = '/pages_goods/category';
export const CONTACT_PAGE_URL = '/pages_tool/contact/contact';
export const MEMBER_PAGE_URL = '/pages_tool/member/index';
export const LOGIN_PAGE_URL = '/pages_tool/login/login';
export const AI_CHAT_PAGE_URL = '/pages_tool/ai-chat/index';
// 当前最新的tabBar.list (参见pages.json 中的tabBar.list 配置)
export const systemTabBarList = [
INDEX_PAGE_URL,
CATEGORY_PAGE_URL,
CONTACT_PAGE_URL,
MEMBER_PAGE_URL
'/pages_goods/category',
'/pages_tool/contact/contact',
'/pages_tool/member/index'
];
/**
@@ -37,28 +32,10 @@ export const adaptSubpackageUrl = (url) => {
*/
// 定义前缀映射表
const urlPrefixMap = {
'/pages/promotion/': '/pages_promotion/',
'/pages/order/': '/pages_order/',
'/pages/goods/': '/pages_goods/',
'/pages/contact/': '/pages_tool/contact/',
'/pages/member/': '/pages_tool/member/',
'/pages/login/': '/pages_tool/login/',
'/pages/agreement/': '/pages_tool/agreement/',
'/pages/article/': '/pages_tool/article/',
'/pages/cases/': '/pages_tool/cases/',
'/pages/contact/': '/pages_tool/contact/',
'/pages/files/': '/pages_tool/files/',
'/pages/form/': '/pages_tool/form/',
'/pages/help/': '/pages_tool/help/',
'/pages/notice/': '/pages_tool/notice/',
'/pages/pay/': '/pages_tool/pay/',
'/pages/recharge/': '/pages_tool/recharge/',
'/pages/seal/': '/pages_tool/seal/',
'/pages/storeclose/': '/pages_tool/storeclose/',
'/pages/vr/': '/pages_tool/vr/',
'/pages/weapp/': '/pages_tool/weapp/',
'/pages/webview/': '/pages_tool/webview/',
'/pages/vr': '/pages_tool/vr/'
};
// 构建正则表达式
@@ -84,55 +61,20 @@ export const adaptSubpackageUrl = (url) => {
return replacePrefix(url);
}
/**
* 检查tabBar是否激活
* @param {string} linkUrl 链接路径 /pages/goods/category
* @param {string} currentPageRoute 当前页面路径 /pages_goods/category
* @returns {boolean} 是否激活
*/
export const checkTabBarActive = (linkUrl, currentPageRoute) => {
const linkUrlParts = adaptSubpackageUrl(linkUrl).split('/');
const currentPageRouteParts = currentPageRoute.split('/');
// console.log('diy-bottom-nav verify:', { linkUrlParts, currentPageRouteParts});
try {
// 二级页面
if (linkUrlParts[2] === currentPageRouteParts[2]) {
return true;
}
// 一级页面,限定只能是goods相关
if (linkUrlParts[1] === currentPageRouteParts[1] && linkUrlParts[1] === 'pages_goods') {
return true;
}
} catch (error) {
console.error('diy-bottom-nav verify error:', error);
}
return false;
}
export default {
/** 导出页面URL常量 */
MEMBER_PAGE_URL,
CATEGORY_PAGE_URL,
CONTACT_PAGE_URL,
INDEX_PAGE_URL,
LOGIN_PAGE_URL,
AI_CHAT_PAGE_URL,
/**
* 页面跳转
* @param {string} to 跳转链接 /pages/idnex/index
* @param {Object} param 参数 {key : value, ...}, 默认{}
* @param {string} mode 模式 navigateTo、redirectTo、reLaunch、tabbar, 默认navigateTo
* @param {Object} param 参数 {key : value, ...}
* @param {string} mode 模式
*/
redirectTo(to, param = {}, mode = 'navigateTo') {
redirectTo(to, param, mode) {
let url = to;
// 替换url中的前缀
console.log('redirectTo', to, param, mode);
url = adaptSubpackageUrl(url);
console.log('adaptSubpackageUrl', url);
if (param != undefined) {
Object.keys(param).forEach(function (key) {
@@ -149,7 +91,7 @@ export default {
const tabBarUrl = systemTabBarList[i];
if (url.indexOf(tabBarUrl) == 0) {
// 首页特殊处理,采用switchTab, 其他页面采用redirectTo, 不能返回,不能退回
(tabBarUrl == INDEX_PAGE_URL ? uni.switchTab : uni.redirectTo)({ url });
(tabBarUrl == INDEX_PAGE_URL ? uni.switchTab : uni.redirectTo)({url});
return;
}
}
@@ -157,25 +99,26 @@ export default {
// 如果url不包含tabBarList中的路径,根据mode判断跳转方式
switch (mode) {
case 'tabbar':
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。重置页面栈,仅保留 tabBar 页面
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
uni.switchTab({
url
});
break;
case 'redirectTo':
// 关闭当前页面,跳转到应用内的某个页面。替换栈顶页面,长度不变(上限10层)
// 关闭当前页面,跳转到应用内的某个页面。
uni.redirectTo({
url
});
break;
case 'reLaunch':
// 关闭所有页面,打开到应用内的某个页面。清空栈后打开新页面,长度=1
// 关闭所有页面,打开到应用内的某个页面。
uni.reLaunch({
url
});
break;
default:
// 保留当前页面,跳转到应用内的某个页面,新增页面到栈顶,长度+1(上限10层)
// 保留当前页面,跳转到应用内的某个页面
console.log('保留当前页面,跳转到应用内的某个页面', url);
uni.navigateTo({
url
});
@@ -187,6 +130,8 @@ export default {
* @param {Object} params 参数,针对商品、相册里面的图片区分大中小,size: big、mid、small
*/
img(img_path, params) {
var path = "";
if (img_path != undefined && img_path != "") {
if (img_path.split(',').length > 1) {
@@ -210,8 +155,6 @@ export default {
// console.log(img_path)
path = img_path;
}
// 修复:去除 URL 中的双斜杠,避免微信 downloadFile 域名匹配失败
path = path.replace(/([^:]\/)\/+/g, "$1");
}
// path += '?t=' + parseInt(new Date().getTime() / 1000);
@@ -548,7 +491,7 @@ export default {
* 检测苹果X以上的手机
*/
isIPhoneX() {
let res = this.getDeviceInfo();
let res = uni.getSystemInfoSync();
if (res.model.search('iPhone X') != -1) {
return true;
}
@@ -556,33 +499,13 @@ export default {
},
//判断安卓还是iOS
isAndroid() {
let platform = this.getDeviceInfo().platform;
let platform = uni.getSystemInfoSync().platform
if (platform == 'ios') {
return false;
} else if (platform == 'android') {
return true;
}
},
/**
* 获取设备信息(包含降级处理)
*/
getDeviceInfo() {
try {
return uni.getDeviceInfo();
} catch (e) {
return uni.getSystemInfoSync();
}
},
/**
* 获取窗口信息(包含降级处理)
*/
getWindowInfo() {
try {
return uni.getWindowInfo();
} catch (e) {
return uni.getSystemInfoSync();
}
},
/**
* 深度拷贝对象
* @param {Object} obj
@@ -604,32 +527,6 @@ export default {
}
return cloneObj
},
/**
* 打开微信企业客服
* @param {Function} fallbackFunc 降级处理函数
*/
openWxWorkServiceChat(fallbackFunc) {
// #ifdef MP-WEIXIN
let wxworkConfig = store.state?.wxworkConfig
if (wxworkConfig?.enable && wxworkConfig?.contact_url) {
// 直接使用活码链接跳转
wx.navigateToMiniProgram({
appId: 'wxeb490c6f9b154ef9', // 是企业微信官方小程序的AppID(固定值, 由腾讯企业微信团队维护, 不需要修改,用于展示"添加企业微信联系人"的官方页面)
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig?.contact_url)}`,
success: () => {
},
fail: (err) => {
}
});
} else {
fallbackFunc && fallbackFunc();
}
// #endif
},
/**
* 自定义模板的跳转链接
* @param {Object} link
@@ -652,6 +549,7 @@ export default {
} else if (link.appid) {
// 跳转其他小程序
uni.navigateToMiniProgram({
appId: link.appid,
path: link.page
@@ -659,6 +557,7 @@ export default {
} else if (link.name == 'MOBILE' && !link.wap_url) {
// 拨打电话
uni.makePhoneCall({
phoneNumber: link.mobile,
success: (res) => {
@@ -691,19 +590,16 @@ export default {
// #endif
// #ifdef MP-WEIXIN
this.openWxWorkServiceChat(() => {
wx.openCustomerServiceChat({
extInfo: {
url: config.wxwork_url
},
corpId: config.corpid,
showMessageCard: true,
sendMessageTitle: 'this.sendMessageTitle',
sendMessagePath: 'this.sendMessagePath',
sendMessageImg: 'this.sendMessageImg'
});
wx.openCustomerServiceChat({
extInfo: {
url: config.wxwork_url
},
corpId: config.corpid,
showMessageCard: true,
sendMessageTitle: 'this.sendMessageTitle',
sendMessagePath: 'this.sendMessagePath',
sendMessageImg: 'this.sendMessageImg'
});
// #endif
break;
case 'third':
@@ -754,7 +650,7 @@ export default {
*/
uniappIsIPhoneX() {
let isIphoneX = false;
let systemInfo = this.getDeviceInfo();
let systemInfo = uni.getSystemInfoSync();
// #ifdef MP
if (systemInfo.model.search('iPhone X') != -1 || systemInfo.model.search('iPhone 11') != -1 || systemInfo.model.search('iPhone 12') != -1 || systemInfo.model.search('iPhone 13') != -1) {
isIphoneX = true;
@@ -781,7 +677,7 @@ export default {
*/
uniappIsIPhone11() {
let isIphone11 = false;
let systemInfo = this.getDeviceInfo();
let systemInfo = uni.getSystemInfoSync();
// #ifdef MP
if (systemInfo.model.search('iPhone 11') != -1) {
isIphone11 = true;
@@ -792,7 +688,7 @@ export default {
// #ifdef H5
//判断该浏览器是否为safaria浏览器
isSafari() {
let res = this.getDeviceInfo();
let res = uni.getSystemInfoSync();
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf('applewebkit') > -1 && ua.indexOf('mobile') > -1 && ua.indexOf('safari') > -1 &&
ua.indexOf('linux') === -1 && ua.indexOf('android') === -1 && ua.indexOf('chrome') === -1 &&
@@ -831,22 +727,13 @@ export default {
let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
return routes.length ? routes[routes.length - 1].route : '';
},
goBack(backUrl = INDEX_PAGE_URL) {
goBack(backUrl = '/pages/index/index') {
if (getCurrentPages().length == 1) {
this.redirectTo(backUrl);
} else {
uni.navigateBack();
}
},
/**
* 隐藏“返回首页/小房子”按钮
* 这个函数,用到页面show, onshow 的生命周期时
*/
hideHomeButton() {
// #ifdef MP-WEIXIN
wx.hideHomeButton();
// #endif
},
/**
*
* @param val 转化时间字符串 (转化时分秒)
@@ -902,11 +789,12 @@ export default {
},
success: res => {
if (res.code >= 0) {
uni.removeStorage({
key: 'source_member',
success: res => {
}
})
uni.removeStorage({
key: 'source_member',
success: res => {
console.log('删除成功', res)
}
})
}
}
})
@@ -930,23 +818,27 @@ export default {
success: res => {
if (res.data.length) {
// #ifdef MP-WEIXIN
uni.requestSubscribeMessage({
tmplIds: res.data,
success: (res) => {
},
fail: (res) => {
}
})
uni.requestSubscribeMessage({
tmplIds: res.data,
success: (res) => {
console.log("res", res)
},
fail: (res) => {
console.log('fail', res)
}
})
// #endif
// #ifdef MP-ALIPAY
my.requestSubscribeMessage({
entityIds: res.data,
success: res => {
},
fail: res => {
}
});
my.requestSubscribeMessage({
entityIds: res.data,
success: res => {
console.log("res", res)
},
fail: res => {
console.log('fail', res)
}
});
// #endif
}
}
@@ -1191,73 +1083,5 @@ export default {
verifyMobile(mobile) {
var parse = /^\d{11}$/.test(mobile);
return parse;
},
/**
* 判断是否为快应用环境
* @returns {boolean} 是否为快应用
*/
isQuickApp() {
// #ifndef QUICKAPP-WEBVIEW
let _isQuickApp = false;
try {
const ua = navigator?.userAgent?.toLowerCase();
_isQuickApp = ua.indexOf('quickapp') !== -1;
if (!_isQuickApp) {
// 特殊说明由于网站是嵌入到快应用的Webview组件中<web>,UA中不会包含quickapp字符串,
// 但是会包含uniacid参数,所以这里通过uniacid参数来判断是否为快应用环境
_isQuickApp = ua.indexOf('uniacid=') !== -1;
}
} catch (e) { }
if (!_isQuickApp) {
const systemInfo = this.getDeviceInfo();
_isQuickApp = systemInfo?.platform === 'quickapp' || process?.env?.UNI_PLATFORM === 'quickapp';
}
return _isQuickApp;
// #endif
return true;
},
/**
* 判断是否为华为快应用环境
* @returns {boolean} 是否为华为快应用
*/
isHuaweiQuickApp() {
if (!this.isQuickApp()) return false;
// #ifndef QUICKAPP-WEBVIEW-HUAWEI
const systemInfo = this.getDeviceInfo();
return systemInfo.brand === 'HUAWEI' || systemInfo.manufacturer === 'HUAWEI' ||
(typeof qh !== 'undefined' && qh.platform === 'huawei');
// #endif
return true;
},
/**
* 蛇形命名转驼峰命名
* @param {string} str 蛇形命名字符串
* @returns {string} 驼峰命名字符串
*/
snakeToCamel(str) {
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
},
/**
* 蛇形命名转驼峰命名(递归处理对象中的所有属性名)
* @param {Object} obj 包含蛇形命名字符串属性的对象
* @returns {Object} 驼峰命名字符串属性的对象
*/
snakeToCamelForObj(obj) {
if (typeof obj !== 'object' || obj === null) return obj;
if (Array.isArray(obj)) return obj.map(this.snakeToCamelForObj.bind(this));
const newObj = {};
for (const key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
const newKey = this.snakeToCamel(key);
newObj[newKey] = this.snakeToCamelForObj(obj[key]);
}
}
return newObj;
}
}

View File

@@ -55,6 +55,7 @@ let Weixin = function () {
typeof callback == 'function' && callback(res);
},
fail: (res) => {
console.log('获取收货地址 fail',res);
alert(JSON.stringify(res))
}
});

View File

@@ -1,38 +0,0 @@
/**
* 微信小程序图片长按识别二维码 mixin
* 自动为页面中的所有 image 组件添加 show-menu-by-longpress 属性
*/
export default {
data() {
return {
// 需要排除的图片类名(不需要长按识别的)
excludeImageClass: ['no-longpress', 'swiper-image', 'banner-image']
}
},
mounted() {
// #ifdef MP-WEIXIN
this.$nextTick(() => {
this.addLongpressToImages()
})
// #endif
},
methods: {
/**
* 为页面中的所有 image 添加长按识别支持
*/
addLongpressToImages() {
// 获取当前页面所有 image 组件
const images = document.querySelectorAll && document.querySelectorAll('image')
if (images) {
images.forEach(img => {
// 检查是否需要排除
const className = img.className || ''
const shouldExclude = this.excludeImageClass.some(cls => className.includes(cls))
if (!shouldExclude) {
img.setAttribute('show-menu-by-longpress', 'true')
}
})
}
}
}
}

View File

@@ -1,143 +0,0 @@
// 公共微信视频号样式
// CSS 变量
:root {
// 尺寸变量
--channel-play-btn-size: 80rpx;
--channel-play-btn-small-size: 60rpx;
--channel-play-btn-icon-size: 40rpx;
--channel-play-btn-icon-small-size: 30rpx;
--channel-border-radius: 12rpx;
--channel-stats-padding: 10rpx;
--channel-info-wrap-padding: 10rpx 0;
// 字体变量
--channel-name-font-size: 28rpx;
--video-title-font-size: 28rpx;
--video-title-small-font-size: 24rpx;
--video-stats-font-size: 24rpx;
--channel-stats-font-size: 20rpx;
// 颜色变量
--channel-name-color: #333;
--video-title-color: #333;
--video-title-small-color: #666;
--video-stats-color: #999;
--channel-stats-color: #fff;
--channel-border-color: #f0f0f0;
--channel-play-btn-bg: rgba(0, 0, 0, 0.4);
--channel-stats-bg: linear-gradient(transparent, rgba(0, 0, 0, 0.6));
// 间距变量
--channel-name-margin-bottom: 4rpx;
--video-title-margin-bottom: 8rpx;
}
// 响应式设计
@media (max-width: 375px) {
:root {
--channel-play-btn-size: 70rpx;
--channel-play-btn-small-size: 50rpx;
--channel-play-btn-icon-size: 35rpx;
--channel-play-btn-icon-small-size: 25rpx;
--channel-name-font-size: 24rpx;
--video-title-font-size: 24rpx;
}
}
@media (min-width: 750px) {
:root {
--channel-play-btn-size: 90rpx;
--channel-play-btn-small-size: 70rpx;
--channel-play-btn-icon-size: 45rpx;
--channel-play-btn-icon-small-size: 35rpx;
--channel-name-font-size: 32rpx;
--video-title-font-size: 32rpx;
}
}
// 播放按钮样式
.channel-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
width: var(--channel-play-btn-size);
height: var(--channel-play-btn-size);
background-color: var(--channel-play-btn-bg);
border-radius: 50%;
.play-icon {
width: var(--channel-play-btn-icon-size);
height: var(--channel-play-btn-icon-size);
}
}
// 小尺寸播放按钮(用于列表)
.channel-play-btn.small {
width: var(--channel-play-btn-small-size);
height: var(--channel-play-btn-small-size);
.play-icon {
width: var(--channel-play-btn-icon-small-size);
height: var(--channel-play-btn-icon-small-size);
}
}
// 视频统计信息
.channel-stats {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: var(--channel-stats-bg);
padding: var(--channel-stats-padding);
color: var(--channel-stats-color);
font-size: var(--channel-stats-font-size);
}
// 视频信息容器
.channel-info-wrap {
display: flex;
flex-direction: column;
flex: 1;
padding: var(--channel-info-wrap-padding);
.channel-name {
margin-bottom: var(--channel-name-margin-bottom);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: var(--channel-name-font-size);
font-weight: 500;
color: var(--channel-name-color);
}
.video-title {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: var(--video-title-small-font-size);
color: var(--video-title-small-color);
}
}
// 视频标题
.video-title {
font-size: var(--video-title-font-size);
font-weight: 500;
color: var(--video-title-color);
margin-bottom: var(--video-title-margin-bottom);
line-height: 1.4;
}
// 视频统计信息(非绝对定位版本)
.video-stats {
font-size: var(--video-stats-font-size);
color: var(--video-stats-color);
}

View File

@@ -3,16 +3,16 @@
<view class="article-wrap" :style="warpCss">
<view :class="['list-wrap', value.style]" :style="warpCss">
<!-- 自动垂直滚动 -->
<swiper class="auto-scroll-swiper" :style="[swiperStyle]" :vertical="swiperConfig.vertical !== false"
<swiper class="auto-scroll-swiper" :style="swiperStyle" :vertical="swiperConfig.vertical !== false"
:autoplay="swiperConfig.autoplay !== false" :circular="swiperConfig.circular !== false"
:interval="swiperConfig.interval || 3000" :duration="swiperConfig.duration || 500"
:display-multiple-items="safeDisplayMultipleItems">
<swiper-item v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)">
<swiper-item v-for="(item, index) in list" :key="index" @click="toDetail(item)">
<view class="swiper-item-content">
<view :class="['item', value.ornament.type]" :style="itemCss">
<view class="article-img">
<image class="cover-img" :src="$util.img(item.cover_img)" mode="widthFix"
@error="imgError(index)" show-menu-by-longpress/>
@error="imgError(index)" />
</view>
<view class="info-wrap">
<text class="title">{{ item.article_title }}</text>

View File

@@ -11,13 +11,13 @@
<view class="time" :style="{ color: value.timecolor }">
{{ audiotime }}
</view>
<view @tap.stop="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"
<view @click="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"
style="padding-top: 18rpx"></view>
</view>
<view class="fui-audio style3" :style="{ background: value.background }" v-else>
<!-- <audio src="/static/audio/bgm.mp3" controls loop></audio> -->
<view class="img">
<image :src="$util.img(value.imageUrl)" show-menu-by-longpress></image>
<image :src="$util.img(value.imageUrl)"></image>
</view>
<view class="content">
<view class="name" :style="{ color: value.textcolor }">{{ value.text }}</view>
@@ -30,7 +30,7 @@
<!-- {{audios[value.id].audiotime}} -->
{{ audiotime }}
</view>
<view @tap.stop="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"></view>
<view @click="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"></view>
</view>
</view>
</template>
@@ -98,7 +98,9 @@ export default {
uni.setStorageSync('audio_list', audio_list)
}
}
console.log(uni.getStorageSync('audio_list'))
var n = this;
// console.log(a)
a.onPlay(function () {
var e = setInterval(function () {
var i = a.currentTime / a.duration * 100 + "%", s = Math.floor(Math.ceil(a.currentTime) / 60), o = (Math.ceil(a.currentTime) % 60 / 100).toFixed(2).slice(-2), r = Math.ceil(a.currentTime);
@@ -111,12 +113,13 @@ export default {
var s = n.$util.img(n.value.audioUrl), o = n.audios[n.value.id].seconds || 0, r = 0, u = 1;
0 == u && a.onEnded(function (e) {
c[t].status = !1, n.status = !1, c[t].seconds = 0, n.audios = c;
c[t].status = !1, n.status = !1, c[t].seconds = 0, console.log(c), n.audios = c;
});
var c = n.audios;
c[t] || (c[t] = {}), a.paused && 0 == o ? (a.src = s, a.play(), 1 == u && (a.loop = !0),
c[t].status = !0, n.status = !0, n.pauseOther(t)) : a.paused && o > 0 ? (a.play(), 0 == r ? a.seek(o) : a.seek(0),
c[t].status = !0, n.status = !0, n.pauseOther(t)) : (a.pause(), c[t].status = !1, n.status = !1), n.audios = c;
console.log(n.audios)
},
pauseOther: function (e) {
var t = this;
@@ -187,14 +190,18 @@ export default {
var u = s + ":" + o, c = that.audios;
c[t].audiowidth = i, c[t].Time = e, c[t].audiotime = u, c[t].seconds = r
that.audios = c
// console.log(c)
console.log(that.audios[that.value.id].audiotime)
that.audiotime = that.audios[that.value.id].audiotime
that.audiowidth = that.audios[that.value.id].audiowidth
console.log(i)
that.lyg = i
}, 1e3);
});
this.audioContext.onEnded(() => {
console.log('播放结束');
this.status = 0
});
}

View File

@@ -10,12 +10,12 @@
:style="{ fontSize: value.titleStyle.fontSize * 2 + 'rpx', color: value.titleStyle.textColor, fontWeight: value.titleStyle.fontWeight ? 'bold' : '' }">
{{ value.titleStyle.leftText }}
</view>
<image v-else class="left-img" :src="$util.img(value.titleStyle.leftImg)" mode="heightFix" show-menu-by-longpress></image>
<image v-else class="left-img" :src="$util.img(value.titleStyle.leftImg)" mode="heightFix"></image>
<view class="head-content" v-if="value.titleStyle.style == 'style-1'"
:style="{ color: value.titleStyle.textColor }">低至0元免费拿</view>
<view class="head-right"
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
@tap.stop="$util.redirectTo('/pages_promotion/bargain/list')">
@click="$util.redirectTo('/pages_promotion/bargain/list')">
<text>{{ value.titleStyle.more }}</text>
<text class="iconfont icon-right"></text>
</view>
@@ -23,12 +23,12 @@
<!-- 商品列表 -->
<template v-if="value.template == 'row1-of1'">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.btnStyle.control">
@@ -41,7 +41,7 @@
<view class="bg">
<view class="curr" :style="{ width: progress(item) * 2 + 'rpx' }">
<image class="progress-bar" mode="widthFix"
:src="$util.img('public/uniapp/bargain/progress_bar_01.png')" show-menu-by-longpress/>
:src="$util.img('public/uniapp/bargain/progress_bar_01.png')" />
</view>
</view>
<view class="num" v-if="item.is_bargaining">
@@ -84,12 +84,12 @@
<template v-if="value.template == 'horizontal-slide'">
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" :lazy-load="true" show-menu-by-longpress/>
@error="imageError(index)" :lazy-load="true" />
<image class="bg"
v-if="value.saleStyle.control && value.template == 'horizontal-slide' && value.style != 'style-2'"
:src="$util.img('public/uniapp/bargain/bg.png')" mode="widthFix" />
@@ -130,11 +130,11 @@
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(dataIndex)" :lazy-load="true" show-menu-by-longpress/>
@error="imageError(dataIndex)" :lazy-load="true" />
<image class="bg"
v-if="value.saleStyle.control && value.template == 'horizontal-slide' && value.style != 'style-2'"
:src="$util.img('public/uniapp/bargain/bg.png')" mode="widthFix" />
@@ -365,7 +365,7 @@ export default {
</script>
<style lang="scss">
::v-deep .uni-scroll-view ::-webkit-scrollbar {
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
@@ -374,7 +374,7 @@ export default {
background: transparent;
}
::v-deep ::-webkit-scrollbar {
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;

View File

@@ -2,7 +2,7 @@
<view data-component-name="diy-bottom-nav" v-if="tabBarList && tabBarList.list">
<view class="tab-bar" :style="{ backgroundColor: tabBarList.backgroundColor }">
<view class="tabbar-border"></view>
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @tap.stop="redirectTo(item.link)">
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @click="redirectTo(item.link)">
<view class="bd">
<block v-if="item.link.wap_url == '/pages_goods/cart'">
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2"
@@ -59,7 +59,7 @@
</template>
<script>
import { adaptSubpackageUrl, checkTabBarActive } from '@/common/js/util.js'
import { adaptSubpackageUrl } from '@/common/js/util.js'
import DiyMinx from './minx.js'
// 底部导航栏
export default {
@@ -145,16 +145,27 @@ export default {
let linkUrl = link.wap_url;
// 首页特殊处理
if (linkUrl === this.$util.INDEX_PAGE_URL && this.name === 'DIY_VIEW_INDEX') {
if (linkUrl === '/pages/index/index' && this.name === 'DIY_VIEW_INDEX') {
return true;
}
// console.log('diy-bottom-nav verify:', { likkUrl: adaptSubpackageUrl(linkUrl), currentPageRoute: currentPageRoute});
// 精确匹配当前路径
if (adaptSubpackageUrl(linkUrl) === currentPageRoute) {
return true;
}
return checkTabBarActive(linkUrl, currentPageRoute);
// 同属于一个子包的路径,也认为是匹配的
try {
if (adaptSubpackageUrl(linkUrl).split('/')[1] === currentPageRoute.split('/')[1]) {
return true;
}
} catch (error) {
console.error('diy-bottom-nav verify error:', error);
}
return false;
}
}
};

View File

@@ -1,17 +1,17 @@
<template>
<view data-component-name="diy-category-item" class="item-wrap" :class="type">
<block v-if="type == 'category' && category.child_list && category.child_list.length">
<view class="category-adv" v-if="category.image_adv" @tap.stop="diyRedirectTo(category.link_url)">
<image :src="$util.img(category.image_adv)" mode="widthFix" show-menu-by-longpress />
<view class="category-adv" v-if="category.image_adv" @click="diyRedirectTo(category.link_url)">
<image :src="$util.img(category.image_adv)" mode="widthFix" />
</view>
<block v-if="value.level == 2">
<view class="category-title">{{ category.category_name }}</view>
<view class="category-list">
<view class="category-item" v-for="(one, oneIndex) in category.child_list" :key="oneIndex"
@tap.stop="$util.redirectTo('/pages_goods/list', { category_id: one.category_id })">
@click="$util.redirectTo('/pages_goods/list', { category_id: one.category_id })">
<view class="img-box">
<image :src="$util.img(one.image)" mode="widthFix" show-menu-by-longpress />
<image :src="$util.img(one.image)" mode="widthFix" />
</view>
<view class="name">{{ one.category_name }}</view>
</view>
@@ -23,9 +23,9 @@
<view class="category-title">{{ one.category_name }}</view>
<view class="category-list">
<view class="category-item" v-for="(two, twoIndex) in one.child_list" :key="twoIndex"
@tap.stop="$util.redirectTo('/pages_goods/list', { category_id: two.category_id })">
@click="$util.redirectTo('/pages_goods/list', { category_id: two.category_id })">
<view class="img-box">
<image :src="$util.img(two.image)" mode="widthFix" :lazy-load="true" show-menu-by-longpress />
<image :src="$util.img(two.image)" mode="widthFix" :lazy-load="true" />
</view>
<view class="name">{{ two.category_name }}</view>
</view>
@@ -44,22 +44,22 @@
:class="{ 'screen-category-4': value.template == 4 }" :scroll-with-animation="true"
:scroll-into-view="scrollIntoView">
<view class="item" id="category-2--1" :class="{ selected: categoryId == -1 }"
@tap.stop="selectCategory(-1)">全部</view>
@click="selectCategory(-1)">全部</view>
<view class="item" :id="'category-2-' + oneIndex"
:class="{ selected: categoryId == oneIndex }" @tap.stop="selectCategory(oneIndex)"
:class="{ selected: categoryId == oneIndex }" @click="selectCategory(oneIndex)"
v-for="(one, oneIndex) in category.child_list" :key="oneIndex">
{{ one.category_name }}
</view>
</scroll-view>
<view class="iconfont icon-unfold" @tap.stop="$refs.screenCategoryPopup.open()"></view>
<view class="iconfont icon-unfold" @click="$refs.screenCategoryPopup.open()"></view>
</view>
<uni-popup type="top" ref="screenCategoryPopup">
<view class="screen-category-popup" @tap.stop="$refs.screenCategoryPopup.close()">
<view class="screen-category-popup" @click="$refs.screenCategoryPopup.close()">
<scroll-view scroll-y="true" class="screen-category"
:class="{ 'screen-category-4': value.template == 4 }">
<view class="title">全部</view>
<view class="item" :class="{ selected: categoryId == oneIndex }"
@tap.stop="selectCategory(oneIndex)" v-for="(one, oneIndex) in category.child_list"
@click="selectCategory(oneIndex)" v-for="(one, oneIndex) in category.child_list"
:key="oneIndex">
{{ one.category_name }}
</view>
@@ -81,13 +81,13 @@
:data-template="value.template">
<block v-if="goodsList.length">
<view class="goods-item" v-for="(item, index) in goodsList" :key="index">
<view class="goods-img" @tap.stop="toDetail(item)">
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" show-menu-by-longpress />
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}
<view class="goods-img" @click="toDetail(item)">
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)" />
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}
</view>
</view>
</view>
<view class="info-wrap">
<view class="name-wrap" @tap.stop="toDetail(item)">
<view class="name-wrap" @click="toDetail(item)">
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
</view>
<view class="price-wrap">
@@ -99,14 +99,17 @@
<text class="unit price-style small">.{{
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
</block>
<block v-else>
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询价' }}</text>
</block>
</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" show-menu-by-longpress />
<image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix" />
</view>
<view class="member-price-tag" v-else-if="item.promotion_type == 1">
<image :src="$util.img('public/uniapp/index/discount.png')"
mode="widthFix" show-menu-by-longpress />
mode="widthFix" />
</view>
</view>
<view class="footer-wrap">
@@ -117,33 +120,27 @@
<text>{{ showMarketPrice(item) }}</text>
</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">
<block v-if="item.is_virtual">
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
</block>
<block v-else>
<view v-if="item.goods_spec_format" class="color-base-bg select-sku" @tap.stop="selectSku(item)">
<view v-if="item.goods_spec_format" class="color-base-bg select-sku" @click="selectSku(item)">
<text>选规格</text>
<text class="num-tag" v-if="item.num">{{ item.num }}</text>
</view>
<block v-else>
<block v-if="cartList['goods_' + item.goods_id]&&cartList['goods_' + item.goods_id]['sku_' + item.sku_id]">
<view class="num-action reduce" @tap.stop="reduce(item)">
<view class="num-action reduce" @click="reduce(item)">
<text class="iconfont icon-jian"></text>
</view>
<view class="num">{{ cartList['goods_' + item.goods_id]['sku_' + item.sku_id].num }}</view>
<view class="num-action" :id="'cart-num-' + index" @tap.stop="increase($event, item)">
<view class="num-action" :id="'cart-num-' + index" @click="increase($event, item)">
<text class="iconfont icon-jia"></text>
<view class="click-event"></view>
</view>
</block>
<view class="num-action" v-else :id="'cart-num-' + index" @tap.stop="increase($event, item, 0)">
<view class="num-action" v-else :id="'cart-num-' + index" @click="increase($event, item, 0)">
<text class="iconfont icon-jia"></text>
<view class="click-event"></view>
</view>
@@ -151,17 +148,17 @@
</block>
</view> -->
<!-- <view class="right-wrap" v-if="value.template == 3">
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
</view> -->
</view>
</view>
</view>
</block>
<view class="category-empty" v-else>
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" show-menu-by-longpress />
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" />
</view>
<!-- <view class="end-tips" ref="endTips" v-if="last && (categoryId == -1 || !category.child_list || (category.child_list && categoryId == category.child_list.length - 1))">已经到底了~</view>
<view class="end-tips" ref="endTips" v-else @tap.stop="switchCategory('next')">
<view class="end-tips" ref="endTips" v-else @click="switchCategory('next')">
<text class="iconfont icon-xiangshangzhanhang"></text>
上滑查看下一分类
</view> -->
@@ -176,31 +173,35 @@
<view class="goods-list" :class="{ 'double-column': !isList, 'single-column': isList }"
:data-template="value.template">
<view class="goods-item" v-for="(item, index) in goodsList" :key="index">
<view class="goods-img" @tap.stop="toDetail(item)">
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"
:lazy-load="true" show-menu-by-longpress />
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}</view>
</view>
<view class="goods-img" @click="toDetail(item)">
<image :src="goodsImg(item.goods_image)" mode="widthFix" @error="imgError(index)"
:lazy-load="true" />
<view class="color-base-bg goods-tag" v-if="item.label_name">{{ item.label_name }}</view>
</view>
<view class="info-wrap">
<view class="name-wrap" @tap.stop="toDetail(item)">
<view class="name-wrap" @click="toDetail(item)">
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
</view>
<view class="price-wrap">
<view class="discount-price">
<block v-if="item.isinformation == 0">
<text class="unit price-style small">¥</text>
<text class="price price-style large">{{
parseFloat(showPrice(item)).toFixed(2).split('.')[0] }}</text>
<text class="unit price-style small">.{{
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
</block>
</view>
<block v-if="item.isinformation == 0">
<text class="unit price-style small">¥</text>
<text class="price price-style large">{{
parseFloat(showPrice(item)).toFixed(2).split('.')[0] }}</text>
<text class="unit price-style small">.{{
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
</block>
<block v-else>
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询价' }}</text>
</block>
</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" show-menu-by-longpress />
<image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix" />
</view>
<view class="member-price-tag" v-else-if="item.promotion_type == 1">
<image :src="$util.img('public/uniapp/index/discount.png')" mode="widthFix" show-menu-by-longpress />
<image :src="$util.img('public/uniapp/index/discount.png')" mode="widthFix" />
</view>
</view>
<view class="footer-wrap">
@@ -211,38 +212,32 @@
<text>{{ showMarketPrice(item) }}</text>
</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">
<block v-if="item.is_virtual">
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
</block>
<block v-else>
<view v-if="item.goods_spec_format" class="color-base-bg select-sku"
@tap.stop="selectSku(item)">
@click="selectSku(item)">
<text>选规格</text>
<text class="num-tag" v-if="item.num">{{ item.num }}</text>
</view>
<block v-else>
<block
v-if="cartList['goods_' + item.goods_id] && cartList['goods_' + item.goods_id]['sku_' + item.sku_id]">
<view class="num-action reduce" @tap.stop="reduce(item)">
<view class="num-action reduce" @click="reduce(item)">
<text class="iconfont icon-jian"></text>
</view>
<view class="num">{{ cartList['goods_' + item.goods_id]['sku_' +
item.sku_id].num }}</view>
<view class="num-action" :id="'cart-num-' + index"
@tap.stop="increase($event, item)">
@click="increase($event, item)">
<text class="iconfont icon-jia"></text>
<view class="click-event"></view>
</view>
</block>
<view class="num-action" v-else :id="'cart-num-' + index"
@tap.stop="increase($event, item, 0)">
@click="increase($event, item, 0)">
<text class="iconfont icon-jia"></text>
<view class="click-event"></view>
</view>
@@ -250,7 +245,7 @@
</block>
</view>
<view class="right-wrap" v-if="value.template == 3">
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
<view class="color-base-bg select-sku" @click="toDetail(item)">立即购买</view>
</view>
</view>
</view>
@@ -723,15 +718,6 @@ export default {
}
}
},
/**
* 跳转到商品详情
* @param {Object} item 商品信息
*/
sendToAIChat(item) {
this.$util.redirectTo('/pages_goods/detail', {
goods_id: item.goods_id
});
},
diyRedirectTo(link) {
if (!link) return;
this.$util.diyRedirectTo(JSON.parse(link));
@@ -1174,7 +1160,7 @@ export default {
.right-wrap {
display: flex;
align-items: center;
justify-content: flex-end;
justify-content: end;
.num {
width: auto;
@@ -1328,7 +1314,7 @@ export default {
}
}
::v-deep .uni-popup__wrapper-box {
/deep/ .uni-popup__wrapper-box {
border-radius: 0;
}
@@ -1362,7 +1348,7 @@ export default {
justify-content: center;
}
::v-deep .loading-layer {
/deep/ .loading-layer {
background: #fff !important;
}
@@ -1398,25 +1384,4 @@ export default {
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>

View File

@@ -3,9 +3,9 @@
:style="{ height: 'calc(100vh - ' + tabBarHeight + ')' }">
<!-- #ifdef MP-WEIXIN -->
<!-- <block v-if="value.template == 4">
<view class="search-box" v-if="value.search" @tap.stop="$util.redirectTo('/pages_tool/goods/search')" :style="navbarInnerStyle">
<view class="search-box" v-if="value.search" @click="$util.redirectTo('/pages_tool/goods/search')" :style="navbarInnerStyle">
<view class="search-content">
<input type="text" class="uni-input font-size-tag" maxlength="50" :placeholder="$lang('search')" confirm-type="search" @tap.stop="onClickSearch()" disabled="true" />
<input type="text" class="uni-input font-size-tag" maxlength="50" :placeholder="$lang('search')" confirm-type="search" @click.stop="onClickSearch()" @tap.stop="onClickSearch()" disabled="true" />
<text class="iconfont icon-sousuo3"></text>
</view>
</view>
@@ -13,61 +13,61 @@
</block> -->
<block v-if="value.template != 4">
<!-- <view :style="navbarInnerStyle">商品分类</view> -->
<view class="search-box" v-if="value.search" @tap.stop="onClickSearch()"
<view class="search-box" v-if="value.search" @click="onClickSearch()" @tap.stop="onClickSearch()"
:style="wxSearchHeight">
<view class="search-content">
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('search')"
confirm-type="search" @tap.stop="onClickSearch()"
confirm-type="search" @click.stop="onClickSearch()" @tap.stop="onClickSearch()"
disabled="true" />
<text class="iconfont icon-sousuo3"></text>
</view>
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
@tap.stop.prevent="changeListStyle()"></view>
@click.stop.prevent="changeListStyle()"></view>
</view>
</block>
<!-- #endif -->
<!-- #ifdef H5 -->
<view class="search-box" v-if="value.search" @tap.stop="onClickSearch()">
<view class="search-box" v-if="value.search" @click="onClickSearch()" @tap.stop="onClickSearch()">
<view class="search-content">
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('search')" confirm-type="search"
@tap.stop="onClickSearch()" disabled="true" />
@click.stop="onClickSearch()" @tap.stop="onClickSearch()" disabled="true" />
<text class="iconfont icon-sousuo3"></text>
</view>
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
@tap.stop.prevent="changeListStyle()"></view>
@click.stop.prevent="changeListStyle()"></view>
</view>
<!-- #endif -->
<view class="template-four wx" v-if="value.template == 4">
<scroll-view scroll-x="true" class="template-four-wrap" :scroll-with-animation="true"
:scroll-into-view="'category-one-' + oneCategorySelect" enable-flex="true">
<view class="category-item" :id="'category-one-' + index" v-for="(item, index) in templateFourData"
:key="index" :class="{ select: oneCategorySelect == index }" @tap.stop="templateFourOneFn(index)">
:key="index" :class="{ select: oneCategorySelect == index }" @click="templateFourOneFn(index)">
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
<image :src="$util.img(item.image)" mode="aspectFill" show-menu-by-longpress/>
<image :src="$util.img(item.image)" mode="aspectFill" />
</view>
<view :class="['text', { 'color-base-bg': oneCategorySelect == index }]">{{ item.category_name }}
</view>
</view>
</scroll-view>
<view class="category-item-all" @tap.stop="$refs.templateFourPopup.open()">
<view class="category-item-all" @click="$refs.templateFourPopup.open()">
<view class="category-item-all-wrap">
<text class="text">展开</text>
<image class="img" :src="$util.img('/public/uniapp/category/unfold.png')" mode="aspectFill" show-menu-by-longpress></image>
<image class="img" :src="$util.img('/public/uniapp/category/unfold.png')" mode="aspectFill"></image>
</view>
</view>
<uni-popup type="top" ref="templateFourPopup" :top="uniPopupTop">
<view class="template-four-popup">
<scroll-view scroll-y="true" class="template-four-scroll" enable-flex="true">
<view class="item" :class="{ selected: oneCategorySelect == index }"
@tap.stop="templateFourOneFn(index)" v-for="(item, index) in templateFourData" :key="index">
@click="templateFourOneFn(index)" v-for="(item, index) in templateFourData" :key="index">
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
<image :src="$util.img(item.image)" mode="aspectFill" show-menu-by-longpress></image>
<image :src="$util.img(item.image)" mode="aspectFill"></image>
</view>
<view :class="['text', { 'color-base-bg': oneCategorySelect == index }]">{{
item.category_name }}</view>
</view>
</scroll-view>
<view class="pack-up" @tap.stop="$refs.templateFourPopup.close()">
<view class="pack-up" @click="$refs.templateFourPopup.close()">
<text>点击收起</text>
<text class="iconfont icon-iconangledown-copy"></text>
</view>
@@ -83,7 +83,7 @@
{ select: select == index },
{ 'border-bottom': value.template == 4 && select + 1 === index },
{ 'border-top': value.template == 4 && select - 1 === index }
]" @tap.stop="switchOneCategory(index)">
]" @click="switchOneCategory(index)">
<view class="">{{ item.category_name }}</view>
</view>
</view>
@@ -119,18 +119,18 @@
</view>
</block>
<view class="category-empty" v-else>
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" show-menu-by-longpress></image>
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix"></image>
<view class="tips">暂时没有分类哦!</view>
</view>
</view>
<view class="category-empty" v-else>
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" show-menu-by-longpress></image>
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix"></image>
<view class="tips">暂时没有分类哦!</view>
</view>
<!-- <view class="cart-box" v-if="(value.template == 2 || value.template == 4) && value.quickBuy && storeToken && categoryTree && categoryTree.length">
<view class="left-wrap">
<view class="cart-icon" ref="cartIcon" :animation="cartAnimation" @tap.stop="$util.redirectTo('/pages_goods/cart')">
<view class="cart-icon" ref="cartIcon" :animation="cartAnimation" @click="$util.redirectTo('/pages_goods/cart')">
<text class="iconfont icon-ziyuan1"></text>
<view class="num" v-if="cartNumber">{{ cartNumber < 99 ? cartNumber : '99+' }}</view>
</view>
@@ -141,7 +141,7 @@
<text class="unit font-size-tag price-font">.{{ cartTotalMoney[1] ? cartTotalMoney[1] : '00' }}</text>
</view>
</view>
<view class="right-wrap"><button type="primary" class="settlement-btn" @tap.stop="settlement">去结算</button>
<view class="right-wrap"><button type="primary" class="settlement-btn" @click="settlement">去结算</button>
</view>
</view> -->
@@ -161,11 +161,15 @@ let menuButtonInfo = {};
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// #endif
import nsGoodsSkuCategory from '@/components/ns-goods-sku/ns-goods-sku-category.vue';
import DiyMinx from './minx.js'
var contentWrapHeight, query, cartPosition;
// 商品分类
export default {
components: {
nsGoodsSkuCategory
},
name: 'diy-category',
props: {
value: {
@@ -548,7 +552,7 @@ export default {
};
</script>
<style lang="scss" scoped>
<style lang="scss">
.category-page-wrap {
width: 100vw;
// height: calc(100vh - var(--tab-bar-height, 0));
@@ -818,7 +822,7 @@ export default {
z-index: 2;
}
::v-deep .template-four {
/deep/ .template-four {
position: relative;
z-index: 1;

View File

@@ -1,631 +0,0 @@
<template>
<view class="channel-list-container" :style="[componentStyle, { '--row-count': value.rowCount }]">
<!-- 轮播模式 -->
<swiper v-if="value.showStyle == 'carousel' && carouselConfig.type != 'hide'" :indicator-dots="isIndicatorDots"
:autoplay="carouselConfig.autoplay || false" :interval="carouselConfig.interval || 3000"
:duration="carouselConfig.duration || 500" :circular="carouselConfig.circular || false"
:style="swiperHeight" class="channel-swiper">
<swiper-item v-for="(slide, slideIndex) in swiperSlides" :key="slideIndex">
<view :class="['swiper-slide-content', 'row1-of' + value.rowCount]">
<view v-for="(item, index) in slide" :key="index" :class="['channel-item', value.mode]">
<!-- 视频号视频卡片,轮播模式 -->
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
:show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
:play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
</view>
</view>
</swiper-item>
</swiper>
<!-- 固定布局模式 -->
<view v-else-if="value.showStyle == 'fixed'" :class="['channel-list', 'row1-of' + value.rowCount]">
<view v-for="(item, index) in value.list" :key="index" class="channel-item">
<!-- 视频号视频卡片,列表模式 -->
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
:show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
:play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
</view>
</view>
<!-- 其他布局模式(如滚动布局) -->
<scroll-view v-else
:class="['channel-nav', value.showStyle == 'fixed' ? 'fixed-layout' : 'singleSlide', 'row1-of' + value.rowCount]"
:scroll-x="true"
:scroll-y="false"
:enhanced="true"
:bounces="false">
<view class="uni-scroll-view-content">
<view v-for="(item, index) in value.list" :key="index"
:class="['channel-nav-item', value.mode, 'row1-of' + value.rowCount]">
<!-- 视频号视频卡片,滚动模式 -->
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
:show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
:play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
</view>
</view>
</scroll-view>
</view>
</template>
<script>
/**
* 微信视频号列表组件
* 支持多种布局模式,包括固定布局和滚动布局
* 可配置列数、视频高度、标题行数等属性
* 用于在页面中展示多个微信视频号视频
*/
import DiyMinx from './minx.js'
import { wechatChannelUtil, wechatChannelConfig } from './js/wechat-channel.js'
export default {
name: 'diy-channel-list',
props: {
/**
* 组件配置数据
* @type {Object}
* @default () => ({})
* @property {string} showStyle - 显示样式,可选值:carousel, fixed, singleSlide
* @property {number} rowCount - 每行显示的视频数量
* @property {Array} list - 视频列表数据
* @property {string} componentBgColor - 组件背景色
* @property {string} componentAngle - 组件圆角类型,可选值:round
* @property {number} topAroundRadius - 顶部圆角半径
* @property {number} bottomAroundRadius - 底部圆角半径
* @property {Object} ornament - 装饰效果配置
* @property {boolean} showViewCount - 是否显示播放量,可选值:true, false
* @property {number} titleLineClamp - 标题显示行数
* @property {string} aspectRatio - 视频比例,可选值:16:9, 3:4
* @property {boolean} showPlayBtn - 是否显示播放按钮
* @property {Object} coverStyle - 视频封面图样式
* @property {Object} playBtnStyle - 播放按钮样式
* @property {string} mode - 显示模式, 可选值:video, text, image, graphic
* @property {number} imageSize - 图片尺寸(仅在特定模式下使用)
* @property {number} pageCount - 每页显示的视频数量
* @property {Object} carousel - 轮播配置
* @property {string} carousel.type - 轮播类型,可选值:default, hide
* @property {boolean} carousel.autoplay - 是否自动播放,默认false
* @property {number} carousel.interval - 自动播放间隔,默认3000ms
* @property {number} carousel.duration - 切换动画时长,默认500ms
* @property {boolean} carousel.circular - 是否循环播放,默认false
*/
value: {
type: Object,
default: () => ({})
}
},
mixins: [DiyMinx],
data() {
return {
pageWidth: '', // 页面宽度
indicatorDots: false, // 是否显示轮播指示器
swiperCurrent: 0 // 当前轮播索引
}
},
created() {
// 组件创建时的逻辑
// 可以在这里进行初始化操作,如获取页面宽度等
},
mounted() {
// 组件挂载后添加鼠标拖拽滚动功能
if (!['fixed', 'carousel'].includes(this.value?.showStyle)) {
this.$nextTick(() => {
this.addMouseDragScroll();
});
}
},
watch: {
/**
* 组件刷新监听
* 当组件需要刷新时触发
* @param {*} newValue - 新值
*/
componentRefresh(newValue) {
// 监听组件刷新
// 可以在这里处理组件刷新时的逻辑
}
},
computed: {
carouselConfig() {
return this.value?.carousel || {
type: 'default',
autoplay: false,
interval: 3000,
duration: 500,
circular: true
}
},
/**
* 组件样式
* 根据配置动态生成样式字符串,包括背景色、圆角、阴影和边框
* @returns {string} 样式字符串
*/
componentStyle() {
const style = {};
// 背景色
if (this.value?.componentBgColor) {
style.backgroundColor = this.value?.componentBgColor;
}
// 圆角样式
if (this.value?.componentAngle == 'round') {
style.borderTopLeftRadius = (2 * this.value?.topAroundRadius) + 'rpx';
style.borderTopRightRadius = (2 * this.value?.topAroundRadius) + 'rpx';
style.borderBottomLeftRadius = (2 * this.value?.bottomAroundRadius) + 'rpx';
style.borderBottomRightRadius = (2 * this.value?.bottomAroundRadius) + 'rpx';
}
// 装饰效果:阴影
style.boxShadow = this.value?.ornament?.type == 'shadow' ? '0 0 10rpx ' + this.value?.ornament?.color : '';
// 装饰效果:边框
style.border = this.value?.ornament?.type == 'stroke' ? '2rpx solid ' + this.value?.ornament?.color : '';
return style;
},
/**
* 轮播高度
* 根据模式和配置计算轮播高度
* @returns {string} 轮播高度样式
*/
swiperHeight() {
let height = 0;
const pageCount = this.value?.pageCount || 1;
// 根据不同模式计算高度
if (this.value?.mode == 'graphic') {
height = (49 + this.value?.imageSize) * pageCount;
} else if (this.value?.mode == 'img') {
height = (22 + this.value?.imageSize) * pageCount;
} else if (this.value?.mode == 'text') {
height = 43 * pageCount;
} else { // 默认视频模式
if (this.value?.aspectRatio == '16:9') {
height = [250, 160, 140, 120][this.value.rowCount - 1];
} else {
height = [510, 280, 220, 180][this.value.rowCount - 1];
}
}
return 'height:' + (2 * height) + 'rpx';
},
/**
* 是否显示指示器
* 根据轮播配置和列表长度判断是否显示指示器
* @returns {boolean} 是否显示指示器
*/
isIndicatorDots() {
// 当轮播类型不是隐藏,且视频数量超过一页时显示指示器
const pageCount = this.value?.pageCount || 1;
return this.value?.carousel?.type != 'hide' && Math.ceil(this.value?.list?.length / (pageCount * this.value?.rowCount)) > 1
},
/**
* 轮播幻灯片数据
* 将视频列表分割成轮播所需的幻灯片数据
* @returns {Array} 轮播幻灯片数据
*/
swiperSlides() {
const slides = [];
const list = this.value?.list || [];
const pageSize = (this.value?.pageCount || 1) * (this.value?.rowCount || 1);
// 将列表数据分割成每页显示的数量
for (let i = 0; i < list.length; i += pageSize) {
slides.push(list.slice(i, i + pageSize));
}
return slides;
},
/**
* 视频封面样式
* 根据aspectRatio属性动态计算封面样式
* @returns {Object} 封面样式对象
*/
computedCoverStyle() {
const aspectRatio = this.value?.aspectRatio || '16:9';
let paddingTop = '56.25%'; // 默认 16:9 比例
if (aspectRatio === '3:4') {
paddingTop = '133.33%'; // 3:4 比例
}
return {
width: '100%',
height: '0',
paddingTop: paddingTop
};
}
},
methods: {
/**
* 播放视频
* 触发 video-play 事件,并在微信小程序中调用视频播放接口
* @param {Object} item - 视频数据对象
*/
async playVideo(item) {
await this.__$emitEvent({
eventName: 'video-play',
data: item,
promiseCallback: async (event, handler, awaitedResult) => {
if (!awaitedResult) return;
try {
// 发送视频被点击播放事件
this.$emit('channel-video-click-play', item);
// #ifdef MP-WEIXIN
// 在微信小程序环境中调用视频播放接口
await wechatChannelUtil.playVideo(item);
// #endif
// #ifndef MP-WEIXIN
if (item?.channelType === 'wechat') {
uni.showToast({
title: '视频号仅支持在微信小程序环境中播放',
icon: 'none',
duration: 2000
});
} else {
// 在非微信小程序环境中,直接触发事件
this.$emit('video-play', item);
}
// #endif
} catch (err) {
console.error('打开视频号失败', err);
}
}
})
},
/**
* 图片加载错误处理
* 当图片加载失败时,设置默认图片
* @param {number} index - 图片索引
*/
imgError(index) {
// 图片加载失败的处理逻辑
// 为失败的图片设置默认图片
const item = this.value.list[index];
if (item) {
// 使用默认图片替代加载失败的图片
// #ifdef MP-WEIXIN
item.coverUrl = wechatChannelConfig.video.defaultCoverUrl;
// #endif
}
},
/**
* 添加鼠标拖拽滚动功能
* 在Web环境中实现与微信小程序相同的拖拽滚动效果
*/
addMouseDragScroll() {
// 只在Web环境中添加
// #ifndef MP
let isDragging = false;
let startX = 0;
let startScrollLeft = 0;
let currentScrollElement = null;
// 查找最近的可滚动祖先元素
const findScrollableParent = (element) => {
while (element && element !== document) {
const style = window.getComputedStyle(element);
if (style.overflowX === 'auto' || style.overflowX === 'scroll') {
return element;
}
element = element.parentElement;
}
return null;
};
// 鼠标按下事件
const handleMouseDown = (e) => {
// 检查是否点击在组件内
if (this.$el.contains(e.target)) {
// 查找可滚动元素
currentScrollElement = findScrollableParent(e.target);
if (currentScrollElement) {
isDragging = true;
startX = e.pageX;
startScrollLeft = currentScrollElement.scrollLeft;
currentScrollElement.style.cursor = 'grabbing';
}
}
};
// 鼠标移动事件
const handleMouseMove = (e) => {
if (!isDragging || !currentScrollElement) return;
e.preventDefault();
const dx = e.pageX - startX;
currentScrollElement.scrollLeft = startScrollLeft - dx;
};
// 鼠标释放事件
const handleMouseUp = () => {
if (isDragging && currentScrollElement) {
currentScrollElement.style.cursor = 'grab';
}
isDragging = false;
currentScrollElement = null;
};
// 添加全局事件监听器
document.addEventListener('mousedown', handleMouseDown);
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
document.addEventListener('mouseleave', handleMouseUp);
// 组件销毁时移除事件监听器
this.$once('hook:beforeDestroy', () => {
document.removeEventListener('mousedown', handleMouseDown);
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
document.removeEventListener('mouseleave', handleMouseUp);
});
// 为所有.channel-nav元素添加必要的样式
setTimeout(() => {
const channelNavs = document.querySelectorAll('.channel-nav');
channelNavs.forEach(element => {
element.style.overflowX = 'auto';
element.style.overflowY = 'hidden';
element.style.whiteSpace = 'nowrap';
element.style.width = '100%';
element.style.maxWidth = '100%';
element.style.cursor = 'grab';
element.style.userSelect = 'none'; // 防止文本选择
});
}, 100); // 延迟执行,确保DOM已完全渲染
// #endif
}
}
}
</script>
<style lang="scss" scoped>
@import './css/common-channel.scss';
.channel-list-container {
padding: 16px 16px 0px;
}
/**
* 列表布局样式
*/
.channel-list {
display: grid;
grid-template-columns: repeat(var(--row-count, 2), 1fr);
gap: 8px;
}
/**
* 导航布局样式
* 支持固定布局和滚动布局
*/
.channel-nav {
box-sizing: border-box;
padding: 16rpx;
// 确保在H5环境中可以水平滚动
overflow-x: auto;
white-space: nowrap;
// 隐藏滚动条但保留滚动功能
::-webkit-scrollbar {
display: none;
}
scrollbar-width: none;
-ms-overflow-style: none;
// 启用触摸滚动和鼠标拖拽滚动
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
.uni-scroll-view-content {
/* #ifdef MP-WEIXIN */
display: flex;
flex-wrap: nowrap;
gap: 16rpx;
/* #endif */
/* #ifndef MP-WEIXIN */
display: grid;
grid-template-columns: repeat(var(--row-count, 2), 1fr);
gap: 16rpx;
/* #endif */
}
// 单滑动模式
&.singleSlide {
.uni-scroll-view-content {
display: flex;
flex-wrap: nowrap;
gap: 16rpx;
white-space: nowrap;
}
.channel-nav-item {
flex-shrink: 0;
width: 280rpx;
}
}
.channel-nav-item {
display: flex;
flex-direction: column;
box-sizing: border-box;
/* #ifdef MP-WEIXIN */
&.row1-of1 {
width: 100%;
}
&.row1-of2 {
width: calc(50% - 8rpx);
}
&.row1-of3 {
width: calc(33.333% - 10.67rpx);
}
&.row1-of4 {
width: calc(25% - 12rpx);
}
/* #endif */
}
// 1 列布局
&.row1-of1 {
.uni-scroll-view-content {
// #ifndef MP-WEIXIN
grid-template-columns: 1fr;
// #endif
}
}
// 2 列布局
&.row1-of2 {
.uni-scroll-view-content {
// #ifndef MP-WEIXIN
grid-template-columns: repeat(2, 1fr);
// #endif
}
}
// 3 列布局
&.row1-of3 {
.uni-scroll-view-content {
// #ifndef MP-WEIXIN
grid-template-columns: repeat(3, 1fr);
// #endif
}
}
// 4 列布局
&.row1-of4 {
.uni-scroll-view-content {
// #ifndef MP-WEIXIN
grid-template-columns: repeat(4, 1fr);
// #endif
}
}
}
/**
* 确保所有视频卡片高度一致
*/
.channel-item,
.channel-nav-item {
display: flex;
flex-direction: column;
}
/**
* 轮播样式
* 支持轮播模式的布局和样式
*/
.channel-swiper {
width: 100%;
box-sizing: border-box;
.swiper-slide-content {
display: grid;
grid-template-columns: repeat(var(--row-count, 2), 1fr);
gap: 16rpx;
box-sizing: border-box;
.channel-item {
display: flex;
flex-direction: column;
box-sizing: border-box;
}
// 轮播模式下的 1 列布局
&.row1-of1 {
grid-template-columns: 1fr;
}
// 轮播模式下的 2 列布局
&.row1-of2 {
grid-template-columns: repeat(2, 1fr);
}
// 轮播模式下的 3 列布局
&.row1-of3 {
grid-template-columns: repeat(3, 1fr);
}
// 轮播模式下的 4 列布局
&.row1-of4 {
grid-template-columns: repeat(4, 1fr);
}
}
}
/**
* 响应式调整
* 在小屏幕设备上调整布局和间距
*/
@media (max-width: 375px) {
.channel-list,
.channel-nav,
.channel-swiper .swiper-slide-content {
gap: 12rpx;
padding: 12rpx;
}
// 小屏幕上的单滑动模式
.channel-nav {
&.singleSlide {
.uni-scroll-view-content {
gap: 12rpx;
}
.channel-nav-item {
width: 240rpx;
}
}
}
}
/**
* 视频比例样式调整
* 根据不同的视频比例调整布局
*/
// // 3:4 比例的视频卡片样式
// .channel-video.ratio-3-4 {
// // 调整视频卡片的整体高度
// ::v-deep .video-cover-wrap {
// padding-top: 133.33%; // 3:4 比例
// }
// // 列表模式下的3:4比例调整
// &.list-mode {
// ::v-deep .video-cover-wrap {
// padding-top: 133.33%; // 3:4 比例
// }
// }
// }
// // 16:9 比例的视频卡片样式(默认)
// .channel-video.ratio-16-9 {
// // 保持默认的16:9比例
// ::v-deep .video-cover-wrap {
// padding-top: 56.25%; // 16:9 比例
// }
// // 列表模式下的16:9比例保持默认
// &.list-mode {
// ::v-deep .video-cover-wrap {
// padding-top: 56.25%; // 16:9 比例
// }
// }
// }</style>

View File

@@ -1,488 +0,0 @@
<template>
<view class="channel-video" :class="{ 'list-mode': listMode }">
<!-- 嵌入式视频播放 -->
<view v-if="canUseEmbedMode" class="embed-video-container">
<view class="video-cover-wrap" :style="[coverStyle]">
<!-- #ifdef MP-WEIXIN -->
<native-component>
<!-- 嵌入式视频播放组件 -->
<channel-video :feed-id="value.feedId" :finder-user-name="value.finderUserName"
:feed-token="value.feedToken" :auto-play="autoPlay">
</channel-video>
</native-component>
<!-- #endif -->
</view>
<view class="video-info">
<!-- 视频标题,支持多行显示控制 -->
<view class="video-title" :style="[{ '--title-line-clamp': titleLineClamp }]">{{ value.videoTitle }}
</view>
<!-- 视频统计信息 -->
<view class="video-stats" v-if="showViewCount && value.showViewCount">{{ value.viewCount }}次观看</view>
</view>
</view>
<!-- 跳转式视频播放 -->
<view v-else @tap.stop="playVideo" class="video-container">
<view class="video-cover-wrap" :style="[coverStyle]">
<image class="video-cover" :src="$util.img(value.coverUrl)" mode="aspectFill" show-menu-by-longpress></image>
<view class="channel-play-btn" v-if="showPlayBtn" :style="[playBtnStyle]">
<view class="play-icon-css"></view>
</view>
<view class="video-stats-overlay" v-if="showViewCount && value.showViewCount">
{{ value.viewCount }}次观看
</view>
</view>
<view class="video-info">
<!-- 视频标题,支持多行显示控制 -->
<view class="video-title" :style="[{ '--title-line-clamp': titleLineClamp }]">{{ value.videoTitle }}
</view>
<!-- 视频统计信息,非列表模式下显示 -->
<view class="video-stats" v-if="showViewCount && value.showViewCount && !listMode">{{ value.viewCount }}次观看</view>
</view>
</view>
</view>
</template>
<script>
import { wechatChannelUtil, wechatChannelConfig } from './js/wechat-channel.js'
/**
* 微信视频号视频卡片组件
* 支持嵌入式播放和跳转式播放两种模式
* 可配置列表模式、视频高度、标题行数等属性
*/
export default {
name: 'diy-channel-video',
props: {
/**
* 视频数据对象
* @type {Object}
* @required
* @property {string} feedId - 视频 feedId
* @property {string} feedToken - 视频 token
* @property {string} coverUrl - 视频封面图
* @property {string} videoTitle - 视频标题
* @property {number} viewCount - 观看次数
* @property {boolean} showViewCount - 是否显示观看次数
* @property {boolean} embedMode - 是否启用嵌入式播放
*/
value: {
type: Object,
required: true
},
/**
* 是否为列表模式
* @type {boolean}
* @default false
*/
listMode: {
type: Boolean,
default: false
},
/** 是否显示观看次数,由父组件可以整体配置 */
showViewCount: {
type: Boolean,
default: true
},
/**
* 标题显示行数
* @type {number}
* @default 1
*/
titleLineClamp: {
type: Number,
default: 1
},
/** 是否显示播放按钮 */
showPlayBtn: {
type: Boolean,
default: true
},
/**
* 视频封面图样式
* 采用 16:9 比例的响应式高度
*/
coverStyle: {
type: Object,
default: () => ({
width: '100%',
height: '0',
paddingTop: '56.25%' // 16:9 比例
})
},
/**
* 播放按钮样式
*/
playBtnStyle: {
type: Object,
default: () => ({
width: '60rpx',
height: '60rpx',
borderRadius: '30rpx',
backgroundColor: 'rgba(0, 0, 0, 0.6)'
})
},
/** 是否自动播放 */
autoPlay: {
type: Boolean,
default: false
},
},
computed: {
/**
* 是否支持嵌入式播放
* @returns {boolean}
*/
canUseEmbedMode() {
// #ifdef MP-WEIXIN
const enableEmbedMode = Boolean(this.value?.embedMode)
&& Boolean(this.value?.feedToken)
&& wechatChannelUtil.isEmbedModeSupported();
return enableEmbedMode;
// #endif
return false
}
},
methods: {
/**
* 播放视频
* 触发 video-play 事件,由父组件处理具体播放逻辑
*/
async playVideo() {
this.$emit('video-play', this.value);
}
}
};
</script>
<style scoped lang="scss">
@import './css/common-channel.scss';
/**
* 视频卡片容器样式
* 包含卡片基础样式、悬停效果和列表模式样式
*/
.channel-video {
position: relative;
background-color: #fff;
border-radius: 12rpx;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
flex-direction: column;
height: 100%;
// 悬停效果
&:hover {
transform: translateY(-4rpx);
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
}
// 列表模式样式调整
&.list-mode {
border-radius: 10rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.08);
.video-info {
padding: 14rpx;
.video-title {
font-size: 24rpx;
margin-bottom: 6rpx;
}
}
}
}
/**
* 视频容器样式
* 用于跳转式播放模式
*/
.video-container {
display: flex;
flex-direction: column;
height: 100%;
}
/**
* 嵌入式视频容器样式
* 与视频容器样式保持一致
*/
.embed-video-container {
display: flex;
flex-direction: column;
height: 100%;
}
/**
* 视频封面容器
*/
.video-cover-wrap {
position: relative;
width: 100%;
padding-top: 56.25%;
/* 16:9 比例 */
height: 0;
overflow: hidden;
border-radius: 12rpx 12rpx 0 0;
transition: transform 0.3s ease;
// 悬停时缩放效果
.channel-video:hover & {
transform: scale(1.02);
}
// 列表模式下的边框圆角调整
.channel-video.list-mode & {
border-radius: 10rpx 10rpx 0 0;
}
}
/**
* 视频封面图片
* 绝对定位填充整个容器
*/
.video-cover {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
/**
* 视频统计信息遮罩
* 显示在视频封面底部
*/
.video-stats-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
padding: 12rpx 16rpx;
color: #fff;
font-size: 20rpx;
text-align: right;
font-weight: 500;
transition: opacity 0.3s ease;
// 悬停时的透明度变化
.channel-video:hover & {
opacity: 1;
}
.channel-video:not(:hover) & {
opacity: 0.8;
}
}
/**
* 视频信息区域
* 包含标题和统计信息
*/
.video-info {
padding: 16rpx;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
background-color: #fff;
transition: background-color 0.3s ease;
// 悬停时的背景色变化
.channel-video:hover & {
background-color: #fafafa;
}
}
/**
* 视频标题
* 支持多行显示控制和渐变遮罩效果
*/
.video-title {
font-size: 28rpx;
font-weight: 600;
color: #222;
margin-bottom: 10rpx;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: var(--title-line-clamp, 2);
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
transition: color 0.3s ease;
position: relative;
word-break: break-all;
word-wrap: break-word;
white-space: normal;
// 悬停时的颜色变化
.channel-video:hover & {
color: #000;
}
// 列表模式下的样式调整
.channel-video.list-mode & {
-webkit-line-clamp: var(--title-line-clamp, 1);
font-size: 24rpx;
margin-bottom: 6rpx;
font-weight: 500;
color: #333;
line-height: 1.3;
}
// 添加渐变遮罩效果,让过长的文字有柔和的结束
&::after {
content: '';
position: absolute;
bottom: 0;
right: 0;
width: 40rpx;
height: 1.4em;
background: linear-gradient(to right, transparent, #fff 90%);
pointer-events: none;
}
// 列表模式下的遮罩高度调整
.channel-video.list-mode &::after {
height: 1.3em;
}
// 根据行数调整遮罩高度
&[style*="--title-line-clamp: 1"]::after {
height: 1.4em;
}
&[style*="--title-line-clamp: 3"]::after {
height: 4.2em;
}
&[style*="--title-line-clamp: 4"]::after {
height: 5.6em;
}
// 列表模式下的多行遮罩高度调整
.channel-video.list-mode &[style*="--title-line-clamp: 1"]::after {
height: 1.3em;
}
.channel-video.list-mode &[style*="--title-line-clamp: 3"]::after {
height: 3.9em;
}
.channel-video.list-mode &[style*="--title-line-clamp: 4"]::after {
height: 5.2em;
}
}
/**
* 视频统计信息
* 显示观看次数等数据
*/
.video-stats {
font-size: 22rpx;
color: #999;
margin-top: 6rpx;
transition: color 0.3s ease;
// 悬停时的颜色变化
.channel-video:hover & {
color: #666;
}
}
/**
* 列表模式下的播放按钮样式
* 更小的尺寸和悬停效果
*/
.channel-video.list-mode .channel-play-btn {
width: 50rpx;
height: 50rpx;
background-color: rgba(0, 0, 0, 0.5);
transition: all 0.3s ease;
// 悬停效果
&:hover {
background-color: rgba(0, 0, 0, 0.7);
transform: scale(1.1);
}
// 播放图标尺寸
.play-icon {
width: 25rpx;
height: 25rpx;
}
}
/**
* 通用播放按钮样式优化
* 添加悬停效果
*/
.channel-play-btn {
transition: all 0.3s ease;
// 悬停效果
&:hover {
background-color: rgba(0, 0, 0, 0.6);
transform: scale(1.05);
}
}
/**
* 纯 CSS 播放按钮图标
*/
.play-icon-css {
width: 0;
height: 0;
border-top: 12rpx solid transparent;
border-bottom: 12rpx solid transparent;
border-left: 18rpx solid #fff;
margin-left: 4rpx;
transition: transform 0.3s ease;
// 悬停时的缩放效果
.channel-play-btn:hover & {
transform: scale(1.1);
}
// 列表模式下的尺寸调整
.channel-video.list-mode & {
border-top: 10rpx solid transparent;
border-bottom: 10rpx solid transparent;
border-left: 15rpx solid #fff;
margin-left: 3rpx;
}
}
/**
* 原生组件样式控制
* 确保 native-component 和 channel-video 正确填充容器
*/
native-component {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
/**
* channel-video 组件样式控制
* 避免受到 wx-channel-video 全局样式的影响
*/
channel-video {
width: 100%;
height: 100%;
min-width: 100%;
min-height: 100%;
max-width: 100%;
max-height: 100%;
object-fit: cover;
}
</style>

View File

@@ -16,7 +16,7 @@
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style1-bg.png') + ')',
marginRight: couponItemHeight + 'px',
marginLeft: couponItemHeight + 'px'
}" @tap.stop="couponAction(item, index)">
}" @click="couponAction(item, index)">
<view class="coupon-info">
<view class="coupon-num" :style="{ color: value.moneyColor }"
@@ -52,7 +52,7 @@
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_bg1.png') + ')',
marginRight: couponItemHeight + 'px',
marginLeft: couponItemHeight + 'px'
}" @tap.stop="couponAction(item, index)">
}" @click="couponAction(item, index)">
<view class="coupon-info">
<view class="coupon-num" :style="{ color: value.moneyColor }"
v-if="!parseInt(item.discount)">
@@ -87,7 +87,7 @@
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_shu.png') + ')',
marginRight: couponItemHeight + 'px',
marginLeft: couponItemHeight + 'px'
}" @tap.stop="couponAction(item, index)">
}" @click="couponAction(item, index)">
<view class="coupon-num" :style="{ color: value.moneyColor }"
v-if="!parseInt(item.discount)">
<text class="font-size-tag coupon-sign">¥</text>
@@ -124,7 +124,7 @@
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style4_bg.png') + ')',
marginRight: couponItemHeight + 'px',
marginLeft: couponItemHeight + 'px'
}" @tap.stop="couponAction(item, index)">
}" @click="couponAction(item, index)">
<view class="coupon-info">
<view class="coupon-num" :style="{ color: value.moneyColor }"
v-if="!parseInt(item.discount)">
@@ -153,7 +153,7 @@
<view class="coupon-all">
<view class="coupon-box">
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index"
@tap.stop="couponAction(item, index)">
@click="couponAction(item, index)">
<image :src="$util.img('public/uniapp/coupon/style5_bg.png')"></image>
<view class="coupon">
<view class="coupon-info">
@@ -199,7 +199,7 @@
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-1.png') + ')',
marginRight: couponItemHeight + 'px',
marginLeft: couponItemHeight + 'px'
}" @tap.stop="couponAction(item, index)">
}" @click="couponAction(item, index)">
<view class="coupon-content">
<view class="price-wrap">
<text class="price" :style="{ color: value.moneyColor }">{{ (item.discount == '0.00'
@@ -229,7 +229,7 @@
<text class="limit" :style="{ color: value.limitColor }" v-else>无门槛使用</text>
</view>
<div v-if="computedCouponList.length <= 2" @tap.stop="$util.redirectTo('/pages_goods/category')"
<div v-if="computedCouponList.length <= 2" @click="$util.redirectTo('/pages_goods/category')"
class="coupon coupon-null" :style="{
color: value.moneyColor,
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-2.png') + ')',
@@ -250,7 +250,7 @@
<scroll-view class="coupon-style-seven" scroll-x="true">
<view class="wrap">
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index"
@tap.stop="couponAction(item, index)">
@click="couponAction(item, index)">
<image :src="$util.img('public/uniapp/coupon/style7_bg.png')"></image>
<view class="coupon">
<view class="coupon-info">
@@ -454,7 +454,7 @@ export default {
}
});
} else {
this.$refs.login.open(this.$util.INDEX_PAGE_URL);
this.$refs.login.open('/pages/index/index');
this.couponBtnSwitch = false;
}
},
@@ -488,7 +488,7 @@ export default {
}
// 风格一
::v-deep .coupon-style-one {
/deep/.coupon-style-one {
height: 110rpx;
.coupon-item-box {
@@ -534,7 +534,7 @@ export default {
}
// 风格二
::v-deep .coupon-style-two {
/deep/.coupon-style-two {
height: 96rpx;
.coupon-item-box {
@@ -591,7 +591,7 @@ export default {
background-size: 100% 100%;
}
::v-deep .coupon-style-three {
/deep/.coupon-style-three {
height: 284rpx;
padding: 20rpx;
box-sizing: border-box;
@@ -638,7 +638,7 @@ export default {
}
// 风格四
::v-deep .coupon-style-four {
/deep/.coupon-style-four {
height: 108rpx;
.coupon-item-box {
@@ -997,7 +997,7 @@ export default {
}
//风格七
::v-deep .coupon-style-seven {
/deep/ .coupon-style-seven {
.wrap {
display: flex;
}
@@ -1075,7 +1075,7 @@ export default {
}
}
::v-deep .uni-scroll-view ::-webkit-scrollbar {
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
@@ -1084,7 +1084,7 @@ export default {
background: transparent;
}
::v-deep ::-webkit-scrollbar {
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;

View File

@@ -1,5 +1,5 @@
<template>
<view :style="componentStyle" data-component-name="diy-digit">
<view :style="componentStyle">
<scroll-view :class="['graphic-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle]"
:scroll-x="value.showStyle == 'singleSlide'">
<view class="uni-scroll-view-content">
@@ -38,10 +38,16 @@
</template>
<script>
import uvCountTo from '@/components/uv-count-to/uv-count-to.vue'
import nsLogin from '@/components/ns-login/ns-login.vue'
import DiyMinx from './minx.js'
// 自定义数字展示
export default {
name: 'diy-digit',
components: {
uvCountTo,
nsLogin
},
props: {
value: {
type: Object,
@@ -90,7 +96,8 @@ export default {
// 页面跳转
redirectTo(item) {
if (!item.wap_url || this.$util.getCurrRoute() != this.$util.MEMBER_PAGE_URL || this.storeToken) {
if (!item.wap_url || this.$util.getCurrRoute() != 'pages/member/index' || this.storeToken) {
console.log(item);
this.$util.diyRedirectTo(item);
} else {
this.$refs.login.open(item.wap_url);

View File

@@ -1,11 +1,11 @@
<template>
<view data-component-name="diy-fenxiao-goods-list" class="diy-fenxiao" v-if="list.length"
:class="['goods-list', value.template, value.style]" :style="goodsListWarpCss">
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)" show-menu-by-longpress/>
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)" />
</view>
<view class="info-wrap"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl || value.btnStyle.control">
@@ -32,14 +32,14 @@
background: value.btnStyle.theme == 'diy' ? 'linear-gradient(to right,' + value.btnStyle.bgColorStart + ',' + value.btnStyle.bgColorEnd + ')' : '',
color: value.btnStyle.theme == 'diy' ? value.btnStyle.textColor : '',
borderRadius: value.btnStyle.aroundRadius * 2 + 'rpx'
}" @tap.stop="followGoods(item, index)">
}" @click.stop="followGoods(item, index)">
关注
</view>
<view class="sale-btn" v-if="value.btnStyle.control && item.is_collect == 1" :style="{
background: value.btnStyle.theme == 'diy' ? 'linear-gradient(to right,' + value.btnStyle.bgColorStart + ',' + value.btnStyle.bgColorEnd + ')' : '',
color: value.btnStyle.theme == 'diy' ? value.btnStyle.textColor : '',
borderRadius: value.btnStyle.aroundRadius * 2 + 'rpx'
}" @tap.stop="delFollowTip(item, index)">
}" @click.stop="delFollowTip(item, index)">
取消关注
</view>
</view>
@@ -75,7 +75,7 @@ export default {
this.currentRoute = '/' + currentPage.route;
if (!this.storeToken) {
this.$util.redirectTo(
this.$util.LOGIN_PAGE_URL,
'/pages_tool/login/login',
{
back: this.currentRoute
},
@@ -337,7 +337,7 @@ export default {
width: calc(50% - 10rpx);
&:nth-child(2n + 2) {
width: calc(50% - 10rpx);
width: calc(50% - 11rpx);
margin-right: 0;
}

View File

@@ -3,10 +3,10 @@
:class="{ left_top: value.bottomPosition == 1, right_top: value.bottomPosition == 2, left_bottom: value.bottomPosition == 3, right_bottom: value.bottomPosition == 4 }"
:style="style">
<block v-for="(item, index) in value.list" :key="index">
<view class="button-box" @tap.stop="$util.diyRedirectTo(item.link)"
<view class="button-box" @click="$util.diyRedirectTo(item.link)"
:style="{ width: value.imageSize + 'px', height: value.imageSize + 'px', fontSize: value.imageSize + 'px' }">
<image v-if="!item.iconType || item.iconType == 'img'" :src="$util.img(item.imageUrl)" mode="aspectFit"
show-menu-by-longpress />
:show-menu-by-longpress="true" />
<diy-icon v-else-if="item.iconType && item.iconType == 'icon'" :icon="item.icon"
:value="item.style ? item.style : null"></diy-icon>
</view>

View File

@@ -33,7 +33,7 @@
</view>
</view>
</view>
<view @tap.stop="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
<view @click="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
</view>
</template>

View File

@@ -8,8 +8,8 @@
<view class="ul-wrap">
<view class="li-item" v-for="(item, index) in list" :key="index">
<image class="brand-pic" :src="$util.img(item.image_url)" mode="aspectFit"
@tap.stop="handlerClick(item)" @error="imgError(index)"
:style="itemCss" show-menu-by-longpress/>
@click="handlerClick(item)" @tap="handlerClick(item)" @error="imgError(index)"
:style="itemCss" />
</view>
</view>
</view>
@@ -19,6 +19,8 @@
<script>
// 商品品牌
import uniGrid from '@/components/uni-grid/uni-grid.vue';
import uniGridItem from '@/components/uni-grid-item/uni-grid-item.vue';
import DiyMinx from './minx.js'
// 自定义商品品牌展示
@@ -29,6 +31,10 @@ export default {
type: Object
}
},
components: {
uniGrid,
uniGridItem
},
data() {
return {
list: [],

View File

@@ -2,14 +2,13 @@
<x-skeleton data-component-name="diy-goods-list" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
<view :class="['goods-list', goodsValue.template, goodsValue.style]" :style="goodsListWarpCss">
<template v-if="goodsValue.template != 'horizontal-slide'">
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
@tap="handlerClick(item)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
<view class="goods-img-wrap">
<image class="goods-img"
:src="$util.img(item.goods_image, { size: goodsValue.template == 'large-mode' ? 'big' : 'mid' })"
mode="widthFix" @error="imgError(index)"
:style="{ borderRadius: goodsValue.imgAroundRadius * 2 + 'rpx' }"
show-menu-by-longpress />
:style="{ borderRadius: goodsValue.imgAroundRadius * 2 + 'rpx' }" />
<view class="sell-out" v-if="item.stock <= 0">
<text class="iconfont icon-shuqing"></text>
</view>
@@ -49,9 +48,9 @@
<view class="member-price"
v-if="(item.member_price && item.member_price == showPrice(item)) || item.promotion_type == 1">
<image v-if="item.member_price && item.member_price == showPrice(item)"
:src="$util.img('public/uniapp/index/VIP.png')" show-menu-by-longpress />
:src="$util.img('public/uniapp/index/VIP.png')" />
<image v-else-if="item.promotion_type == 1"
:src="$util.img('public/uniapp/index/discount.png')" show-menu-by-longpress />
:src="$util.img('public/uniapp/index/discount.png')" />
</view>
<view v-if="goodsValue.priceStyle.lineControl && showMarketPrice(item)"
class="delete-price price-font"
@@ -71,7 +70,7 @@
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : '',
borderColor: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : ''
}" class="cart shopping-cart-btn iconfont icon-gouwuche click-wrap" :id="'goods-' + item.id"
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
<view class="click-event"></view>
</view>
@@ -80,7 +79,7 @@
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : '',
borderColor: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : ''
}" class="cart plus-sign-btn iconfont icon-add1 click-wrap" :id="'goods-' + item.id"
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
<view class="click-event"></view>
</view>
@@ -91,7 +90,7 @@
fontWeight: goodsValue.btnStyle.theme == 'diy' ? (goodsValue.btnStyle.fontWeight ? 'bold' : 'normal') : '',
padding: goodsValue.btnStyle.theme == 'diy' ? '0 ' + goodsValue.btnStyle.padding * 2 + 'rpx' : ''
}" class="cart buy-btn click-wrap" :id="'goods-' + item.id"
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
{{ goodsValue.btnStyle.text }}
<view class="click-event"></view>
<!-- <text class="cart-num" v-if="cartList['goods_' + item.goods_id]">{{ cartList['goods_' + item.goods_id].num }}</text> -->
@@ -101,7 +100,7 @@
<view v-else-if="goodsValue.btnStyle.style == 'icon-diy'" :style="{
color: goodsValue.btnStyle.theme == 'diy' ? goodsValue.btnStyle.textColor : ''
}" class="icon-diy click-wrap" :id="'goods-' + item.id"
@tap.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
@click.stop="$refs.goodsSkuIndex.addCart(goodsValue.btnStyle.cartEvent, item, $event)">
<view class="click-event"></view>
<diy-icon :icon="goodsValue.btnStyle.iconDiy.icon"
:value="goodsValue.btnStyle.iconDiy.style ? goodsValue.btnStyle.iconDiy.style : null"></diy-icon>
@@ -113,12 +112,12 @@
</template>
<scroll-view v-if="goodsValue.template == 'horizontal-slide' && goodsValue.slideMode == 'scroll'"
class="scroll" :scroll-x="true">
<view class="goods-item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
@tap="handlerClick(item)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
<view class="goods-img-wrap">
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)"
:lazy-load="true" show-menu-by-longpress />
:lazy-load="true" />
<view class="sell-out" v-if="item.stock <= 0">
<text class="iconfont icon-shuqing"></text>
</view>
@@ -157,9 +156,9 @@
<view class="member-price"
v-if="(item.member_price && item.member_price == showPrice(item)) || item.promotion_type == 1">
<image v-if="item.member_price && item.member_price == showPrice(item)"
:src="$util.img('public/uniapp/index/VIP.png')" show-menu-by-longpress />
:src="$util.img('public/uniapp/index/VIP.png')" />
<image v-else-if="item.promotion_type == 1"
:src="$util.img('public/uniapp/index/discount.png')" show-menu-by-longpress />
:src="$util.img('public/uniapp/index/discount.png')" />
</view>
<view v-if="goodsValue.priceStyle.lineControl && showMarketPrice(item)"
class="delete-price price-font"
@@ -180,12 +179,12 @@
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
<view class="goods-item" v-for="(dataItem, dataIndex) in list[pageIndex]" :key="dataIndex"
@tap.stop="handlerClick(dataItem)"
@click="handlerClick(dataItem)" @tap="handlerClick(dataItem)"
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
<view class="goods-img-wrap">
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
@error="imgError(dataIndex)" :lazy-load="true" show-menu-by-longpress />
@error="imgError(dataIndex)" :lazy-load="true" />
<view class="sell-out" v-if="dataItem.stock <= 0">
<text class="iconfont icon-shuqing"></text>
</view>
@@ -227,9 +226,9 @@
v-if="(dataItem.member_price && dataItem.member_price == showPrice(dataItem)) || dataItem.promotion_type == 1">
<image
v-if="dataItem.member_price && dataItem.member_price == showPrice(dataItem)"
:src="$util.img('public/uniapp/index/VIP.png')" show-menu-by-longpress />
:src="$util.img('public/uniapp/index/VIP.png')" />
<image v-else-if="dataItem.promotion_type == 1"
:src="$util.img('public/uniapp/index/discount.png')" show-menu-by-longpress />
:src="$util.img('public/uniapp/index/discount.png')" />
</view>
<view v-if="goodsValue.priceStyle.lineControl && showMarketPrice(dataItem)"
class="delete-price"
@@ -254,12 +253,15 @@
</template>
<script>
import nsGoodsSkuIndex from '@/components/ns-goods-sku/ns-goods-sku-index.vue';
import DiyMinx from './minx.js'
import util from '@/common/js/util.js'
// 自定义商品列表展示
export default {
name: 'diy-goods-list',
components: {
nsGoodsSkuIndex
},
props: {
value: {
type: Object,
@@ -329,7 +331,7 @@ export default {
if (this.goodsValue.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.goodsValue.ornament.color + ';';
}
let screenWidth = util.getWindowInfo().windowWidth;
const screenWidth = uni.getSystemInfoSync().windowWidth;
if (this.value.template == 'horizontal-slide') {
var width = '';
if (this.value.slideMode == 'scroll' && this.value.goodsMarginType == 'diy') width = this.rpxUpPx(
@@ -409,7 +411,7 @@ export default {
}
},
rpxUpPx(res) {
const screenWidth = util.getWindowInfo().windowWidth;
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
@@ -1018,6 +1020,10 @@ export default {
width: calc(33.3333333% - 14rpx);
box-sizing: border-box;
&:nth-child(3n + 3) {
width: calc(33.33% - 15rpx);
}
&:nth-of-type(1),
&:nth-of-type(2),
&:nth-of-type(3) {

View File

@@ -13,11 +13,11 @@
<swiper-item v-for="(item, index) in page" :key="index"
:class="['swiper-item', [list[index].length / 3] >= 1 && 'flex-between']">
<view class="goods-item" v-for="(dataItem, dataIndex) in list[index]" :key="dataIndex"
@tap.stop="toDetail(dataItem)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
@click="toDetail(dataItem)" :class="[goodsValue.ornament.type]" :style="goodsItemCss">
<div class="goods-img-wrap">
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
@error="imgError(index, dataIndex)" :lazy-load="true" show-menu-by-longpress />
@error="imgError(index, dataIndex)" :lazy-load="true" />
<view class="sell-out" v-if="dataItem.stock <= 0">
<text class="iconfont icon-shuqing"></text>
</view>
@@ -33,7 +33,7 @@
<view class="label-wrap" v-if="goodsValue.labelStyle.support"
:style="{ background: goodsValue.labelStyle.bgColor, color: goodsValue.labelStyle.color }">
<image :src="$util.img('app/component/view/goods_recommend/img/label.png')"
mode="widthFix" show-menu-by-longpress />
mode="widthFix" />
<text>{{ goodsValue.labelStyle.title }}</text>
</view>
<view class="discount-price">

View File

@@ -9,13 +9,13 @@
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
:key="index"
v-if="index >= [(numItem) * (value.pageCount * value.rowCount)] && index < [(numItem + 1) * (value.pageCount * value.rowCount)]"
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
<!-- #endif -->
<!-- #ifdef H5 -->
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
:key="index"
v-if="index >= [(numItem - 1) * (value.pageCount * value.rowCount)] && index < [numItem * (value.pageCount * value.rowCount)]"
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
<!-- #endif -->
<view class="graphic-img" v-if="value.mode != 'text'"
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
@@ -23,7 +23,7 @@
:src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
mode="aspectFill"
:style="{ maxWidth: value.imageSize * 2 + 'rpx', maxHeight: value.imageSize * 2 + 'rpx', borderRadius: value.aroundRadius * 2 + 'rpx' }"
show-menu-by-longpress />
:show-menu-by-longpress="true" />
<diy-icon v-if="item.iconType == 'icon'" :icon="item.icon"
:value="item.style ? item.style : null"
@@ -62,14 +62,14 @@
<!-- #endif -->
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list" :key="index"
:style="{ width: 100 / value.rowCount + '%' }" @tap.stop="redirectTo(item.link)">
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
<view class="graphic-img" v-if="value.mode != 'text'"
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
<image v-if="item.iconType == 'img'"
:src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
mode="aspectFill"
:style="{ maxWidth: value.imageSize * 2 + 'rpx', maxHeight: value.imageSize * 2 + 'rpx', borderRadius: value.aroundRadius * 2 + 'rpx' }"
show-menu-by-longpress />
:show-menu-by-longpress="true" />
<diy-icon v-if="item.iconType == 'icon'" :icon="item.icon"
:value="item.style ? item.style : null"
:style="{ maxWidth: value.imageSize * 2 + 'rpx', maxHeight: value.imageSize * 2 + 'rpx', width: '100%', height: '100%' }"></diy-icon>
@@ -159,11 +159,12 @@ export default {
redirectTo(link) {
if (link.wap_url) {
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
this.$refs.login.open(link.wap_url);
return;
}
}
console.log(link)
this.$util.diyRedirectTo(link);
},
swiperChange(e) {

View File

@@ -251,16 +251,6 @@
<diy-icon :value="item"></diy-icon>
</template>
<template v-if="item.componentName == 'Tab'">
<!-- Tab 组件 -->
<diy-tab :value="item" :diyGlobal="diyGlobalData"></diy-tab>
</template>
<template v-if="['ChannelList', 'WechatChannel'].includes(item.componentName)">
<!-- 视频号列表 -->
<diy-channel-list :value="item"></diy-channel-list>
</template>
<!-- 自定义扩展组件 -->
<diy-comp-extend :value="item"></diy-comp-extend>
</view>
@@ -270,9 +260,8 @@
<script>
// 组件组展示
import DiyMinx from './minx.js'
export default {
name: 'diy-group',
components: {},
props: {
diyData: {
type: Object
@@ -317,12 +306,7 @@ export default {
this.diyGlobalData.value.forEach((item, index) => {
item.pageStyle = '';
// 给每个组件增加位置属性,用于定位,搜索、分类导航等定位
// 如果是Tab组件内部的子组件,添加tabIndex前缀避免moduleIndex冲突
if (this.diyData.tabIndex !== undefined) {
item.moduleIndex = `${this.diyData.tabIndex}-${index + 1}`;
} else {
item.moduleIndex = index + 1;
}
item.moduleIndex = index + 1;
// 特殊处理搜索框 当显示位置为滚动至顶部固定时,只设置背景颜色
if (item.componentName == 'Search' && item.positionWay == 'fixed') {
@@ -357,7 +341,6 @@ export default {
}
});
} else data = this.setPagestyle;
return data;
}
},

View File

@@ -2,12 +2,12 @@
<x-skeleton data-component-name="diy-groupbuy" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
<view class="diy-groupbuy" :class="[value.template, value.style]" :style="warpCss">
<template v-if="value.template == 'row1-of1'">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress>
@error="imageError(index)">
</image>
</view>
<view class="content"
@@ -39,12 +39,12 @@
</template>
<template v-if="value.template == 'horizontal-slide'">
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
<image class="bg" v-if="value.saleStyle.control"
:src="$util.img('public/uniapp/groupbuy/bg.png')" mode="widthFix" />
<view class="num" v-if="value.saleStyle.control"
@@ -81,11 +81,11 @@
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(dataIndex)" show-menu-by-longpress/>
@error="imageError(dataIndex)" />
<image class="bg" v-if="value.saleStyle.control"
:src="$util.img('public/uniapp/groupbuy/bg.png')" mode="widthFix" />
<view class="num" v-if="value.saleStyle.control"
@@ -274,7 +274,7 @@ export default {
</script>
<style lang="scss">
::v-deep .uni-scroll-view ::-webkit-scrollbar {
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
@@ -283,7 +283,7 @@ export default {
background: transparent;
}
::v-deep ::-webkit-scrollbar {
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;

View File

@@ -2,14 +2,14 @@
<view data-component-name="diy-hot-area" :style="hotAreaWarp" class="hot-area-box">
<view class="simple-graph-wrap">
<image :style="{ height: value.imgHeight }" :src="$util.img(value.imageUrl)" mode="widthFix"
show-menu-by-longpress />
:show-menu-by-longpress="true" />
<!-- 热区功能 -->
<view class="heat-map" v-for="(mapItem, mapIndex) in value.heatMapData" :key="mapIndex" :style="{
width: mapItem.width + '%',
height: mapItem.height + '%',
left: mapItem.left + '%',
top: mapItem.top + '%'
}" @tap.stop="$util.diyRedirectTo(mapItem.link)"></view>
}" @click.stop="$util.diyRedirectTo(mapItem.link)"></view>
</view>
</view>
</template>

View File

@@ -15,12 +15,12 @@
'width': (item.imgWidth / 2 + 'rpx') + ';',
'height': (item.imgHeight / 2 + 'rpx') + ';'
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
show-menu-by-longpress @tap.stop="redirectTo(item.link)"></image>
:show-menu-by-longpress="true" @tap="redirectTo(item.link)"></image>
<image v-else :style="{
'width': (item.imgWidth / 2 + 'rpx') + ';',
'height': (item.imgHeight / 2 + 'rpx') + ';'
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
show-menu-by-longpress @tap.stop="previewImg(item.imageUrl)"></image>
:show-menu-by-longpress="true" @tap="previewImg(item.imageUrl)"></image>
</view>
<!-- 文字部分 -->
@@ -38,11 +38,14 @@
</template>
<script>
import nsLogin from '@/components/ns-login/ns-login.vue'
import DiyMinx from './minx.js'
export default {
name: 'diy-image-nav',
components: {
nsLogin
},
props: {
value: {
type: Object,
@@ -103,9 +106,20 @@ export default {
}
},
methods: {
// 预览图片
previewImg(imageUrl) {
uni.previewImage({
current: 0,
urls: [this.$util.img(imageUrl)],
success: (res) => { },
fail: (res) => { },
complete: (res) => { }
});
},
// 页面跳转
redirectTo(link) {
if (!link.wap_url || this.$util.getCurrRoute() != this.$util.MEMBER_PAGE_URL || this.storeToken) {
if (!link.wap_url || this.$util.getCurrRoute() != 'pages/member/index' || this.storeToken) {
this.$util.diyRedirectTo(link);
} else {
this.$refs.login.open(link.wap_url);

View File

@@ -2,9 +2,10 @@
<view data-component-name="diy-img-ads" class="single-graph">
<view :style="imgAdsMarginWarp" class="swiper-box">
<block v-if="imgAdsValue.list.length == 1">
<view class="simple-graph-wrap" :style="imgAdsSwiper" @tap.stop="handlerClick(imgAdsValue.list[0].link)">
<view class="simple-graph-wrap" :style="imgAdsSwiper" @click="handlerClick(imgAdsValue.list[0].link)"
@tap="handlerClick(imgAdsValue.list[0].link)">
<image :style="{ height: imgAdsValue.list[0].imgHeight }"
:src="$util.img(imgAdsValue.list[0].imageUrl)" mode="widthFix" show-menu-by-longpress />
:src="$util.img(imgAdsValue.list[0].imageUrl)" mode="widthFix" :show-menu-by-longpress="true" />
</view>
</block>
<swiper v-else class="swiper" :style="{ height: swiperHeight }" :class="{
@@ -15,10 +16,10 @@
indicator-color="rgba(130, 130, 130, .5)" :indicator-active-color="imgAdsValue.indicatorColor"
@change="swiperChange">
<swiper-item class="swiper-item" :style="imgAdsSwiper" v-for="(item, index) in imgAdsValue.list"
:key="index" v-if="item.imageUrl" @tap.stop="handlerClick(item.link)">
:key="index" v-if="item.imageUrl" @click="handlerClick(item.link)" @tap="handlerClick(item.link)">
<view class="item" :style="imgAdsSwiper + 'height: ' + item.imgHeight">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
show-menu-by-longpress />
:show-menu-by-longpress="true" />
</view>
</swiper-item>
</swiper>
@@ -279,39 +280,39 @@ export default {
}
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
::v-deep .uni-scroll-view::-webkit-scrollbar {
/deep/.uni-scroll-view::-webkit-scrollbar {
display: none;
}
.swiper ::v-deep .uni-swiper-dots-horizontal {
.swiper /deep/ .uni-swiper-dots-horizontal {
bottom: 25rpx;
}
.swiper-left ::v-deep .uni-swiper-dots-horizontal {
.swiper-left /deep/ .uni-swiper-dots-horizontal {
left: 40rpx;
transform: translate(0);
}
.swiper-right ::v-deep .uni-swiper-dots-horizontal {
.swiper-right /deep/ .uni-swiper-dots-horizontal {
right: 40rpx;
display: flex;
justify-content: flex-end;
transform: translate(0);
}
.carousel-angle ::v-deep .uni-swiper-dots-horizontal .uni-swiper-dot {
.carousel-angle /deep/ .uni-swiper-dots-horizontal .uni-swiper-dot {
width: 24rpx;
border-radius: 0;
height: 8rpx;
}
.swiper.ns-indicator-dots ::v-deep .uni-swiper-dot {
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot {
width: 18rpx;
height: 6rpx;
border-radius: 4rpx;
}
.swiper.ns-indicator-dots ::v-deep .uni-swiper-dot-active {
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot-active {
width: 36rpx;
}
</style>

View File

@@ -8,7 +8,7 @@
:style="{ background: value.backgroundColor ? value.backgroundColor : '', width: 'calc(100% - 48rpx)' }"
@touchmove.stop>
<view class="item" :id="'a' + index" v-for="(item, index) in cateList" :key="index"
@tap.stop="changePageIndex(index)" :class="{ fill: value.styleType == 'fill' }"
@click="changePageIndex(index)" :class="{ fill: value.styleType == 'fill' }"
:style="{ background: index == pageIndex && value.styleType == 'fill' ? value.selectColor : '' }">
<view class="text-con" :class="index == pageIndex ? 'active' : ''" :style="{
color: index == pageIndex ? '' : value.noColor
@@ -25,13 +25,13 @@
</view>
</scroll-view>
<text class="iconfont icon-unfold unfold-arrows" :style="{ color: value.moreColor }"
@tap.stop="unfoldMenu"></text>
@click="unfoldMenu"></text>
</view>
<uni-popup ref="navTopCategoryPop" type="top" :top="uniPopTop">
<view class="nav-topcategory-pop">
<text v-for="(item, index) in cateList" :key="index"
:class="['category-item', { 'color-base-text color-base-border active': pageIndex == index }]"
@tap.stop="changePageIndex(index)">
@click="changePageIndex(index)">
{{ item.short_name ? item.short_name : item.category_name }}
</text>
</view>
@@ -55,12 +55,12 @@
<view class="twoCategory min" v-if="twoCategorylist.length <= 5">
<view class="twoCategory-page">
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
:key="index" @tap.stop="toCateGoodsList(item.category_id_2, 2)">
:key="index" @click="toCateGoodsList(item.category_id_2, 2)">
<view class="item-box">
<image :src="$util.img(item.image)" v-if="item.image"
mode="aspectFill" show-menu-by-longpress/>
mode="aspectFill" />
<image :src="$util.getDefaultImage().goods" v-else
mode="aspectFill" show-menu-by-longpress/>
mode="aspectFill" />
<view>{{ item.category_name }}</view>
</view>
</view>
@@ -70,12 +70,12 @@
v-if="twoCategorylist.length > 5 && twoCategorylist.length <= 10">
<view class="twoCategory-page">
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
:key="index" @tap.stop="toCateGoodsList(item.category_id_2, 2)">
:key="index" @click="toCateGoodsList(item.category_id_2, 2)">
<view class="item-box">
<image :src="$util.img(item.image)" v-if="item.image"
mode="aspectFill" show-menu-by-longpress/>
mode="aspectFill" />
<image :src="$util.getDefaultImage().goods" v-else
mode="aspectFill" show-menu-by-longpress/>
mode="aspectFill" />
<view>{{ item.category_name }}</view>
</view>
</view>
@@ -86,9 +86,9 @@
<swiper-item class="twoCategory-page" v-for="page in maxPage" :key="page">
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
:key="index" v-if="index >= (page - 1) * 10 && index < page * 10"
@tap.stop="toCateGoodsList(item.category_id_2, 2)">
@click="toCateGoodsList(item.category_id_2, 2)">
<view class="item-box">
<image :src="item.image" mode="aspectFill" show-menu-by-longpress/>
<image :src="item.image" mode="aspectFill" />
<view>{{ item.category_name }}</view>
</view>
</view>
@@ -104,19 +104,19 @@
<!-- 分类广告 -->
<image class="category_adv" v-if="cateList[pageIndex].image_adv"
:src="$util.img(cateList[pageIndex].image_adv)" mode="widthFix" show-menu-by-longpress/>
:src="$util.img(cateList[pageIndex].image_adv)" mode="widthFix" />
<view class="goods-list double-column" v-if="goodsList[pageIndex].list.length">
<view class="goods-item" v-for="(item, index) in goodsList[pageIndex].list"
:key="index" @tap.stop="toDetail(item)">
:key="index" @click="toDetail(item)">
<view class="goods-img">
<image :src="goodsImg(item.goods_image)" mode="widthFix"
@error="imgError(index)" show-menu-by-longpress/>
@error="imgError(index)" />
<view class="color-base-bg goods-tag"
v-if="value.goodsTag == 'default' && goodsTag(item) != ''">{{
goodsTag(item) }}</view>
<view class="goods-tag-img" v-if="value.goodsTag == 'diy'">
<image :src="$util.img(value.tagImg.imageUrl)" show-menu-by-longpress/>
<image :src="$util.img(value.tagImg.imageUrl)" />
</view>
</view>
<view class="info-wrap">
@@ -133,11 +133,11 @@
<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" show-menu-by-longpress/>
mode="widthFix" />
</view>
<view class="member-price-tag" v-else-if="item.promotion_type == 1">
<image :src="$util.img('public/uniapp/index/discount.png')"
mode="widthFix" show-menu-by-longpress/>
mode="widthFix" />
</view>
</view>
<view class="pro-info">
@@ -169,6 +169,7 @@
</template>
<script>
import nsLoading from '@/components/ns-loading/ns-loading.vue';
import DiyMinx from './minx.js'
export default {
name: 'diy-index-page',
@@ -188,6 +189,9 @@ export default {
}
},
mixins: [DiyMinx],
components: {
nsLoading
},
data() {
return {
pageIndex: 0, //当前选中分类id
@@ -732,7 +736,7 @@ export default {
margin-top: 100rpx;
}
::v-deep .uni-scroll-view::-webkit-scrollbar {
/deep/.uni-scroll-view::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
}

View File

@@ -1,9 +1,9 @@
<template>
<view data-component-name="diy-kefu" class="diy-kefu" :style="style">
<view class="fui-list-group merchgroup" v-for="(item, index) in value.list" :key="index">
<view class="fui-list-group merchgroup" v-for="(item, index) in value.list">
<view class="fui-list jump" v-if="index == 0">
<view class="fui-list-media">
<image class="round" :src="$util.img(item.imageUrl)" style="border-radius:6rpx" show-menu-by-longpress></image>
<image class="round" :src="$util.img(item.imageUrl)" style="border-radius:6rpx"></image>
</view>
<view class="fui-list-inner">
<view class="title" style="height: 75rpx;">
@@ -14,7 +14,7 @@
</view>
<view class="fui-remark jump" style="padding-right: 20rpx; text-align: center; line-height: 140rpx;">
<span style="font-size:24rpx;padding: 14rpx 18rpx;border-radius:8rpx"
:style="{ background: item.BtBgColor, color: item.BtColor }" @tap.stop="previewSqs()">立即添加</span>
:style="{ background: item.BtBgColor, color: item.BtColor }" @click="previewSqs()">立即添加</span>
</view>
</view>
</view>

View File

@@ -1,9 +1,9 @@
<template>
<view data-component-name="diy-listmenu" class="diy-listmenu" :style="style">
<view data-component-name="diy-picture" class="diy-picture" :style="style">
<view class="fui-cell-group">
<!-- <image mode="widthFix" style="width: 100%;" :src="$util.img(item.imageUrl)" show-menu-by-longpress></image> -->
<!-- <image mode="widthFix" style="width: 100%;" :src="$util.img(item.imageUrl)"></image> -->
<view v-for="(item, index) in value.list" @tap.stop="redirectTo(item.link)" class="fui-cell"
<view v-for="(item, index) in value.list" @click="redirectTo(item.link)" class="fui-cell"
:class="item.iconType == 'img' ? 'img-cell' : ''">
<view class="fui-cell-icon" :style="{ 'color': item.style ? item.style.iconColor : '#333' }">
<diy-icon v-if="item.iconType == 'icon'" :icon="item.icon" :value="item.style ? item.style : null"
@@ -62,8 +62,8 @@ export default {
methods: {
redirectTo(link) {
if (link.wap_url) {
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
this.$refs?.login?.open(link.wap_url);
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
this.$refs.login.open(link.wap_url);
return;
}
}

View File

@@ -1,6 +1,6 @@
<template>
<x-skeleton data-component-name="diy-live" type="banner" :loading="loading" :configs="skeletonConfig">
<view class="live-wrap" @tap.stop="handlerClick(liveInfo.roomid)"
<view class="live-wrap" @click="handlerClick(liveInfo.roomid)" @tap="handlerClick(liveInfo.roomid)"
v-if="liveInfo">
<view class="banner-wrap">
<image
@@ -25,7 +25,7 @@
<block v-if="value.isShowAnchorInfo">
<image
:src="liveInfo.anchor_img != '' ? $util.img(liveInfo.anchor_img) : $util.getDefaultImage().head"
class="anchor-img" @error="liveInfo.anchor_img = $util.getDefaultImage().head" show-menu-by-longpress/>
class="anchor-img" @error="liveInfo.anchor_img = $util.getDefaultImage().head" />
<text class="anchor-name">主播:{{ liveInfo.anchor_name }}</text>
</block>
<text class="separate" v-if="value.isShowAnchorInfo && value.isShowLiveGood">|</text>
@@ -109,6 +109,7 @@ export default {
}
})
.catch(err => {
console.log('get live status', err);
});
// 往后间隔1分钟或更慢的频率去轮询获取直播状态
@@ -126,7 +127,8 @@ export default {
clearInterval(timer);
}
})
.catch(err => {
.catch(err => {
console.log('get live status', err);
});
}, 60000);
// #endif

View File

@@ -3,7 +3,7 @@
<scroll-view scroll-x="true" class="many-goods-list-head" :scroll-into-view="'a' + cateIndex"
:style="manyWrapCss">
<view v-for="(item, index) in value.list" class="scroll-item" :class="{ active: index == cateIndex }"
:id="'a' + index" :key="index" @tap.stop="handlerClick({ item, index })">
:id="'a' + index" :key="index" @click="handlerClick({ item, index })" @tap="handlerClick({ item, index })">
<view class="split-line" v-if="index > 0"></view>
<view class="cate">
<view class="name" :style="{ color: value.headStyle.titleColor }">{{ item.title }}</view>

View File

@@ -3,18 +3,11 @@
<view class="fui-list-group merchgroup" style="margin-top:0" v-for="(item, index) in value.list">
<map id="map" style="width: 100%; height:600rpx" scale="12" :markers="markerst" bindupdated="bindupdated"
:longitude="item.lng" :latitude="item.lat" show-location>
<!-- <cover-view
<cover-view
style="position:absolute;right:10px;bottom:30rpx;z-index:99999;background:#4390FF;padding:5px 10px;wxcs_style_padding:10rpx 20rpx;border-radius:8rpx;color: #fff;"
@tap.stop="handlerClick(item)" @tap="handlerClick(item)">
@click="handlerClick(item)" @tap="handlerClick(item)">
<cover-view style="font-size:24rpx">一键导航</cover-view>
</cover-view> -->
<!-- 使用非原生cover-view, 解决原生cover-view组件渲染机制z-index失效的问题 -->
<div
style="position:absolute;right:12rpx;bottom:48rpx;z-index:1;background:#4390FF;padding:0rpx 20rpx;border-radius:8rpx;color: #fff;"
@tap.stop="handlerClick(item)">
<span style="font-size:24rpx;color: #fff;">一键导航</span>
</div>
</cover-view>
</map>
</view>

View File

@@ -4,18 +4,18 @@
<view class="common-wrap info-wrap" :class="[`data-style-${value.style}`]">
<view class="member-info" :style="memberInfoStyle">
<view class="info-wrap" :style="infoStyle" v-if="memberInfo">
<view class="headimg" @tap.stop="getWxAuth">
<view class="headimg" @click="getWxAuth">
<image :src="memberInfo.headimg ? $util.img(memberInfo.headimg) : $util.getDefaultImage().head"
mode="widthFix" @error="memberInfo.headimg = $util.getDefaultImage().head" show-menu-by-longpress/>
mode="widthFix" @error="memberInfo.headimg = $util.getDefaultImage().head" />
</view>
<view class="info">
<!-- #ifdef MP -->
<block
v-if="(memberInfo.nickname.indexOf('u_') != -1 && memberInfo.nickname == memberInfo.username) || memberInfo.nickname == memberInfo.mobile">
<view class="nickname"><text class="name" @tap.stop="getWxAuth">点击授权头像昵称</text></view>
<view class="nickname"><text class="name" @click="getWxAuth">点击授权头像昵称</text></view>
</block>
<view class="nickname" v-else>
<text class="name" @tap.stop="getWxAuth">{{ memberInfo.nickname }}</text>
<text class="name" @click="getWxAuth">{{ memberInfo.nickname }}</text>
<view class="member-level"
v-if="(value.style == 1 || value.style == 2) && memberInfo.member_level">
<!-- <text class="icondiy icon-system-huangguan"></text> -->
@@ -36,10 +36,10 @@
<!-- #ifdef H5 -->
<block
v-if="$util.isWeiXin() && ((memberInfo.nickname.indexOf('u_') != -1 && memberInfo.nickname == memberInfo.username) || memberInfo.nickname == memberInfo.mobile)">
<view class="nickname"><text class="name" @tap.stop="getWxAuth">点击获取微信头像</text></view>
<view class="nickname"><text class="name" @click="getWxAuth">点击获取微信头像</text></view>
</block>
<view class="nickname" v-else>
<text class="name" @tap.stop="redirect('/pages_tool/member/info')">{{ memberInfo.nickname
<text class="name" @click="redirect('/pages_tool/member/info')">{{ memberInfo.nickname
}}</text>
<view class="member-level"
v-if="(value.style == 1 || value.style == 2) && memberInfo.member_level">
@@ -61,12 +61,12 @@
</view>
<view v-if="ischina == 1"
style="background: #fff;height: 60rpx;width: 60rpx;border-radius: 50rpx;line-height:65rpx;text-align: center;color:#000"
@tap.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
@click.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
</view>
<view class="info-wrap" v-else :style="infoStyle" @tap.stop="redirect($util.MEMBER_PAGE_URL)">
<view class="info-wrap" v-else :style="infoStyle" @click="redirect('/pages/member/index')">
<view class="headimg">
<image :src="$util.getDefaultImage().head" mode="widthFix" show-menu-by-longpress></image>
<image :src="$util.getDefaultImage().head" mode="widthFix"></image>
</view>
<view class="info">
<view class="nickname"><text class="name">{{ $lang('login') }}</text></view>
@@ -75,12 +75,12 @@
<view v-if="ischina == 1"
style="background: #fff;height: 60rpx;width: 60rpx;border-radius: 50rpx;line-height:65rpx;text-align: center;color:#000"
@tap.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
@click.stop="modifyInfo()">{{ langIndex == 0 ? 'CN' : 'EN' }}</view>
</view>
<view class="account-info" v-show="value.style == 1"
:style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance')">
<view class="account-item" @click="redirect('/pages_tool/member/balance')">
<view class="value price-font">
{{ memberInfo ? (parseFloat(memberInfo.balance) +
parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}
@@ -88,12 +88,12 @@
<view class="title">{{ $lang('balance') }}</view>
</view>
<view class="solid"></view>
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}</view>
<view class="title">{{ $lang('point') }}</view>
</view>
<view class="solid"></view>
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
<view class="value price-font">
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
</view>
@@ -110,19 +110,19 @@
<text>超级会员</text>
</view>
<view class="super-text">
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">会员可享更多权益</text>
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">会员可享更多权益</text>
<text class="iconfont icon-right"></text>
</view>
</block>
<block v-if="value.style == 3">
<view class="super-info">
<image :src="$util.img('public/uniapp/member/open_member.png')" class="title" mode="heightFix" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/member/open_member.png')" class="title" mode="heightFix" />
<view class="desc">开通可享更多权益</view>
</view>
<view class="super-text">
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看特权</text>
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
</view>
</block>
</view>
@@ -130,29 +130,29 @@
<view class="member-info-style4" v-show="value.style == 4">
<view class="super-member" v-if="superMember" :style="superMemberStyle">
<view class="super-info">
<image :src="$util.img('app/component/view/member_info/img/style_4_vip_huangguan.png')" class="title" mode="widthFix" show-menu-by-longpress/>
<image :src="$util.img('app/component/view/member_info/img/style_4_vip_huangguan.png')" class="title" mode="widthFix" />
<view class="desc">开通可享更多权益</view>
</view>
<view class="super-text" :class="{ 'more' : memberInfo && memberInfo.member_level_type }">
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @tap.stop="redirectBeforeAuth('/pages_tool/member/card')">查看更多权益</text>
<text class="see" v-else @tap.stop="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
<text class="see" v-if="memberInfo && memberInfo.member_level_type" @click="redirectBeforeAuth('/pages_tool/member/card')">查看更多权益</text>
<text class="see" v-else @click="redirectBeforeAuth('/pages_tool/member/card_buy')">立即开通</text>
</view>
</view>
<view class="account-info" :style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance_detail')">
<view class="account-item" @click="redirect('/pages_tool/member/balance_detail')">
<view class="value price-font">
{{ memberInfo ? (parseFloat(memberInfo.balance) + parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}
</view>
<view class="title">余额</view>
</view>
<view class="solid"></view>
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}
</view>
<view class="title">积分</view>
</view>
<view class="solid"></view>
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
<view class="value price-font">
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
</view>
@@ -161,7 +161,7 @@
</view>
<view class="style4-other">
<view class="style4-btn-wrap">
<view @tap.stop="redirect('/pages_tool/recharge/list')" class="recharge-btn">余额充值</view>
<view @click="redirect('/pages_tool/recharge/list')" class="recharge-btn">余额充值</view>
</view>
</view>
</view> -->
@@ -169,18 +169,18 @@
<view class="account-info" v-show="value.style == 2"
:style="{ 'margin-left': parseInt(value.infoMargin) * 2 + 'rpx', 'margin-right': parseInt(value.infoMargin) * 2 + 'rpx' }">
<view class="account-item" @tap.stop="redirect('/pages_tool/member/balance')">
<view class="account-item" @click="redirect('/pages_tool/member/balance')">
<view class="value price-font">{{ memberInfo ? (parseFloat(memberInfo.balance) +
parseFloat(memberInfo.balance_money)).toFixed(2) : '--' }}</view>
<view class="title">{{ $lang('balance') }}</view>
</view>
<view class="solid"></view>
<view class="account-item" @tap.stop="redirect('/pages_tool/member/point_detail')">
<view class="account-item" @click="redirect('/pages_tool/member/point_detail')">
<view class="value price-font">{{ memberInfo ? parseFloat(memberInfo.point) : '--' }}</view>
<view class="title">{{ $lang('point') }}</view>
</view>
<view class="solid"></view>
<view class="account-item" @tap.stop="redirect('/pages_tool/member/coupon')">
<view class="account-item" @click="redirect('/pages_tool/member/coupon')">
<view class="value price-font">
{{ memberInfo && memberInfo.coupon_num != undefined ? memberInfo.coupon_num : '--' }}
</view>
@@ -196,14 +196,14 @@
<view class="head">
<text class="title">获取您的昵称、头像</text>
<text class="color-tip tips">获取用户头像、昵称完善个人资料,主要用于向用户提供具有辨识度的用户中心界面</text>
<text class="iconfont icon-close color-tip" @tap.stop="cancelCompleteInfo"></text>
<text class="iconfont icon-close color-tip" @click="cancelCompleteInfo"></text>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="item-wrap">
<text class="label">头像</text>
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<image :src="avatarUrl ? avatarUrl : $util.getDefaultImage().head"
@error="avatarUrl = $util.getDefaultImage().head" mode="aspectFill" show-menu-by-longpress/>
@error="avatarUrl = $util.getDefaultImage().head" mode="aspectFill" />
<text class="iconfont icon-right color-tip"></text>
</button>
</view>
@@ -218,7 +218,7 @@
<button open-type="getAuthorize" scope="userInfo" @getAuthorize="aliappGetUserinfo"
:plain="true" class="border-0">
<image :src="avatarUrl ? avatarUrl : $util.getDefaultImage().head"
@error="avatarUrl = $util.getDefaultImage().head" mode="aspectFill" show-menu-by-longpress/>
@error="avatarUrl = $util.getDefaultImage().head" mode="aspectFill" />
<text class="iconfont icon-right color-tip"></text>
</button>
</view>
@@ -227,7 +227,7 @@
<input type="nickname" placeholder="请输入昵称" v-model="nickName" @blur="blurNickName" />
</view>
<!-- #endif -->
<button type="default" class="save-btn" @tap.stop="saveCompleteInfo" :disabled="isDisabled">保存</button>
<button type="default" class="save-btn" @click="saveCompleteInfo" :disabled="isDisabled">保存</button>
</view>
</uni-popup>
</view>
@@ -243,7 +243,7 @@ let menuButtonInfo = {};
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// #endif
// 自定义会员中心——会员信息展示
import nsContact from '@/components/ns-contact/ns-contact.vue';
import DiyMinx from './minx.js'
export default {
name: 'diy-member-info',
@@ -259,6 +259,9 @@ export default {
}
},
mixins: [DiyMinx],
components: {
nsContact
},
data() {
return {
info: null,
@@ -545,7 +548,7 @@ export default {
*/
redirectBeforeAuth(url) {
if (!this.storeToken) {
this.$refs.login.open(this.$util.MEMBER_PAGE_URL);
this.$refs.login.open('/pages/member/index');
return;
}
@@ -583,7 +586,7 @@ export default {
url: '/wechat/api/wechat/authcode',
data: {
scopes: 'snsapi_userinfo',
redirect_url: this.$config.h5Domain + this.$util.MEMBER_PAGE_URL
redirect_url: this.$config.h5Domain + '/pages/member/index'
},
success: res => {
if (res.code >= 0) {
@@ -1380,11 +1383,11 @@ export default {
}
}
::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: none !important;
}
::v-deep .member-info-style4 .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
/deep/ .member-info-style4 .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: #fff !important;
}
@@ -1484,8 +1487,8 @@ export default {
}
</style>
<style scoped>
.member-complete-info-popup ::v-deep .uni-popup__wrapper.bottom,
.member-complete-info-popup ::v-deep .uni-popup__wrapper.bottom .uni-popup__wrapper-box {
.member-complete-info-popup /deep/ .uni-popup__wrapper.bottom,
.member-complete-info-popup /deep/ .uni-popup__wrapper.bottom .uni-popup__wrapper-box {
border-top-left-radius: 30rpx !important;
border-top-right-radius: 30rpx !important;
}

View File

@@ -2,11 +2,11 @@
<view data-component-name="diy-member-my-order" class="common-wrap" :style="warpCss">
<view class="order-wrap">
<view class="status-wrap">
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitpay')"
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitpay')"
style="margin-right: 10rpx;">
<view class="icon-block">
<template v-if="value.style == 3">
<image :src="$util.img('public/uniapp/member/order/wait_pay.png')" mode="widthFix" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/member/order/wait_pay.png')" mode="widthFix" />
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_pay_shade.png') + ')'">
</view>
@@ -21,11 +21,11 @@
</view>
<view class="title">{{ $lang('waitpay') }}</view>
</view>
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitsend')"
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitsend')"
style="margin-right: 10rpx;">
<view class="icon-block">
<template v-if="value.style == 3">
<image :src="$util.img('public/uniapp/member/order/wait_send.png')" mode="widthFix" show-menu-by-longpress></image>
<image :src="$util.img('public/uniapp/member/order/wait_send.png')" mode="widthFix"></image>
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_send_shade.png') + ')'">
</view>
@@ -40,11 +40,11 @@
</view>
<view class="title">{{ $lang('waitsend') }}</view>
</view>
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitconfirm')"
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitconfirm')"
style="margin-right: 10rpx;">
<view class="icon-block">
<template v-if="value.style == 3">
<image :src="$util.img('public/uniapp/member/order/wait_confirm.png')" mode="widthFix" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/member/order/wait_confirm.png')" mode="widthFix" />
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_confirm_shade.png') + ')'">
</view>
@@ -59,11 +59,11 @@
</view>
<view class="title">{{ $lang('waitconfirm') }}</view>
</view>
<view class="item-wrap" @tap.stop="redirect('/pages_order/list?status=waitrate')"
<view class="item-wrap" @click="redirect('/pages_order/list?status=waitrate')"
style="margin-right: 10rpx;">
<view class="icon-block">
<template v-if="value.style == 3">
<image :src="$util.img('public/uniapp/member/order/wait_use.png')" mode="widthFix" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/member/order/wait_use.png')" mode="widthFix" />
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_rate_shade.png') + ')'">
</view>
@@ -76,10 +76,10 @@
</view>
<view class="title">{{ $lang('completed') }}</view>
</view>
<view class="item-wrap" @tap.stop="redirect('/pages_tool/order/activist')">
<view class="item-wrap" @click="redirect('/pages_tool/order/activist')">
<view class="icon-block">
<template v-if="value.style == 3">
<image :src="$util.img('public/uniapp/member/order/refunding.png')" mode="widthFix" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/member/order/refunding.png')" mode="widthFix" />
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/refunding_shade.png') + ')'">
</view>

View File

@@ -4,10 +4,10 @@
<view class="merch-wrap" :style="warpCss">
<view :class="['list-wrap', value.style]" :style="warpCss">
<view :class="['item', value.ornament.type]" v-for="(item, index) in list" :key="index"
:style="itemCss" @tap.stop="handlerClick(item)">
:style="itemCss" @click="handlerClick(item)" @tap="handlerClick(item)">
<view class="merch-img">
<image class="cover-img" :src="$util.img(item.merch_image)" mode="widthFix"
@error="imgError(index)" show-menu-by-longpress />
@error="imgError(index)" />
</view>
<view class="info-wrap">
<text class="title">{{ item.merch_name }}</text>
@@ -25,12 +25,12 @@
<!-- #endif -->
<view class="merch-nav-item graphic" v-for="(item, index) in list" :key="index"
:style="{ width: 100 / 4 + '%' }" @tap.stop="handlerClick(item)">
:style="{ width: 100 / 4 + '%' }" @click="handlerClick(item)" @tap="handlerClick(item)">
<view class="graphic-img" v-if="value.mode != 'text'"
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
<image
:src="$util.img(item.merch_image) || $util.img('public/uniapp/default_img/goods.png')"
mode="aspectFill" show-menu-by-longpress
mode="aspectFill" :show-menu-by-longpress="true"
style="max-width: 80rpx; max-height: 80rpx; border-radius: 50rpx;" />
</view>
<text class="graphic-text"
@@ -119,6 +119,7 @@ export default {
obj += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
}
console.log(obj)
return obj;
},
// 子项样式
@@ -139,12 +140,14 @@ export default {
}
return obj;
}
},
},
methods: {
getList() {
console.log(121)
var data = {
num: this.value.count
};
console.log(this.value)
if (this.value.sources == 'diy') {
data.num = 0;
data.merch_id_arr = this.value.merchIds.toString();

View File

@@ -3,12 +3,13 @@
<view class="diy-notes" :style="{ backgroundColor: value.componentBgColor }">
<view class="diy-notes-top">
<view class="notes-title" :style="{ color: value.titleTextColor }">{{ value.title }}</view>
<view class="notes-more" @tap.stop="toMore()" :style="{ color: value.moreTextColor }">{{ value.more }}
<view class="notes-more" @click="toMore()" :style="{ color: value.moreTextColor }">{{ value.more }}
</view>
</view>
<scroll-view class="diy-notes-box" scroll-x="true" show-scrollbar="true">
<view class="notes-box-item" v-for="(item, i) in dataList" :key="i" @tap.stop="handlerClick(item)" :style="notesItemStyle">
<view class="notes-box-item" v-for="(item, i) in dataList" :key="i" @click="handlerClick(item)"
@tap="handlerClick(item)" :style="notesItemStyle">
<view class="notes-item" v-if="item.status == 1">
<view class="notes-item-con">
<view class="notes-title">{{ item.note_title }}</view>
@@ -25,10 +26,10 @@
<view class="notes-img-wrap" :class="{ 'notes-img-wrap-list': item.cover_type == 1 }">
<image v-if="item.cover_type == 0" :src="$util.img(item.img)" @error="imageError(i)"
mode="aspectFill" class="notes-item-image" show-menu-by-longpress/>
mode="aspectFill" class="notes-item-image" />
<image v-else v-for="(imgItem, imgIndex) in item.img" :key="imgIndex"
:src="$util.img(imgItem)" @error="imageError(i)" mode="aspectFit"
class="notes-item-image-li" show-menu-by-longpress/>
class="notes-item-image-li" />
</view>
<view class="notes-item-con">
@@ -156,7 +157,7 @@ export default {
/* 点赞 */
giveLike(noteId, index) {
if (!this.storeToken) {
this.$refs.login.open(this.$util.INDEX_PAGE_URL);
this.$refs.login.open('/pages/index/index');
return;
}

View File

@@ -41,12 +41,12 @@
<view @touchmove.prevent.stop>
<uni-popup ref="noticePopup" type="center">
<view class="notice-popup">
<view class="head-wrap" @tap.stop="closeNoticePopup">
<view class="head-wrap" @click="closeNoticePopup">
<text>公告</text>
<text class="iconfont icon-close"></text>
</view>
<view class="content-wrap">{{ notice }}</view>
<button type="primary" @tap.stop="closeNoticePopup">我知道了</button>
<button type="primary" @click="closeNoticePopup">我知道了</button>
</view>
</uni-popup>
</view>

View File

@@ -7,11 +7,11 @@
<!-- <text class="iconfont icon-shuaxin"></text> -->
</view>
<view class="qrocde-action">
<button type="primary" @tap.stop="toLink">
<button type="primary" @click="toLink">
<text class="iconfont icon-fukuanma"></text>
<text class="action-name">付款码</text>
</button>
<button type="primary" @tap.stop="openPaymentPopup">
<button type="primary" @click="openPaymentPopup">
<text class="iconfont icon-saomafu"></text>
<text class="action-name">扫码付</text>
</button>
@@ -26,12 +26,12 @@
<view @touchmove.prevent.stop>
<uni-popup ref="paymentPopup" type="center">
<view class="payment-popup">
<view class="head-wrap" @tap.stop="closePaymentPopup">
<view class="head-wrap" @click="closePaymentPopup">
<text>提示</text>
<text class="iconfont icon-close"></text>
</view>
<view class="content-wrap">扫码付请退出程序后直接使用微信扫一扫或返回上一页使用付款码进行支付</view>
<button type="primary" @tap.stop="closePaymentPopup">我知道了</button>
<button type="primary" @click="closePaymentPopup">我知道了</button>
</view>
</uni-popup>
</view>
@@ -75,6 +75,8 @@ export default {
// 允许从相机和相册扫码,h5端不起作用
uni.scanCode({
success: function (res) {
console.log('条码类型:' + res.scanType);
console.log('条码内容:' + res.result);
}
});
// #endif

View File

@@ -3,9 +3,9 @@
<view class="fui-picture">
<view v-for="(item, index) in value.list" style="line-height: 0;">
<image mode="widthFix" style="width: 100%;height:auto" :src="$util.img(item.imageUrl)"
v-if="item.link.wap_url" @tap.stop="handlerClick(item)" show-menu-by-longpress></image>
v-if="item.link.wap_url" @click="handlerClick(item)" @tap="handlerClick(item)"></image>
<image mode="widthFix" style="width: 100%;height:auto" :src="$util.img(item.imageUrl)" v-else
@tap.stop="handlerClick(item)" show-menu-by-longpress></image>
@click="handlerClick(item)" @tap="handlerClick(item)"></image>
</view>
<!-- <view wx:if="{{!childitem.linkurl}}" bindtap="previewImg" data-src="{{childitem.imgurl}}" style="padding:{{diyitem.style.paddingtop==0?0:diyitem.style.paddingtop+'rpx'}} {{diyitem.style.paddingleft==0?0:diyitem.style.paddingleft+'rpx'}}" wx:for="{{diyitem.data}}" wx:for-index="childid" wx:for-item="childitem" wx:key="{{childid}}">
<image mode="widthFix" src="{{childitem.imgurl}}" style="{{bannerheight?'height:'+bannerheight+'px':'height:auto'}}"></image>
@@ -52,9 +52,20 @@ export default {
}
},
methods: {
previewImg(img) {
// #ifdef MP-WEIXIN
uni.previewImage({
current: 0,
urls: [this.$util.img(img)],
success: function (res) { },
fail: function (res) { },
complete: function (res) { },
})
// #endif
},
redirectTo(link) {
if (link.wap_url) {
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
this.$refs.login.open(link.wap_url);
return;
}
@@ -66,9 +77,7 @@ export default {
await this.__$emitEvent({
eventName: 'picture-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
const link = item.link;
if (link?.name || link?.wap_url || link?.appid) {
if (item.link.wap_url) {
this.redirectTo(item.link);
} else {
this.previewImg(item.imageUrl);

View File

@@ -2,12 +2,12 @@
<x-skeleton data-component-name="diy-pinfan" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
<view class="diy-pinfan" :class="[value.template, value.style]" :style="warpCss">
<template v-if="value.template == 'row1-of1'">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl || value.btnStyle.control">
@@ -61,12 +61,12 @@
<template v-if="value.template == 'horizontal-slide'">
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
@@ -113,11 +113,11 @@
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(dataIndex)" show-menu-by-longpress/>
@error="imageError(dataIndex)" />
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
@@ -319,7 +319,7 @@ export default {
</script>
<style lang="scss">
::v-deep .uni-scroll-view ::-webkit-scrollbar {
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
@@ -328,7 +328,7 @@ export default {
background: transparent;
}
::v-deep ::-webkit-scrollbar {
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;

View File

@@ -10,18 +10,18 @@
:style="{ fontSize: value.titleStyle.fontSize * 2 + 'rpx', color: value.titleStyle.textColor, fontWeight: value.titleStyle.fontWeight ? 'bold' : '' }">
{{ value.titleStyle.leftText }}
</view>
<image v-else class="left-img" :src="$util.img(value.titleStyle.leftImg)" mode="heightFix" show-menu-by-longpress/>
<image v-else class="left-img" :src="$util.img(value.titleStyle.leftImg)" mode="heightFix" />
<view class="head-content">
<view class="img-warp">
<block v-if="headData && headData.member_list && headData.member_list.length">
<image v-for="(item, index) in headData.member_list" :key="index"
:src="$util.img(item.member_img || 'public/static/img/default_img/square.png')"
mode="aspectFill" @error="headImageError(index)" show-menu-by-longpress/>
mode="aspectFill" @error="headImageError(index)" />
</block>
<block v-else>
<image :src="$util.img('public/static/img/default_img/square.png')" mode="aspectFill" show-menu-by-longpress/>
<image :src="$util.img('public/static/img/default_img/square.png')" mode="aspectFill" show-menu-by-longpress/>
<image :src="$util.img('public/static/img/default_img/square.png')" mode="aspectFill" show-menu-by-longpress/>
<image :src="$util.img('public/static/img/default_img/square.png')" mode="aspectFill" />
<image :src="$util.img('public/static/img/default_img/square.png')" mode="aspectFill" />
<image :src="$util.img('public/static/img/default_img/square.png')" mode="aspectFill" />
</block>
</view>
<view :style="{ color: value.titleStyle.textColor }">
@@ -31,19 +31,19 @@
</view>
<view class="head-right"
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
@tap.stop="$util.redirectTo('/pages_promotion/pintuan/list')">
@click="$util.redirectTo('/pages_promotion/pintuan/list')">
<text>{{ value.titleStyle.more }}</text>
<text class="iconfont icon-right"></text>
</view>
</view>
<template v-if="value.template == 'row1-of1'">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl || value.btnStyle.control">
@@ -100,12 +100,12 @@
<template v-if="value.template == 'horizontal-slide'">
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="toDetail(item)"
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
<view v-if="value.groupStyle.control && value.style == 'style-1'" class="num" :style="{
color: value.theme == 'diy' ? value.groupStyle.color : '',
background: value.theme == 'diy' ? 'linear-gradient(to right,' + value.groupStyle.bgColorStart + ',' + value.groupStyle.bgColorEnd + ')' : ''
@@ -161,11 +161,11 @@
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
@tap.stop="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
@click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(dataIndex)" show-menu-by-longpress/>
@error="imageError(dataIndex)" />
<view v-if="value.groupStyle.control && value.style != 'style-2'" class="num" :style="{
color: value.theme == 'diy' ? value.groupStyle.color : '',
background: value.theme == 'diy' ? 'linear-gradient(to right,' + value.groupStyle.bgColorStart + ',' + value.groupStyle.bgColorEnd + ')' : ''
@@ -391,7 +391,7 @@ export default {
</script>
<style lang="scss">
::v-deep .uni-scroll-view ::-webkit-scrollbar {
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
@@ -400,7 +400,7 @@ export default {
background: transparent;
}
::v-deep ::-webkit-scrollbar {
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;

View File

@@ -2,12 +2,12 @@
<x-skeleton data-component-name="diy-presale" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
<view class="diy-presale" v-if="list.length" :class="[value.template, value.style]" :style="warpCss">
<template v-if="value.template == 'row1-of1'">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
@tap="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.btnStyle.control">
@@ -40,12 +40,12 @@
</template>
<template v-if="value.template == 'horizontal-slide'">
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
<view class="item" v-for="(item, index) in list" :key="index" @tap.stop="handlerClick(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="item" v-for="(item, index) in list" :key="index" @click="handlerClick(item)"
@tap="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
@@ -75,11 +75,12 @@
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
:class="['swiper-item', (list.length && [list[pageIndex].length / 3] >= 1) && 'flex-between']">
<view class="item" v-for="(item, dataIndex) in list[pageIndex]" :key="dataIndex"
@tap.stop="handlerClick(item)" :class="[value.ornament.type]" :style="goodsItemCss">
@click="handlerClick(item)" @tap="handlerClick(item)" :class="[value.ornament.type]"
:style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(dataIndex)" show-menu-by-longpress/>
@error="imageError(dataIndex)" />
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
@@ -275,7 +276,7 @@ export default {
</script>
<style lang="scss">
::v-deep .uni-scroll-view ::-webkit-scrollbar {
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
@@ -284,7 +285,7 @@ export default {
background: transparent;
}
::v-deep ::-webkit-scrollbar {
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;

View File

@@ -5,12 +5,12 @@
<view class="uni-scroll-view-content">
<!-- #endif -->
<view class="quick-nav-item" v-for="(item, index) in value.list" :key="index"
@tap.stop="handlerClick(item)"
@click="handlerClick(item)" @tap="handlerClick(item)"
:style="{ background: 'linear-gradient(to right,' + item.bgColorStart ? item.bgColorStart : '' + ',' + item.bgColorEnd ? item.bgColorEnd : '' + ')' }">
<view class="quick-img" v-if="item.imageUrl || item.icon">
<image v-if="item.iconType == 'img'"
:src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
mode="heightFix" show-menu-by-longpress ></image>
mode="heightFix" :show-menu-by-longpress="true"></image>
<diy-icon v-if="item.iconType == 'icon'" :icon="item.icon"
:value="item.style ? item.style : null" :style="{ fontSize: '60rpx' }"></diy-icon>
</view>
@@ -61,7 +61,7 @@ export default {
methods: {
redirectTo(link) {
if (link.wap_url) {
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
this.$refs.login.open(link.wap_url);
return;
}

View File

@@ -1,6 +1,6 @@
<template>
<view data-component-name="diy-rich-text" class="rich-text-box" :style="richTextWarpCss">
<rich-text :nodes="html" @tap.stop="handlerClick"></rich-text>
<rich-text :nodes="html" @click="handlerClick" @tap="handlerClick"></rich-text>
</view>
</template>

View File

@@ -8,20 +8,22 @@
<!-- 1左2右 -->
<template v-if="value.mode == 'row1-lt-of2-rt'">
<view class="template-left">
<view :class="['item', value.mode]" @tap.stop="handlerClick(value.list[0].link, value.list[0].imageUrl)"
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }">
<view :class="['item', value.mode]" @click="handlerClick(value.list[0].link)"
@tap="handlerClick(value.list[0].link)"
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }">
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
:style="list[0].pageItemStyle" show-menu-by-longpress />
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
</view>
</view>
<view class="template-right">
<template v-for="(item, index) in list">
<template v-if="index > 0">
<view :key="index" :class="['item', value.mode]" @tap.stop="handlerClick(item.link, item.imageUrl)"
:style="{ marginBottom: index < list.length - 1 ? value.imageGap * 2 + 'rpx' : 0, width: item.imgWidth, height: item.imgHeight + 'px' }">
<view :key="index" :class="['item', value.mode]" @click="handlerClick(item.link)"
@tap="handlerClick(item.link)"
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: item.imgWidth, height: item.imgHeight + 'px' }">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
:style="item.pageItemStyle" show-menu-by-longpress />
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
</view>
</template>
</template>
@@ -32,30 +34,31 @@
<template v-else-if="value.mode == 'row1-lt-of1-tp-of2-bm'">
<view class="template-left">
<view :class="['item', value.mode]"
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }"
@tap.stop="handlerClick(value.list[0].link, value.list[0].imageUrl)">
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }"
@click="handlerClick(value.list[0].link)" @tap="handlerClick(value.list[0].link)">
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
:style="list[0].pageItemStyle" show-menu-by-longpress />
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
</view>
</view>
<view class="template-right">
<view :class="['item', value.mode]"
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: list[1].imgWidth, height: list[1].imgHeight + 'px' }"
@tap.stop="handlerClick(value.list[1].link, value.list[1].imageUrl)">
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: list[1].imgWidth, height: list[1].imgHeight + 'px' }"
@click="handlerClick(value.list[1].link)" @tap="handlerClick(value.list[1].link)">
<image :src="$util.img(value.list[1].imageUrl)" :mode="list[1].imageMode || 'scaleToFill'"
:style="list[1].pageItemStyle" show-menu-by-longpress />
:style="list[1].pageItemStyle" :show-menu-by-longpress="true" />
</view>
<view class="template-bottom">
<template v-for="(item, index) in list">
<template v-if="index > 1">
<view :key="index" :class="['item', value.mode]" @tap.stop="handlerClick(item.link, item.imageUrl)" :style="{
marginRight: value.imageGap * 2 + 'rpx',
width: item.imgWidth,
height: item.imgHeight + 'px'
}">
<view :key="index" :class="['item', value.mode]" @click="handlerClick(item.link)"
@tap="handlerClick(item.link)" :style="{
marginRight: value.imageGap * 2 + 'rpx',
width: item.imgWidth,
height: item.imgHeight + 'px'
}">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
:style="item.pageItemStyle" show-menu-by-longpress />
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
</view>
</template>
</template>
@@ -65,10 +68,10 @@
<template v-else>
<view :class="['item', value.mode]" v-for="(item, index) in list" :key="index"
@tap.stop="handlerClick(item.link, item.imageUrl)"
:style="{ marginRight: value.imageGap * 2 + 'rpx', marginBottom: value.imageGap * 2 + 'rpx', width: item.widthStyle, height: item.imgHeight + 'px' }">
@click="handlerClick(item.link)" @tap="handlerClick(item.link)"
:style="{ marginRight: value.imageGap * 2 + 'rpx', marginBottom: value.imageGap * 2 + 'rpx', width: item.widthStyle, height: item.imgHeight + 'px' }">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
:style="item.pageItemStyle" show-menu-by-longpress />
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
</view>
</template>
</view>
@@ -235,6 +238,8 @@ export default {
*/
calcRowOneLeftOfTwoRight() {
let rightHeight = 0; // 右侧两图平分高度
let divide = 'left'; // 划分规则,left:左,right:右
if (this.list[1].imgWidth === this.list[2].imgWidth) divide = 'right';
uni.getSystemInfo({
success: res => {
this.list.forEach((item, index) => {
@@ -244,14 +249,12 @@ export default {
item.imgWidth = item.imgWidth / 2;
item.imgHeight = item.imgWidth * ratio;
rightHeight = (item.imgHeight - uni.upx2px(this.value.imageGap * 2)) / 2;
item.imgWidth += 'px';
} else {
item.imgWidth = this.list[0].imgWidth;
item.imgHeight = rightHeight;
}
});
// 统一追加 px 单位
this.list.forEach((item) => {
item.imgWidth += 'px';
});
}
});
},
@@ -311,6 +314,7 @@ export default {
this.list.forEach((item, index) => {
item.imgWidth += 'px';
item.imgHeight;
});
}
});
@@ -370,16 +374,11 @@ export default {
return obj;
},
async handlerClick(link, imageUrl) {
async handlerClick(link) {
await this.__$emitEvent({
eventName: 'rubik-cube-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
if (link?.name || link?.wap_url || link?.appid) {
this.$util.diyRedirectTo(link);
} else if (imageUrl){
this.previewImg(imageUrl);
}
this.$util.diyRedirectTo(link);
}
})
}
@@ -481,7 +480,7 @@ export default {
// 一左两右
.rubik-cube .template-left,
.rubik-cube .template-right {
width: 50%;
// width: 50%;
box-sizing: border-box;
}

View File

@@ -2,10 +2,10 @@
<view data-component-name="diy-search" class="diy-search">
<view class="diy-search-wrap" :class="value.positionWay" :style="fixedCss">
<view :class="['search-box', 'search-box-' + value.searchStyle]" :style="searchWrapCss"
@tap.stop="handlerSearchClick">
@click="handlerSearchClick" @tap="handlerSearchClick">
<block v-if="[1, 2].includes(value.searchStyle)">
<view class="img" v-if="value.searchStyle == 2 && value.iconType == 'img'">
<image :src="$util.img(value.imageUrl)" mode="heightFix" show-menu-by-longpress/>
<image :src="$util.img(value.imageUrl)" mode="heightFix" />
</view>
<diy-icon class="icon" v-if="value.searchStyle == 2 && value.iconType == 'icon'" :icon="value.icon"
:value="value.style ? value.style : 'null'"
@@ -14,30 +14,32 @@
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title"
v-model="searchText" @confirm="handlerSearchClick" disabled="true"
:placeholderStyle="placeholderStyle" />
<text class="iconfont icon-sousuo3" @tap.stop="handlerSearchClick"
<text class="iconfont icon-sousuo3" @click.stop="handlerSearchClick" @tap="handlerSearchClick"
:style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
</view>
</block>
<block v-if="value.searchStyle == 3">
<view class="search-content" :style="inputStyle"
@tap.stop="handlerSearchClick">
<view class="search-content" :style="inputStyle" @click.stop="handlerSearchClick"
@tap="handlerSearchClick">
<text class="iconfont icon-sousuo3"
:style="{ color: value.textColor ? value.textColor : 'rgba(0,0,0,0)' }"></text>
<input type="text" class="uni-input ns-font-size-base" maxlength="50" :placeholder="value.title"
v-model="searchText" @confirm="handlerSearchClick" disabled="true"
@tap.stop="handlerSearchClick"
@click.stop="handlerSearchClick" @tap="handlerSearchClick"
:placeholderStyle="placeholderStyle" />
<text class="search-content-btn" @tap.stop="handlerSearchClick"
<text class="search-content-btn" @click.stop="handlerSearchClick" @tap="handlerSearchClick"
:style="{ 'backgroundColor': value.pageBgColor ? value.pageBgColor : 'rgba(0,0,0,0)' }">搜索</text>
</view>
<view class="img" v-if="value.iconType == 'img'"
@tap.stop="handlerRedirectToClick(value.searchLink)">
<image :src="$util.img(value.imageUrl)" mode="heightFix" show-menu-by-longpress/>
@click.stop="handlerRedirectToClick(value.searchLink)"
@tap="handlerRedirectToClick(value.searchLink)">
<image :src="$util.img(value.imageUrl)" mode="heightFix" />
</view>
<diy-icon class="icon" v-if="value.iconType == 'icon'" :icon="value.icon"
:value="value.style ? value.style : 'null'"
:style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }"
@tap.stop="handlerRedirectToClick(value.searchLink)"></diy-icon>
@click.stop="handlerRedirectToClick(value.searchLink)"
@tap="handlerRedirectToClick(value.searchLink)"></diy-icon>
</block>
</view>
</view>
@@ -196,7 +198,7 @@ export default {
},
redirectTo(link) {
if (link.wap_url) {
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
this.$refs.login.open(link.wap_url);
return;
}
@@ -255,7 +257,7 @@ export default {
</script>
<style lang="scss">
::v-deep .uni-input-placeholder {
/deep/ .uni-input-placeholder {
overflow: initial;
}

View File

@@ -11,7 +11,7 @@
:style="{ fontSize: value.titleStyle.fontSize * 2 + 'rpx', color: value.titleStyle.textColor, fontWeight: value.titleStyle.fontWeight ? 'bold' : '' }">
{{ value.titleStyle.leftText }}
</view>
<image v-else class="title-img" :src="$util.img(value.titleStyle.leftImg)" mode="heightFix" show-menu-by-longpress/>
<image v-else class="title-img" :src="$util.img(value.titleStyle.leftImg)" mode="heightFix" />
<text v-if="value.titleStyle.style == 'style-2' && isFuture"
:style="{ color: value.titleStyle.textColor }" class="seckill-style-name">距离开始</text>
<view class="time" :style="{ background: value.titleStyle.timeBgColor }">
@@ -27,7 +27,7 @@
</view>
<view class="marketimg-box-title-right" v-if="value.titleStyle.moreSupport"
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
@tap.stop="toMore">
@click="toMore">
<text>{{ value.titleStyle.more }}</text>
<text class="iconfont icon-right"></text>
</view>
@@ -35,12 +35,12 @@
<view class="content-wrap">
<template v-if="value.template == 'row1-of1'">
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view class="content">
<view class="goods-name" v-if="value.goodsNameStyle.control"
@@ -57,7 +57,7 @@
}">
<image v-if="value.style == 'style-2'" class="progress-bar"
:src="$util.img('public/uniapp/seckill/progress_bar_01.png')"
mode="widthFix" show-menu-by-longpress/>
mode="widthFix" />
</view>
</view>
<view class="num"
@@ -105,12 +105,12 @@
</template>
<template v-if="value.template == 'row1-of2'">
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view class="content" v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
<view class="goods-name" v-if="value.goodsNameStyle.control"
@@ -150,12 +150,12 @@
<template v-if="value.template == 'horizontal-slide'">
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true"
:show-scrollbar="false">
<view class="item" v-for="(item, index) in dataList" :key="index" @tap.stop="toDetail(item.id)"
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)"
:class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(index)" show-menu-by-longpress/>
@error="imageError(index)" />
</view>
<view class="content" v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
<view class="goods-name" v-if="value.goodsNameStyle.control"
@@ -166,7 +166,7 @@
<view class="discount-price" v-if="value.priceStyle.mainControl">
<image v-if="value.style == 'style-2'" class="tag"
:src="$util.img('addon/seckill/component/view/seckill/img/style_4_tag.png')"
mode="widthFix" show-menu-by-longpress/>
mode="widthFix" />
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor : '' }">¥</text>
<text class="price price-style large"
@@ -190,11 +190,11 @@
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex"
:class="['swiper-item', dataList[pageIndex] && [dataList[pageIndex].length / 3].length >= 1 && 'flex-between']">
<view class="item" v-for="(item, dataIndex) in dataList[pageIndex]" :key="dataIndex"
@tap.stop="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
@click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix"
@error="imageError(dataIndex, pageIndex)" show-menu-by-longpress/>
@error="imageError(dataIndex, pageIndex)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
@@ -206,7 +206,7 @@
<view class="discount-price" v-if="value.priceStyle.mainControl">
<image v-if="value.style == 'style-2'" class="tag"
:src="$util.img('addon/seckill/component/view/seckill/img/style_4_tag.png')"
mode="widthFix" show-menu-by-longpress/>
mode="widthFix" />
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor : '' }">¥</text>
<text class="price price-style large"
@@ -536,7 +536,7 @@ scroll-view ::-webkit-scrollbar {
touch-action: none;
}
::v-deep .uni-scroll-view ::-webkit-scrollbar {
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
@@ -545,7 +545,7 @@ scroll-view ::-webkit-scrollbar {
background: transparent;
}
::v-deep ::-webkit-scrollbar {
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;

View File

@@ -140,7 +140,7 @@ export default {
display: flex;
align-items: baseline;
::v-deep .uni-scroll-view-content {
/deep/ .uni-scroll-view-content {
display: flex;
align-items: center;
}
@@ -148,7 +148,7 @@ export default {
&.between {
justify-content: space-between;
::v-deep .uni-scroll-view-content {
/deep/.uni-scroll-view-content {
justify-content: space-between;
}
}

View File

@@ -3,7 +3,7 @@
<block v-if="value.style == 1">
<view class="store-box store-one">
<view class="store-info">
<view class="info-box" :style="{ color: value.textColor }" @tap.stop="toStoreList()">
<view class="info-box" :style="{ color: value.textColor }" @click="toStoreList()">
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
<text class="title">{{ globalStoreInfo.store_name }}</text>
<text>
@@ -15,26 +15,26 @@
</view>
<view class="address-wrap" :style="{ color: value.textColor }">
<text class="iconfont icon-dizhi"></text>
<text v-if="globalStoreInfo && globalStoreInfo.store_id" @tap.stop="mapRoute" class="address">{{
<text v-if="globalStoreInfo && globalStoreInfo.store_id" @click="mapRoute" class="address">{{
globalStoreInfo.show_address }}</text>
<text v-else>获取当前位置...</text>
</view>
</view>
<view class="store-image" @tap.stop="selectStore()">
<view class="store-image" @click="selectStore()">
<image :src="$util.img(globalStoreInfo.store_image)"
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill" show-menu-by-longpress></image>
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill" show-menu-by-longpress></image>
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill"></image>
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill"></image>
</view>
</view>
</block>
<block v-if="value.style == 2">
<view class="store-box store-three" @tap.stop="toStoreList()">
<view class="store-box store-three" @click="toStoreList()">
<view class="store-info">
<view class="store-image" @tap.stop="selectStore()">
<view class="store-image" @click="selectStore()">
<image :src="$util.img(globalStoreInfo.store_image)"
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill" show-menu-by-longpress></image>
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill" show-menu-by-longpress></image>
v-if="globalStoreInfo && globalStoreInfo.store_image" mode="aspectFill"></image>
<image :src="$util.getDefaultImage().store" v-else mode="aspectFill"></image>
</view>
<view class="info-box" :style="{ color: value.textColor }">
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
@@ -47,13 +47,13 @@
<text class="title" v-else>定位中...</text>
</view>
</view>
<view class="store-icon" @tap.stop="search()"><text class="iconfont icon-sousuo3"
<view class="store-icon" @click.stop="search()"><text class="iconfont icon-sousuo3"
:style="{ color: value.textColor }"></text></view>
</view>
</block>
<block v-if="value.style == 3">
<view class="store-box store-four" @tap.stop="toStoreList()">
<view class="store-box store-four" @click="toStoreList()">
<view class="store-left-wrap">
<block v-if="globalStoreInfo && globalStoreInfo.store_id">
<text class="iconfont icon-weizhi" :style="{ color: value.textColor }"></text>
@@ -64,8 +64,8 @@
</view>
<view class="store-right-search">
<input type="text" class="uni-input font-size-tag" disabled placeholder="商品搜索"
@tap.stop="search()" />
<text class="iconfont icon-sousuo3" @tap.stop="search()"></text>
@click.stop="search()" />
<text class="iconfont icon-sousuo3" @click.stop="search()"></text>
</view>
</view>
</block>

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
<template>
<view data-component-name="diy-text" class="diy-text" @tap="handlerClick(value.link)" :style="warpCss">
<view data-component-name="diy-text" class="diy-text" @click="handlerClick(value.link)"
@tap="handlerClick(value.link)" :style="warpCss">
<view :class="value.style == 'style-8' ? 'title2' : 'title'"
:style="{ fontSize: value.fontSize * 2 + 'rpx', color: value.textColor }">
<block v-if="value.style == 'style-0'" style="height: 40rpx; line-height: 40rpx;">
@@ -89,23 +90,23 @@
<view class="style9-box">
<view class="style9-center">
<view class="left-img">
<image :src="$util.img('public/uniapp/diy/style9-1.png')" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/diy/style9-1.png')" />
</view>
<text class="style9-title"
:style="{ fontSize: value.fontSize * 2 + 'rpx', color: value.textColor, fontWeight: value.fontWeight }">
{{ value.text }}
</text>
<view class="right-img">
<image :src="$util.img('public/uniapp/diy/style9-2.png')" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/diy/style9-2.png')" />
</view>
<view class="style9-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
@tap.stop="handlerClick(value.more.link)">
@click.stop="handlerClick(value.more.link)" @tap="handlerClick(value.more.link)">
{{ value.more.text }}
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
</view>
</view>
<text class="sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
}}</text>
}}</text>
</view>
</view>
</block>
@@ -114,7 +115,7 @@
<view class="style10-box">
<view class="style10-center">
<view class="left-img">
<image :src="$util.img('public/uniapp/diy/style10-1.png')" show-menu-by-longpress></image>
<image :src="$util.img('public/uniapp/diy/style10-1.png')"></image>
</view>
<text class="style10-title" v-if="$util.img('public/uniapp/diy/style10-3.png')" :style="{
backgroundImage: 'url(' + $util.img('public/uniapp/diy/style10-3.png') + ')',
@@ -128,16 +129,16 @@
{{ value.text }}
</text>
<view class="right-img">
<image :src="$util.img('public/uniapp/diy/style10-2.png')" show-menu-by-longpress></image>
<image :src="$util.img('public/uniapp/diy/style10-2.png')"></image>
</view>
<view class="style10-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
@tap.stop="handlerClick(value.more.link)">
@click.stop="handlerClick(value.more.link)" @tap="handlerClick(value.more.link)">
{{ value.more.text }}
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
</view>
</view>
<text class="sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
}}</text>
}}</text>
</view>
</view>
</block>
@@ -158,16 +159,16 @@
value.subTitle.text }}</view>
</view>
<view class="style11-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
@tap.stop="$util.diyRedirectTo(value.more.link)">
@click.stop="$util.diyRedirectTo(value.more.link)">
{{ value.more.text }}
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
</view>
<image class="center-img" :src="$util.img('public/uniapp/diy/style11-1.png')"
mode="widthFix" show-menu-by-longpress></image>
mode="widthFix"></image>
<image class="right-img" :src="$util.img('public/uniapp/diy/style11-2.png')"
mode="widthFix" show-menu-by-longpress></image>
mode="widthFix"></image>
</view>
</view>
</view>
@@ -182,15 +183,15 @@
{{ value.text }}
</view>
<text class="style12-sub-title" :style="{ color: value.subTitle.color }">{{ value.subTitle.text
}}</text>
}}</text>
<view class="style12-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
@tap.stop="$util.diyRedirectTo(value.more.link)">
@click.stop="$util.diyRedirectTo(value.more.link)">
<text>{{ value.more.text }}</text>
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
</view>
</view>
<view class="style13" v-else-if="value.style == 'style-13'">
<image class="left-img" :src="$util.img('public/uniapp/diy/style13-1.png')" mode="widthFix" show-menu-by-longpress></image>
<image class="left-img" :src="$util.img('public/uniapp/diy/style13-1.png')" mode="widthFix"></image>
<view class="style13-title" :style="{
fontSize: value.fontSize * 2 + 'rpx',
color: value.textColor,
@@ -198,7 +199,7 @@
}">
{{ value.text }}
</view>
<image class="right-img" :src="$util.img('public/uniapp/diy/style13-1.png')" mode="widthFix" show-menu-by-longpress></image>
<image class="right-img" :src="$util.img('public/uniapp/diy/style13-1.png')" mode="widthFix"></image>
</view>
<view class="style14" v-else-if="value.style == 'style-14'">
<view class="title-wrap">
@@ -277,7 +278,7 @@
<text :style="{ fontWeight: value.subTitle.fontWeight }">{{ value.subTitle.text }}</text>
</view>
<view class="style16-more" v-if="value.more.isShow" :style="{ color: value.more.color }"
@tap.stop="$util.diyRedirectTo(value.more.link)">
@click.stop="$util.diyRedirectTo(value.more.link)">
<text>{{ value.more.text }}</text>
<view class="iconfont icon-right" :style="{ color: value.more.color }"></view>
</view>
@@ -323,7 +324,7 @@ export default {
await this.__$emitEvent({
eventName: 'text-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.$util.diyRedirectTo(link);
$util.diyRedirectTo(link);
}
})
}

View File

@@ -6,10 +6,10 @@
<view v-for="(item, index) in value.list" :key="index" class="goods-item" @tap="showVideo(item)">
<view class="goods-img-wrap">
<image class="goods-img" style="border-radius:10rpx 10rpx 0 0;" :src="$util.img(item.imageUrl)"
mode="widthFix" @error="imgError(index)" show-menu-by-longpress ></image>
mode="widthFix" @error="imgError(index)"></image>
<view style="position:absolute;top:10rpx;right:10rpx;">
<image style="width:30rpx;" :src="$util.img('addon/personnel/shop/view/enterprise/play.png')"
mode="widthFix" show-menu-by-longpress ></image>
mode="widthFix"></image>
</view>
</view>
<view class="info-wrap">
@@ -34,10 +34,10 @@
'max-height': '200rpx;',
'border-radius': '8rpx;'
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')" mode="widthFix"
show-menu-by-longpress ></image>
:show-menu-by-longpress="true"></image>
<view style="position:absolute;top:10rpx;right:10rpx;">
<image style="width:30rpx;"
:src="$util.img('addon/personnel/shop/view/enterprise/play.png')" mode="widthFix" show-menu-by-longpress >
:src="$util.img('addon/personnel/shop/view/enterprise/play.png')" mode="widthFix">
</image>
</view>
</view>
@@ -53,29 +53,22 @@
<!-- 视频播放弹窗 -->
<uni-popup ref="videoPopup" type="center" style="background:transparent;width:100%;height:100%;">
<view class="video-container" :style="popupVideoStyle">
<video
ref="popupVideoRef"
class="adaptive-video"
:autoPauseIfNavigate="true"
:autoPauseIfOpenNative="true"
:autoplay="false"
:enableAutoRotation="true"
id="myVideo"
:src="video_url"
:controls="true"
@loadedmetadata="onPopupVideoLoaded"
></video>
<view class="video-container" style="position:fixed;top:30%;width:100%;left:0;">
<video class="adaptive-video" :autoPauseIfNavigate="true" :autoPauseIfOpenNative="true"
:autoplay="false" :enableAutoRotation="true" id="myVideo" :src="video_url" :controls="true"></video>
</view>
</uni-popup>
</view>
</template>
<script>
import uniPopup from '@/components/uni-popup/uni-popup.vue'
import DiyMinx from './minx.js'
export default {
name: 'diy-video-list',
components: {
uniPopup
},
props: {
value: {
type: Object,
@@ -114,6 +107,7 @@ export default {
style += 'box-shadow:' + (this.value.ornament.type == 'shadow' ? '0 0 10rpx ' + this.value.ornament.color : '') + ';';
style += 'border:' + (this.value.ornament.type == 'stroke' ? '2rpx solid ' + this.value.ornament.color : '') + ';';
console.log(this.value);
return style;
},
@@ -135,76 +129,19 @@ export default {
isIndicatorDots() {
return this.value.carousel.type != 'hide' &&
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: {
// 显示视频播放弹窗
showVideo(item) {
this.video_url = item.videoUrl;
// 重置视频比例为null,等待新的检测结果
this.popupVideoRatio = null;
this.$refs.videoPopup.open();
},
// 图片加载错误处理
imgError(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';
} else {
// 获取失败,默认竖屏
this.popupVideoRatio = 'portrait';
}
});
console.log('图片加载失败:', index);
}
}
}
@@ -230,6 +167,10 @@ export default {
width: calc(33.3333333% - 14rpx);
box-sizing: border-box;
&:nth-child(3n + 3) {
width: calc(33.33% - 15rpx);
}
&:nth-of-type(1),
&:nth-of-type(2),
&:nth-of-type(3) {

View File

@@ -1,36 +1,7 @@
<template>
<view class="video-container" :style="containerStyle">
<!-- H5端使用原生video标签 -->
<!-- #ifdef H5 -->
<video
ref="videoRef"
data-component-name="diy-video"
class="diy-video h5-video"
:src="videoUrl"
:poster="posterUrl"
:style="videoWarpCss"
controls
preload="metadata"
@loadedmetadata="onVideoLoaded"
@click="handlerClick(videoUrl)"
></video>
<!-- #endif -->
<!-- 微信小程序端使用uni-app的video组件 -->
<!-- #ifdef MP-WEIXIN -->
<video
ref="videoRef"
data-component-name="diy-video"
class="diy-video mp-video"
:src="videoUrl"
:poster="posterUrl"
:style="videoWarpCss"
controls
@loadedmetadata="onVideoLoaded"
@error="onVideoError"
></video>
<!-- #endif -->
</view>
<video data-component-name="diy-video" class="diy-video" :src="$util.img(value.videoUrl)"
:poster="$util.img(value.imageUrl)" :style="videoWarpCss" objectFit="cover"
@click="handlerClick(value.videoUrl)" @tap="handlerClick(value.videoUrl)"></video>
</template>
<script>
@@ -44,149 +15,27 @@ export default {
}
},
data() {
return {
videoRatio: null, // 视频比例:'landscape'(横屏)或 'portrait'(竖屏)
videoUrl: '',
posterUrl: ''
};
},
created() {
this.initVideoData();
return {};
},
created() { },
mixins: [DiyMinx],
watch: {
value: {
immediate: true,
handler(newVal) {
if (newVal) {
this.initVideoData();
}
}
}
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
videoWarpCss: function () {
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-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
}
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: {
// 初始化视频数据
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;
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;
if (width && height) {
this.videoRatio = width >= height ? 'landscape' : 'portrait';
}
});
video.addEventListener('error', (e) => {
console.error('H5端预加载视频失败:', e);
});
// 触发加载
video.load();
},
// 视频加载完成事件(组件内video标签)
onVideoLoaded(event) {
let width = 0;
let height = 0;
// #ifdef H5
if (event && event.target) {
width = event.target.videoWidth || 0;
height = event.target.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.videoRatio = width >= height ? 'landscape' : 'portrait';
}
},
// 视频播放事件
onVideoPlay() {
},
// 视频暂停事件
onVideoPause() {
},
// 视频错误事件
onVideoError(event) {
console.error('视频加载失败:', event);
},
async handlerClick(videoUrl) {
await this.__$emitEvent({
eventName: 'video-tap', data: videoUrl, promiseCallback: (event, handler, awaitedResult) => {
@@ -199,32 +48,11 @@ export default {
</script>
<style scoped>
.video-container {
video {
width: 100%;
position: relative;
overflow: hidden;
background-color: #000;
}
/* 基础样式 */
.diy-video {
width: 100%;
height: 100%;
display: block;
.diy-video>>>.uni-video-container {
background-color: transparent;
}
/* H5端样式 */
/* #ifdef H5 */
.h5-video {
object-fit: cover;
}
/* #endif */
/* 微信小程序端样式 */
/* #ifdef MP-WEIXIN */
.mp-video {
width: 100%;
height: 100%;
}
/* #endif */
</style>
</style>

View File

@@ -1,187 +0,0 @@
// 微信视频号组件配置
export const wechatChannelConfig = {
// 图标相关
icon: {
defaultSize: 80, // 默认图标尺寸(rpx)
smallSize: 60, // 小图标尺寸(rpx)
channelArrowSize: 24, // 频道箭头图标尺寸(rpx)
channelArrow: 'addon/personnel/shop/view/enterprise/arrow.png', // 频道箭头图标路径
},
// 视频相关配置
video: {
defaultHeight: 320, // 默认视频高度(rpx)
minHeight: 200, // 最小视频高度(rpx)
maxHeight: 500, // 最大视频高度(rpx)
defaultCoverUrl: 'addon/personnel/shop/view/enterprise/default-video-cover.png', // 默认视频封面
},
// 播放按钮配置
playButton: {
size: 80, // 标准尺寸(rpx)
smallSize: 60, // 小尺寸(rpx)
iconSize: 40, // 标准图标尺寸(rpx)
smallIconSize: 30, // 小图标尺寸(rpx)
background: 'rgba(0, 0, 0, 0.4)', // 背景颜色
},
// 布局配置
layout: {
borderRadius: 12, // 圆角(rpx)
padding: 16, // 内边距(rpx)
margin: 10, // 外边距(rpx)
},
// 字体配置
font: {
channelNameSize: 28, // 频道名称字体大小(rpx)
videoTitleSize: 28, // 视频标题字体大小(rpx)
statsSize: 24, // 统计信息字体大小(rpx)
},
// 颜色配置
color: {
channelName: '#333', // 频道名称颜色
videoTitle: '#333', // 视频标题颜色
stats: '#999', // 统计信息颜色
border: '#f0f0f0', // 边框颜色
},
// 微信相关配置
wechat: {
minSdkVersion: '2.19.2', // 最小微信基础库版本
embedComponent: 'channel-video', // 嵌入式视频组件名称
},
// 错误提示配置
error: {
notWechat: '当前环境不是微信小程序',
lowVersion: '当前微信基础库版本过低,需要 2.19.2 或以上版本',
notSupported: '当前环境不支持微信视频号',
missingFields: '缺少必要字段: {field}',
},
};
// 获取配置项的辅助函数
export const getwechatChannelConfig = (key, defaultValue = null) => {
const keys = key.split('.');
let config = wechatChannelConfig;
for (const k of keys) {
if (config[k] === undefined) {
return defaultValue;
}
config = config[k];
}
return config;
};
// 微信视频号工具函数
export const wechatChannelUtil = {
// 版本比较
versionCompare(v1, v2) {
const arr1 = v1.split('.');
const arr2 = v2.split('.');
for (let i = 0; i < Math.max(arr1.length, arr2.length); i++) {
const num1 = parseInt(arr1[i] || 0);
const num2 = parseInt(arr2[i] || 0);
if (num1 > num2) return 1;
if (num1 < num2) return -1;
}
return 0;
},
// 检查是否支持嵌入式播放
isEmbedModeSupported() {
return typeof wx !== 'undefined' && wx.canIUse(wechatChannelConfig.wechat.embedComponent);
},
// 获取默认视频封面
getDefaultCoverUrl() {
return wechatChannelConfig.video.defaultCoverUrl;
},
// 数据校验
validateVideoData(item) {
const requiredFields = ['feedId', 'finderUserName'];
for (const field of requiredFields) {
if (!item[field]) {
throw new Error(`缺少必要字段: ${field}`);
}
}
return true;
},
// 播放视频
playVideo(item) {
return new Promise((resolve, reject) => {
try {
// 数据校验
this.validateVideoData(item);
} catch (err) {
this.handleError(err, item);
reject(err);
return;
}
// 检查微信环境
if (typeof wx === 'undefined') {
const err = new Error(wechatChannelConfig.error.notWechat);
this.handleError(err, item);
reject(err);
return;
}
// 检查基础库版本
const systemInfo = wx.getSystemInfoSync();
const SDKVersion = systemInfo.SDKVersion;
if (this.versionCompare(SDKVersion, wechatChannelConfig.wechat.minSdkVersion) < 0) {
const err = new Error(wechatChannelConfig.error.lowVersion);
this.handleError(err, item);
reject(err);
return;
}
// 调用微信视频号播放API
if (wx.openChannelsActivity) {
wx.openChannelsActivity({
feedId: item.feedId,
finderUserName: item.finderUserName,
success: (res) => {
resolve(res);
},
fail: (err) => {
this.handleError(err, item);
reject(err);
}
});
} else {
const err = new Error(wechatChannelConfig.error.notSupported);
this.handleError(err, item);
reject(err);
}
});
},
// 统一错误处理
handleError(err, item) {
console.error('微信视频号错误:', err);
const { message = '', errMsg = '微信视频播放失败!', errCode = -1 } = err;
// 错误码5: 表示用户点击了取消. openChannelsActivity:fail cancel
if ([5].includes(errCode)) {
return;
}
const showErrorToast = (otherMsgs = []) => {
uni.showToast({
title: [errMsg, message,...otherMsgs].join('\n'),
icon: 'none',
duration: 2000
});
}
showErrorToast();
}
};

View File

@@ -2,20 +2,8 @@ export default {
methods: {
// 异步触发事件
async __$emitEvent(payload = {eventName: '__unnamedEvent', data: {}, promiseCallback: null}) {
// console.log('__$emitEvent', payload)
await this.$eventBus.emit(payload.eventName, payload.data, payload.promiseCallback)
},
// 预览图片
previewImg(img) {
// #ifdef MP-WEIXIN
uni.previewImage({
current: 0,
urls: [this.$util.img(img)],
success: function (res) { },
fail: function (res) { },
complete: function (res) { },
})
// #endif
},
}
}

View File

@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"ns-loading": "../ns-loading/ns-loading"
}
}

View File

@@ -59,7 +59,7 @@
<view class="iconfont icon-right"></view>
</view>
</view>
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')" show-menu-by-longpress></image>
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')"></image>
</view>
<view class="address-box" :class="{ 'not-delivery-type': goodsData.delivery.express_type.length <= 1 }" v-if="orderCreateData.delivery.delivery_type == 'local'">
@@ -112,7 +112,7 @@
</view>
</view>
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')" show-menu-by-longpress></image>
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')"></image>
</view>
<!-- 门店信息 -->
@@ -154,7 +154,7 @@
</view>
</block>
<view v-else class="empty">当前无自提门店,请选择其它配送方式</view>
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')" show-menu-by-longpress></image>
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')"></image>
</view>
</template>
@@ -170,7 +170,7 @@
<view class="goods-item" v-for="(goodsItem, goodsIndex) in goodsSpecFormat(calculateGoodsData.goods_list)" :key="goodsIndex">
<view class="goods-wrap">
<view class="goods-img" @click="$util.redirectTo('/pages_goods/detail', { goods_id: goodsItem.goods_id })">
<image :src="$util.img(goodsItem.sku_image, { size: 'mid' })" @error="imageError(goodsIndex)" mode="aspectFill" show-menu-by-longpress/>
<image :src="$util.img(goodsItem.sku_image, { size: 'mid' })" @error="imageError(goodsIndex)" mode="aspectFill"/>
</view>
<view class="goods-info">
<view class="top-wrap">
@@ -521,7 +521,7 @@
<view class="coupon-item" v-for="(couponItem, couponIndex) in merchCoupon.data" :key="couponIndex" @click="selectCoupon(couponItem,merchCoupon.merch_id)">
<view class="coupon-info" :style="{ backgroundColor: 'var(--main-color-shallow)' }">
<view class="info-wrap">
<image class="coupon-line" mode="heightFix" :src="$util.img('public/uniapp/coupon/coupon_line.png')" show-menu-by-longpress/>
<image class="coupon-line" mode="heightFix" :src="$util.img('public/uniapp/coupon/coupon_line.png')"/>
<view class="coupon-money">
<template v-if="couponItem.type == 'divideticket'">
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
@@ -635,6 +635,7 @@
<script>
import payment from './payment.js';
export default {
name: 'common-payment',
data() {

View File

@@ -270,7 +270,7 @@ export default {
});
setTimeout(() => {
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
this.$util.redirectTo('/pages/index/index');
}, 1000)
}
}
@@ -762,10 +762,13 @@ export default {
}
this.$forceUpdate();
// this.orderCreateData.coupon[merch_id].coupon_id = data.coupon_id
console.log(this.selectCouponId)
},
//确定使用优惠券
useCpopon() {
console.log(this.merchCoupon.merch_id)
this.orderCreateData.coupon[this.merchCoupon.merch_id].coupon_id = this.selectCouponId;
console.log(this.orderCreateData.coupon)
this.$refs.couponPopup.close();
this.calculate();
},

View File

@@ -413,8 +413,10 @@ export default {
}
},
success: function (res) {
console.log('success', res);
},
fail: function (res) {
console.log('fail', res);
}
})
}

View File

@@ -2,27 +2,17 @@
<view>
<view scroll-y="true" class="goods-detail" :class="isIphoneX ? 'active' : ''">
<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"
:duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true"
:info="goodsSkuDetail.barrageData" />
<pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai" :duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true" :info="goodsSkuDetail.barrageData"/>
<!-- 商品媒体信息 -->
<view class="goods-media" :style="{ height: goodsSkuDetail.swiperHeight }">
<view class="goods-media" :style="{height: goodsSkuDetail.swiperHeight}">
<!-- 商品图片 -->
<view class="goods-img" :class="{ show: switchMedia == 'img' }">
<swiper class="swiper" @change="swiperChange" :interval="swiperInterval"
:autoplay="swiperAutoplay" autoplay="true" interval="4000" circular="true">
<swiper-item v-for="(item, index) in goodsSkuDetail.sku_images" :key="index"
:item-id="'goods_id_' + index">
<swiper class="swiper" @change="swiperChange" :interval="swiperInterval" :autoplay="swiperAutoplay" autoplay="true" interval="4000" circular="true">
<swiper-item v-for="(item, index) in goodsSkuDetail.sku_images" :key="index" :item-id="'goods_id_' + index">
<view class="item" @click="previewMedia(index)">
<image :src="$util.img(item, { size: 'big' })" @error="swiperImageError(index)"
mode="aspectFit" show-menu-by-longpress />
<image :src="$util.img(item, { size: 'big' })" @error="swiperImageError(index)" mode="aspectFit" />
</view>
</swiper-item>
</swiper>
@@ -34,16 +24,13 @@
<!-- 商品视频 -->
<view class="goods-video" :class="{ show: switchMedia == 'video' }">
<video id="goodsVideo" :src="$util.img(goodsSkuDetail.video_url)"
:poster="$util.img(goodsSkuDetail.sku_image, { size: 'big' })" objectFit="cover"></video>
<video id="goodsVideo" :src="$util.img(goodsSkuDetail.video_url)" :poster="$util.img(goodsSkuDetail.sku_image, { size: 'big' })" objectFit="cover"></video>
</view>
<!-- 切换视频、图片 -->
<view class="media-mode" v-if="goodsSkuDetail.video_url != ''">
<text :class="{ 'color-base-bg': switchMedia == 'video' }" @click="switchMedia = 'video'">{{
$lang('video') }}</text>
<text :class="{ 'color-base-bg': switchMedia == 'img' }"
@click="(switchMedia = 'img'), videoContext.pause()">{{ $lang('image') }}</text>
<text :class="{ 'color-base-bg': switchMedia == 'video' }" @click="switchMedia = 'video'">{{ $lang('video') }}</text>
<text :class="{ 'color-base-bg': switchMedia == 'img' }" @click="(switchMedia = 'img'), videoContext.pause()">{{ $lang('image') }}</text>
</view>
</view>
@@ -53,20 +40,19 @@
</view>
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.isinformation == 0">
<!-- 入口区域 -->
<slot name="entrance"></slot>
<!-- 配送 -->
<!-- @click="$refs.deliveryType.open()" -->
<view class="item delivery-type" v-if="goodsSkuDetail.is_virtual == 0">
<view class="label">{{ $lang('send') }}</view>
<!-- @click="$refs.deliveryType.open()" -->
<view class="item delivery-type" v-if="goodsSkuDetail.is_virtual == 0" >
<view class="label">{{$lang('send')}}</view>
<block v-if="deliveryType">
<view class="box">
<block v-for="(item, index) in deliveryType" :key="index">
<text
v-if="goodsSkuDetail.support_trade_type.indexOf(index) != -1">{{ $lang('express') }}</text>
<!-- {{ item.name }} -->
<text v-if="goodsSkuDetail.support_trade_type.indexOf(index) != -1">{{$lang('express')}}</text>
<!-- {{ item.name }} -->
</block>
</view>
<text class="iconfont icon-right"></text>
@@ -77,7 +63,7 @@
</view>
<!-- 门店 -->
<!-- <view class="item store-wrap" @click="openStoreListPopup()" v-if="addonIsExist.store && globalStoreInfo && isShowStore">
<!-- <view class="item store-wrap" @click="openStoreListPopup()" v-if="addonIsExist.store && globalStoreInfo && isShowStore">
<view class="label">门店</view>
<view class="list-wrap">
<view class="name-wrap">
@@ -94,21 +80,15 @@
<text class="iconfont icon-right"></text>
</view> -->
<view class="item service" @click="openMerchantsServicePopup()"
v-if="goodsSkuDetail.goods_service.length">
<view class="item service" @click="openMerchantsServicePopup()" v-if="goodsSkuDetail.goods_service.length">
<view class="label">服务</view>
<view class="list-wrap">
<view class="item-wrap" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index"
v-if="index < 3">
<view class="item-wrap" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index" v-if="index < 3">
<view class="item-wrap-box">
<view class="item-wrap-icon">
<text class="iconfont icon-dui"
v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
<image class="icon-img" v-else-if="item.icon.iconType == 'img'"
:src="$util.img(item.icon.imageUrl)" />
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'"
:icon="item.icon.icon"
:value="item.icon.style ? item.icon.style : null"></diy-icon>
<text class="iconfont icon-dui" v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
<image class="icon-img" v-else-if="item.icon.iconType == 'img'" :src=" $util.img(item.icon.imageUrl)" />
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'" :icon="item.icon.icon" :value="item.icon.style ? item.icon.style : null"></diy-icon>
</view>
<text>{{ item.service_name }}</text>
</view>
@@ -116,32 +96,30 @@
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
<!--多规格区域-->
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.sku_spec_format">
<!-- 入口区域 -->
<slot name="skuspec"></slot>
</view>
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.merch_id > 0">
<!--多规格区域-->
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.sku_spec_format">
<!-- 入口区域 -->
<slot name="skuspec"></slot>
</view>
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.merch_id > 0">
<!-- 入口区域 -->
<slot name="entrance"></slot>
<!-- 商家 -->
<view class="item store-wrap"
@click="$util.redirectTo('/pages_promotion/merch/detail', { merch_id: goodsSkuDetail.merch_id })">
<view class="item store-wrap" @click="$util.redirectTo('/pages_promotion/merch/detail', { merch_id: goodsSkuDetail.merch_id })">
<view class="list-wrap" style="display: flex;">
<view class="name-wrap">
<image :src="$util.img(goodsSkuDetail.merchinfo.merch_image)" mode="widthFix"
style="width: 100rpx;height: 100rpx;border-radius: 50rpx;" show-menu-by-longpress ></image>
<image :src="$util.img(goodsSkuDetail.merchinfo.merch_image)" mode="widthFix" style="width: 100rpx;height: 100rpx;border-radius: 50rpx;"></image>
</view>
<view class="other-wrap">
<view class="address" style="margin-left: 30rpx;">
<view>{{ goodsSkuDetail.merchinfo.merch_name }}</view>
<view style="font-size: 24rpx;color: #888;">官方认证商家,值得信赖!</view>
</view>
<view class="other-wrap">
<view class="address" style="margin-left: 30rpx;">
<view>{{goodsSkuDetail.merchinfo.merch_name}}</view>
<view style="font-size: 24rpx;color: #888;">官方认证商家,值得信赖!</view>
</view>
</view>
</view>
<text class="iconfont icon-right"></text>
@@ -158,8 +136,7 @@
</view>
<scroll-view scroll-y class="type-body">
<block v-for="(item, index) in deliveryType" :key="index">
<view class="type-item"
:class="{ 'not-support': goodsSkuDetail.support_trade_type.indexOf(index) == -1 }">
<view class="type-item" :class="{ 'not-support': goodsSkuDetail.support_trade_type.indexOf(index) == -1 }">
<text class="iconfont" :class="item.icon"></text>
<view class="content">
<view class="title">{{ item.name }}</view>
@@ -181,16 +158,11 @@
<text class="iconfont icon-close"></text>
</view>
<scroll-view scroll-y>
<view class="item" :class="{ 'empty-desc': !item.desc }"
v-for="(item, index) in goodsSkuDetail.goods_service" :key="index">
<view class="item-icon" :class="{ 'empty-desc': !item.desc }">
<text class="iconfont icon-dui color-base-text"
v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
<image class="icon-img" v-else-if="item.icon.iconType == 'img'"
:src="$util.img(item.icon.imageUrl)" />
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'"
:icon="item.icon.icon"
:value="item.icon.style ? item.icon.style : null"></diy-icon>
<view class="item" :class="{ 'empty-desc': !item.desc }" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index">
<view class="item-icon" :class="{'empty-desc':!item.desc}">
<text class="iconfont icon-dui color-base-text" v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
<image class="icon-img" v-else-if="item.icon.iconType == 'img'" :src=" $util.img(item.icon.imageUrl)" />
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'" :icon="item.icon.icon" :value="item.icon.style ? item.icon.style : null"></diy-icon>
</view>
<view class="info-wrap">
<text class="title">{{ item.service_name }}</text>
@@ -215,19 +187,17 @@
</view>
<scroll-view scroll-y>
<view class="store-list-content">
<view class="list-item" v-for="(item, index) in storeList.data" :key="index"
@click="selectStore(item)">
<view class="list-item" v-for="(item, index) in storeList.data" :key="index" @click="selectStore(item)">
<view class="item-box">
<view class="item-image">
<image :src="$util.img(item.store_image)" v-if="item.store_image" show-menu-by-longpress />
<image :src="$util.getDefaultImage().store" v-else show-menu-by-longpress />
<image :src="$util.img(item.store_image)" v-if="item.store_image"/>
<image :src="$util.getDefaultImage().store" v-else/>
</view>
<view class="item-info">
<view class="item-title">
<text class="title">{{ item.store_name }}</text>
<text class="distance color-base-text" v-if="item.distance">
距离{{ item.distance > 1 ? item.distance + 'km' : item.distance *
1000 + 'm' }}
距离{{ item.distance > 1 ? item.distance + 'km' : item.distance * 1000 + 'm' }}
</text>
</view>
<view class="item-time" v-if="item.open_date">营业时间:{{ item.open_date }}
@@ -248,7 +218,7 @@
<view class="detail-community" v-if="goodsSkuDetail.qr_data && goodsSkuDetail.qr_data.qr_state == 1">
<view class="community-box">
<image :src="$util.img('public/uniapp/goods/detail_erweiImage.png')" mode="aspectFill" show-menu-by-longpress ></image>
<image :src="$util.img('public/uniapp/goods/detail_erweiImage.png')" mode="aspectFill"></image>
<view class="community-content">
<view class="community-title">{{ goodsSkuDetail.qr_data.qr_name }}</view>
<view class="community-txt">{{ goodsSkuDetail.qr_data.community_describe }}</view>
@@ -258,13 +228,13 @@
</view>
<!-- 促销 -->
<!-- <view class="community-model" @touchmove.prevent.stop @click.stop="onCloseCommunity()" v-show="isCommunity">
<!-- <view class="community-model" @touchmove.prevent.stop @click.stop="onCloseCommunity()" v-show="isCommunity">
<view class="community-model-content" @click.stop>
<view class="community-model-content-radius">
<view>添加社群</view>
</view>
<view class="community-model-content-draw" v-if="goodsSkuDetail.qr_data && goodsSkuDetail.qr_data.qr_img">
<image :src="goodsSkuDetail.qr_data.qr_img != '' && goodsSkuDetail.qr_data.qr_state == 1 ? $util.img(goodsSkuDetail.qr_data.qr_img) : $util.img('public/uniapp/goods/detail_erweiImage.png') " mode="aspectFill" show-menu-by-longpress/>
<image :src="goodsSkuDetail.qr_data.qr_img != '' && goodsSkuDetail.qr_data.qr_state == 1 ? $util.img(goodsSkuDetail.qr_data.qr_img) : $util.img('public/uniapp/goods/detail_erweiImage.png') " mode="aspectFill" show-menu-by-longpress="true"/>
</view>
<view class="community-model-content-text">长按识别二维码,添加社群</view>
</view>
@@ -277,8 +247,7 @@
<slot name="articipation"></slot>
<!-- 商品评价 -->
<view class="group-wrap" v-if="evaluateConfig.evaluate_show == 1 && goodsSkuDetail.isinformation == 0"
style="display: none;">
<view class="group-wrap" v-if="evaluateConfig.evaluate_show == 1 && goodsSkuDetail.isinformation == 0" style="display: none;">
<view class="goods-evaluate" @click="toEvaluateDetail(goodsSkuDetail.goods_id)">
<view class="tit">
<!-- <view class="tit" :class="{ active: goodsEvaluate.content }"> -->
@@ -299,18 +268,12 @@
<view class="evaluator">
<view class="evaluator-info">
<view class="evaluator-face">
<image v-if="item.member_headimg" :src="$util.img(item.member_headimg)"
@error="item.member_headimg = $util.getDefaultImage().head"
mode="aspectFill" show-menu-by-longpress />
<image v-else :src="$util.getDefaultImage().head"
@error="item.member_headimg = $util.getDefaultImage().head"
mode="aspectFill" show-menu-by-longpress />
<image v-if="item.member_headimg" :src="$util.img(item.member_headimg)" @error="item.member_headimg = $util.getDefaultImage().head" mode="aspectFill" />
<image v-else :src="$util.getDefaultImage().head" @error="item.member_headimg = $util.getDefaultImage().head" mode="aspectFill" />
</view>
<view class="evaluator-name-wrap">
<text class="evaluator-name using-hidden"
v-if="item.member_name.length > 2 && item.is_anonymous == 1">
{{ item.member_name[0] }}***{{ item.member_name[item.member_name.length - 1]
}}
<text class="evaluator-name using-hidden" v-if="item.member_name.length > 2 && item.is_anonymous == 1">
{{ item.member_name[0] }}***{{ item.member_name[item.member_name.length - 1] }}
</text>
<text class="evaluator-name using-hidden" v-else>{{ item.member_name }}</text>
<view v-if="item.scores" class="evaluator-xing">
@@ -323,18 +286,16 @@
<view class="cont margin-top">{{ item.content }}</view>
<scroll-view scroll-x="true">
<view class="evaluate-img" v-if="item.images">
<view class="img-box" v-for="(img, img_index) in item.images" :key="img_index"
@click="previewEvaluate(index, img_index, 'images')">
<image :src="$util.img(img)" mode="aspectFill" show-menu-by-longpress />
<view class="img-box" v-for="(img, img_index) in item.images" :key="img_index" @click="previewEvaluate(index, img_index, 'images')">
<image :src="$util.img(img)" mode="aspectFill" />
</view>
</view>
</scroll-view>
</view>
</view>
</view>
<view class="goods-attr"
v-if="goodsSkuDetail.goods_attr_format && goodsSkuDetail.goods_attr_format.length > 0">
<view class="goods-attr" v-if="goodsSkuDetail.goods_attr_format && goodsSkuDetail.goods_attr_format.length > 0">
<view class="title">规格属性</view>
<view class="attr-wrap">
<block v-for="(item, index) in goodsSkuDetail.goods_attr_format" :key="index">
@@ -343,8 +304,7 @@
<text class="value-name">{{ item.attr_value_name }}</text>
</view>
</block>
<view class="attr-action" v-if="goodsSkuDetail.goods_attr_format.length > 4"
@click="switchGoodsAttr">
<view class="attr-action" v-if="goodsSkuDetail.goods_attr_format.length > 4" @click="switchGoodsAttr">
<block v-if="!goodsAttrShow">
展开<text class="iconfont icon-iconangledown"></text>
</block>
@@ -355,25 +315,24 @@
</view>
</view>
<!-- 详情 -->
<view class="goods-detail-tab">
<view class="detail-tab">
<view class="tab-item">{{ $lang('details') }}</view>
<view class="tab-item">{{$lang('details')}}</view>
</view>
<view class="detail-content active">
<view class="detail-content-item">
<view class="goods-details" v-if="goodsSkuDetail.goods_content">
<!-- <rich-text :nodes="goodsSkuDetail.goods_content" @click="showImg($event)" :data-nodes="goodsSkuDetail.goods_content"></rich-text> -->
<!-- {{goodsSkuDetail.goods_content}} -->
<mp-html :content="goodsSkuDetail.goods_content" />
<!-- :loading="loading" @preview="preview" @navigate="navigate" -->
<!-- <rich-text :nodes="goodsSkuDetail.goods_content" @click="showImg($event)" :data-nodes="goodsSkuDetail.goods_content"></rich-text> -->
<!-- {{goodsSkuDetail.goods_content}} -->
<mp-html :content="goodsSkuDetail.goods_content" />
<!-- :loading="loading" @preview="preview" @navigate="navigate" -->
</view>
<view class="goods-details active" v-else></view>
<view class="goods-details" v-if="service && service.is_display == 1 && service.content">
<rich-text :nodes="service.content" @click="showImg($event)"
:data-nodes="service.content"></rich-text>
<rich-text :nodes="service.content" @click="showImg($event)" :data-nodes="service.content"></rich-text>
</view>
</view>
</view>
@@ -390,7 +349,7 @@
<template v-if="poster != '-1'">
<view class="poster-wrap">
<view class="image-wrap">
<image :src="$util.img(poster)" show-menu-by-longpress mode="widthFix" />
<image :src="$util.img(poster)" :show-menu-by-longpress="true" mode="widthFix" />
<view class="close iconfont icon-close" @click="closePosterPopup()"></view>
</view>
<!-- #ifdef MP || APP-PLUS -->
@@ -460,73 +419,37 @@
</template>
<script>
// 商品详情视图
import scroll from '@/common/js/scroll-view.js';
import detail from './detail.js';
import IMAGE_CONFIG from '@/common/js/image-config.js';
import { createCustomerService } from '@/common/js/customer-service.js';
// 商品详情视图
import uniPopup from '@/components/uni-popup/uni-popup.vue';
import nsGoodsRecommend from '@/components/ns-goods-recommend/ns-goods-recommend.vue';
import pengpaiFadeinOut from '@/components/pengpai-fadein-out/pengpai-fadein-out.vue';
import xiaoStarComponent from '@/components/xiao-star-component/xiao-star-component.vue';
import scroll from '@/common/js/scroll-view.js';
import toTop from '@/components/toTop/toTop.vue';
import detail from './detail.js';
import pengpaiFadeinOut from '../pengpai-fadein-out/pengpai-fadein-out.vue';
export default {
name: 'goods-detail-view',
props: {
goodsSkuDetail: {
type: Object,
default: () => {
return {};
export default {
name: 'goods-detail-view',
props: {
goodsSkuDetail: {
type: Object,
default: () => {
return {};
}
}
}
},
components: {
pengpaiFadeinOut
},
computed: {
aiAvatarUrl() {
return this.$util.img(IMAGE_CONFIG.aiAvatar);
},
showAIChatBtn() {
const customerService = createCustomerService(this);
return customerService.hasValidKefuConfig() && customerService.isAIKefu();
}
},
mixins: [scroll, detail]
};
components: {
uniPopup,
nsGoodsRecommend,
pengpaiFadeinOut,
toTop,
xiaoStarComponent
},
mixins: [scroll, detail]
};
</script>
<style lang="scss">
@import '@/common/css/goods_detail.scss';
@import '@/common/css/goods_detail.scss';
</style>
<style scoped>
.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>
<style scoped></style>

View File

@@ -1,329 +1,246 @@
<template>
<view v-if="pageCount === 1 || need" class="fixed-box"
:style="[customContainerStyle, {
height: containerHeight,
backgroundImage: bgUrl ? `url(${bgUrl})` : '',
backgroundSize: 'cover'
}]">
<!-- 中英文切换按钮 -->
<view
v-if="isLanguageSwitchEnabled && fixBtnShow"
class="btn-item common-bg"
@click="toggleLanguage"
>
<text>{{ currentLangDisplayName }}</text>
</view>
<!-- 微信官方客服按钮-->
<button
v-if="fixBtnShow && hasValidKefuConfig && isWeappOfficialKefu"
class="btn-item common-bg"
open-type="contact"
>
<text class="icox icox-kefu" v-if="!kefuimg"></text>
</button>
<!-- 悬浮按钮 -->
<view v-if="pageCount == 1 || need" class="fixed-box"
:style="[{ height: fixBtnShow ? '400rpx' : '320rpx' }, customContainerStyle]">
<!-- <view class="btn-item" v-if="fixBtnShow" @click="$util.redirectTo('/pages/index/index')"> -->
<!-- 切换语言按钮 -->
<button class="btn-item" v-if="fixBtnShow && isLanguageSwitchEnabled" @click="toggleLanguage()"
:style="[{ backgroundSize: '100% 100%' }, customButtonStyle]">
<text :style="customTextStyle">{{ currentLangDisplayName }}</text>
</button>
<!-- 客服按钮 -->
<!-- #ifdef MP-WEIXIN -->
<button class="btn-item" v-if="fixBtnShow" hoverClass="none" openType="contact" sessionFrom="weapp"
showMessageCard="true"
:style="[{ backgroundImage: 'url(' + (kefuimg ? kefuimg : '') + ')', backgroundSize: '100% 100%' }, customButtonStyle]">
<text class="icox icox-kefu" v-if="!kefuimg"></text>
<!-- <view>首页</view> -->
</button>
<!-- #endif -->
<view class="btn-item" v-if="fixBtnShow" @click="call()"
:style="[{ backgroundImage: 'url(' + (phoneimg ? phoneimg : '') + ')', backgroundSize: '100% 100%' }, customButtonStyle]">
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
<!-- <view>我的</view> -->
</view>
<!-- 其他类型客服按钮(智能客服、企业微信等)-->
<view
v-if="fixBtnShow && hasValidKefuConfig && !isWeappOfficialKefu && !showWeappSystemKefu"
class="btn-item common-bg"
@click="handleUnifiedKefuClick"
>
<image
v-if="currentKefuImg"
:src="currentKefuImg"
mode="aspectFill"
class="kefu-img"
show-menu-by-longpress></image>
<text class="ai-icon" v-if="isAIKefu && !currentKefuImg">🤖</text>
<text class="ai-icon" v-if="isWxworkKefu && !currentKefuImg">💬</text>
<text class="ai-icon" v-if="!isAIKefu && !isWxworkKefu && !currentKefuImg">👤</text>
</view>
<!-- 智能客服按钮(当同时显示小程序系统客服时)-->
<view
v-if="fixBtnShow && hasValidKefuConfig && !isWeappOfficialKefu && showWeappSystemKefu"
class="btn-item common-bg"
@click="handleUnifiedKefuClick"
>
<image
v-if="currentKefuImg"
:src="currentKefuImg"
mode="aspectFill"
class="kefu-img"
show-menu-by-longpress></image>
<text class="ai-icon" v-if="isAIKefu && !currentKefuImg">🤖</text>
<text class="ai-icon" v-if="isWxworkKefu && !currentKefuImg">💬</text>
<text class="ai-icon" v-if="!isAIKefu && !isWxworkKefu && !currentKefuImg">👤</text>
</view>
<!-- 小程序系统客服按钮 -->
<button
v-if="fixBtnShow && hasValidKefuConfig && showWeappSystemKefu"
class="btn-item common-bg"
open-type="contact"
>
<text class="icox icox-kefu" v-if="!kefuimg"></text>
</button>
<!-- 电话按钮 -->
<view
v-if="fixBtnShow"
class="btn-item common-bg"
@click="call"
:style="[{ backgroundImage: phoneimg ? `url(${phoneimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]"
>
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
</view>
</view>
<!-- <view class="btn-item icon-xiala" v-if="fixBtnShow" @click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
<text class="iconfont icon-unfold"></text>
</view>
<view class="btn-item switch" v-else :class="{ show: fixBtnShow }"
@click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
<view class="">快捷</view>
<view>导航</view>
</view> -->
</view>
</template>
<script>
import { createCustomerService } from '@/common/js/customer-service.js';
export default {
name: 'hover-nav',
props: {
need: { type: Boolean, default: false }
},
data() {
return {
pageCount: 0,
fixBtnShow: true,
shopInfo: null,
currentLangIndex: 0,
langIndexMap: {},
customerService: null,
};
},
computed: {
bgUrl() {
return this.shopInfo?.bgUrl || '';
},
aiAgentimg() {
return this.shopInfo?.aiAgentimg || '';
},
kefuimg() {
return this.shopInfo?.kefuimg || this.$util.getDefaultImage().kefu;
},
phoneimg() {
return this.shopInfo?.phoneimg || this.$util.getDefaultImage().phone;
},
tel() {
return this.shopInfo?.mobile || '';
},
isLanguageSwitchEnabled() {
return !!this.shopInfo?.ischina;
},
currentLangDisplayName() {
const lang = this.langIndexMap[this.currentLangIndex];
return lang === 'zh-cn' ? 'EN' : 'CN';
},
customContainerStyle() {
return this.shopInfo?.floatingButton?.container || {};
},
customButtonStyle() {
return this.shopInfo?.floatingButton?.button || {};
},
unreadCount() {
const customerService = createCustomerService(this);
return customerService.getUnreadCount();
},
currentKefuImg() {
const customerService = createCustomerService(this);
return customerService.getKefuButtonIcon();
},
isWeappOfficialKefu() {
const customerService = createCustomerService(this);
return customerService.isWeappOfficialKefu();
},
isAIKefu() {
const customerService = createCustomerService(this);
return customerService.isAIKefu();
},
isWxworkKefu() {
const customerService = createCustomerService(this);
return customerService.isWxworkKefu();
},
isThirdKefu() {
const customerService = createCustomerService(this);
return customerService.isThirdKefu();
},
showWeappSystemKefu() {
const customerService = createCustomerService(this);
return customerService.shouldShowExtraWeappSystemKefu();
},
hasValidKefuConfig() {
const customerService = createCustomerService(this);
return customerService.hasValidKefuConfig();
},
//根据显示的按钮数量动态计算容器高度
containerHeight() {
if (!this.fixBtnShow) return '320rpx';
let buttonCount = 1;
if (this.isLanguageSwitchEnabled) buttonCount++;
if (this.showWeappSystemKefu) buttonCount++;
buttonCount++;
const totalRpx = 94 * buttonCount - 14;
const pxValue = Math.round(totalRpx * 0.5);
return ` $ {pxValue}px`;
}
},
watch: {
shopInfo: {
handler(newVal) {
},
immediate: true
}
},
created() {
this.initLanguage();
this.pageCount = getCurrentPages().length;
uni.getStorage({
key: 'shopInfo',
success: (e) => {
this.shopInfo = e.data;
},
fail: () => {
console.warn('未获取到 shopInfo,使用默认设置');
}
});
// 初始化 customerService 实例
this.customerService = createCustomerService(this);
},
methods: {
initLanguage() {
this.langList = this.$langConfig.list();
this.langIndexMap = {};
for (let i = 0; i < this.langList.length; i++) {
this.langIndexMap[i] = this.langList[i].value;
}
const savedLang = this.$langConfig.getCurrentLocale();
if (savedLang) {
for (let i = 0; i < this.langList.length; i++) {
if (this.langList[i].value === savedLang) {
this.currentLangIndex = i;
break;
}
}
} else {
this.currentLangIndex = 0;
}
},
name: 'hover-nav',
props: {
need: {
type: Boolean,
default: false
}
},
data() {
return {
pageCount: 0,
fixBtnShow: true,
tel: '',
kefuimg: '',
phoneimg: '',
shopInfo: null, // 店铺信息对象
call() {
this.customerService.makePhoneCallByNumber(this.tel);
},
// --- 语言切换相关 ---
currentLangIndex: 0, // 当前选中的语言索引
langIndexMap: {}, // 语言索引到语言值的映射
isLanguageSwitchEnabled: false, // 是否启用语言切换
toggleLanguage() {
this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
const targetLang = this.langIndexMap[this.currentLangIndex];
// --- 其他 ---
};
},
created() {
// 初始化语言设置
this.initLanguage();
uni.setStorageSync("lang", targetLang);
this.kefuimg = this.$util.getDefaultImage().kefu
this.phoneimg = this.$util.getDefaultImage().phone
this.pageCount = getCurrentPages().length;
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const currentRoute = currentPage.route;
// 从店铺信息中获取相关信息
uni.getStorage({
key: 'shopInfo',
success: (e) => {
console.log(`获取到的shopInfo:${JSON.stringify(e.data)}`)
this.shopInfo = e.data;
uni.reLaunch({
url: '/' + currentRoute
});
},
// 从店铺信息中获取手机号
this.tel = e.data.mobile
// 从店铺信息中获取是否启用语言切换
this.isLanguageSwitchEnabled = e.data.ischina;
}
})
handleUnifiedKefuClick() {
this.customerService.handleUnifiedKefuClick({
sendMessageTitle: '来自悬浮按钮的咨询',
sendMessagePath: '/pages/index/index'
});
}
}
}
},
computed: {
currentLangDisplayName() {
// 语言切换按钮显示名称,当前语言为中文时显示EN,否则显示CN
// 根据 langIndexMap 获取当前语言值
const lang = this.langIndexMap[this.currentLangIndex];
return lang == 'zh-cn' ? 'EN' : 'CN';
},
// 获取容器的自定义样式
customContainerStyle() {
// 只返回非空的样式属性,确保不覆盖原有的默认样式
return this.shopInfo?.floatingButton?.container || {};
},
// 获取按钮的自定义样式
customButtonStyle() {
// 只返回非空的样式属性,确保不覆盖原有的默认样式
return this.shopInfo?.floatingButton?.button || {};
},
// 获取文本的自定义样式
customTextStyle() {
// 只返回非空的样式属性,确保不覆盖原有的默认样式
return this.shopInfo?.floatingButton?.text || {};
}
},
methods: {
initLanguage() {
// 初始化语言列表
this.langList = this.$langConfig.list();
// 初始化语言索引映射
for (let i = 0; i < this.langList.length; i++) {
this.langIndexMap[i] = this.langList[i].value;
}
// 获取存储的语言设置
const savedLang = uni.getStorageSync('lang');
if (savedLang) {
for (let i = 0; i < this.langList.length; i++) {
if (this.langList[i].value == savedLang) {
this.currentLangIndex = i;
break;
}
}
} else {
this.currentLangIndex = 0;
}
},
//拨打电话
call() {
uni.makePhoneCall({
phoneNumber: this.tel + ''
})
},
toggleLanguage() {
// 切换语言索引
this.currentLangIndex = this.currentLangIndex == 0 ? 1 : 0;
const targetLang = this.langIndexMap[this.currentLangIndex];
// 获取当前页面路由
let currentRoute = this.$util.getCurrentRoute().path;
// 切换语言并重新加载当前页面
this.$langConfig.change(targetLang, currentRoute);
}
}
};
</script>
<style lang="scss" scoped>
<style lang="scss">
.container-box {
width: 100%;
.item-wrap {
border-radius: 10rpx;
.image-box {
border-radius: 10rpx;
}
image {
width: 100%;
height: auto;
border-radius: 10rpx;
will-change: transform;
}
}
}
//悬浮按钮
.fixed-box {
position: fixed;
right: 0rpx;
bottom: 240rpx;
/* #ifdef H5 */
bottom: 320rpx;
/* #endif */
z-index: 10;
border-radius: 120rpx;
padding: 20rpx 0;
display: flex;
justify-content: center;
flex-direction: column;
width: 100rpx;
box-sizing: border-box;
transition: 0.3s;
overflow: hidden;
}
position: fixed;
right: 0rpx;
bottom: 240rpx;
// #ifdef H5
bottom: 320rpx;
// #endif
z-index: 10;
// background: #fff;
// box-shadow: 2rpx 2rpx 22rpx rgba(0, 0, 0, 0.3);
border-radius: 120rpx;
padding: 20rpx 0;
display: flex;
justify-content: center;
flex-direction: column;
width: 100rpx;
box-sizing: border-box;
transition: 0.3s;
overflow: hidden;
.btn-item {
display: flex;
justify-content: center;
text-align: center;
flex-direction: column;
line-height: 1;
margin: 14rpx 0;
transition: 0.1s;
color: var(--hover-nav-text-color);
border-radius: 50%;
width: 80rpx;
height: 80rpx;
padding: 0;
overflow: hidden;
}
.btn-item {
display: flex;
justify-content: center;
text-align: center;
flex-direction: column;
line-height: 1;
margin: 14rpx 0;
transition: 0.1s;
background: #c6251b;
color: #fff;
border-radius: 40rpx;
width: 80rpx;
height: 80rpx;
padding: 0;
overflow: hidden;
.common-bg {
background-color: var(--hover-nav-bg-color);
}
text {
font-size: 28rpx;
}
.iconfont,
.icox {
font-size: 36rpx;
font-weight: bold;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
border-radius: 40rpx;
/* 确保图标本身也是圆形 */
}
.btn-item text {
font-size: 28rpx;
}
view {
font-size: 26rpx;
font-weight: bold;
}
.iconfont,
.icox {
font-size: 36rpx;
font-weight: bold;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
margin: 14rpx 0;
border-radius: 50rpx;
width: 80rpx;
height: 80rpx;
padding: 0;
position: relative;
}
&.show {
transform: rotate(180deg);
}
.iconfont text,
.icox text {
font-size: 36rpx;
font-weight: bold;
}
&.switch {}
.kefu-img {
width: 100%;
height: 100%;
display: block;
border-radius: 50%;
}
.ai-icon {
font-size: 40rpx;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
&.icon-xiala {
margin: 0;
margin-top: 0.1rpx;
}
}
}
</style>

View File

@@ -8,7 +8,7 @@
:src="mOption.src"
mode="widthFix"
@click="toTopClick"
show-menu-by-longpress/>
/>
</template>
<script>

View File

@@ -62,6 +62,8 @@
// 引入回到顶部组件
import MescrollTop from './components/mescroll-top.vue';
import nsLoading from '@/components/ns-loading/ns-loading.vue';
export default {
name: 'mescroll-uni',
components: {

View File

@@ -1,120 +1,120 @@
<template>
<view v-if="advList.length" :class="['container-box',className]">
<swiper :indicator-dots="advList.length > 1" indicator-active-color="#ffffff" :autoplay="true" :interval="3000" :duration="1000" v-if="advList.length > 1" @change="changeSwiper" :current="currentIndex" :style="{ height: swiperHeight + 'px' }" class="item-wrap">
<swiper-item v-for="(item, index) in advList" :key="index" @click="jumppage(item.adv_url)">
<view class="image-box">
<image :src="$util.img(item.adv_image)" mode="widthFix" :id="'content-wrap' + index" show-menu-by-longpress/>
</view>
</swiper-item>
</swiper>
<view v-else class="container-box item-wrap">
<image :src="$util.img(advList[0]['adv_image'])" mode="widthFix" lazy-load="true" @load="imageLoad" @click="jumppage(advList[0].adv_url)" show-menu-by-longpress/>
</view>
</view>
</template>
<script>
export default {
name: 'ns-advert',
props: {
keyword: {
type: String
},
className: {
type: String
}
},
data() {
return {
advList: [],
isImage: false,
//滑块的高度(单位px)
swiperHeight: 150,
//当前索引
currentIndex: 0,
};
},
created() {
this.getAdvList();
},
methods: {
//获取广告位
getAdvList() {
var item = {
adv_image: '',
adv_url: ''
};
this.$api.sendRequest({
url: '/api/adv/detail',
data: {
keyword: this.keyword
},
success: res => {
if (res.code == 0) {
var data = res.data.adv_list;
for (var index in data) {
if (data[index].adv_url) data[index].adv_url = JSON.parse(data[index].adv_url);
}
this.advList = res.data.adv_list;
//动态设置swiper的高度
this.$nextTick(() => {
this.setSwiperHeight();
});
}
}
});
},
jumppage(e) {
this.$util.diyRedirectTo(e);
},
imageLoad(data) {
this.isImage = true;
},
//手动切换题目
changeSwiper(e) {
this.currentIndex = e.detail.current;
//动态设置swiper的高度,使用nextTick延时设置
this.$nextTick(() => {
this.setSwiperHeight();
});
},
//动态设置swiper的高度
setSwiperHeight() {
if (this.advList.length > 1) {
setTimeout(() => {
let element = "#content-wrap" + this.currentIndex;
let query = uni.createSelectorQuery().in(this);
query.select(element).boundingClientRect();
query.exec((res) => {
if (res && res[0]) {
this.swiperHeight = res[0].height;
}
});
}, 10);
}
},
}
};
</script>
<style lang="scss">
.container-box {
width: 100%;
.item-wrap {
border-radius: 10rpx;
.image-box {
border-radius: 10rpx;
}
image {
width: 100%;
height: auto;
border-radius: 10rpx;
will-change: transform;
}
}
}
<template>
<view v-if="advList.length" :class="['container-box',className]">
<swiper :indicator-dots="advList.length > 1" indicator-active-color="#ffffff" :autoplay="true" :interval="3000" :duration="1000" v-if="advList.length > 1" @change="changeSwiper" :current="currentIndex" :style="{ height: swiperHeight + 'px' }" class="item-wrap">
<swiper-item v-for="(item, index) in advList" :key="index" @click="jumppage(item.adv_url)">
<view class="image-box">
<image :src="$util.img(item.adv_image)" mode="widthFix" :id="'content-wrap' + index"/>
</view>
</swiper-item>
</swiper>
<view v-else class="container-box item-wrap">
<image :src="$util.img(advList[0]['adv_image'])" mode="widthFix" lazy-load="true" @load="imageLoad" @click="jumppage(advList[0].adv_url)"/>
</view>
</view>
</template>
<script>
export default {
name: 'ns-advert',
props: {
keyword: {
type: String
},
className: {
type: String
}
},
data() {
return {
advList: [],
isImage: false,
//滑块的高度(单位px)
swiperHeight: 150,
//当前索引
currentIndex: 0,
};
},
created() {
this.getAdvList();
},
methods: {
//获取广告位
getAdvList() {
var item = {
adv_image: '',
adv_url: ''
};
this.$api.sendRequest({
url: '/api/adv/detail',
data: {
keyword: this.keyword
},
success: res => {
if (res.code == 0) {
var data = res.data.adv_list;
for (var index in data) {
if (data[index].adv_url) data[index].adv_url = JSON.parse(data[index].adv_url);
}
this.advList = res.data.adv_list;
//动态设置swiper的高度
this.$nextTick(() => {
this.setSwiperHeight();
});
}
}
});
},
jumppage(e) {
this.$util.diyRedirectTo(e);
},
imageLoad(data) {
this.isImage = true;
},
//手动切换题目
changeSwiper(e) {
this.currentIndex = e.detail.current;
//动态设置swiper的高度,使用nextTick延时设置
this.$nextTick(() => {
this.setSwiperHeight();
});
},
//动态设置swiper的高度
setSwiperHeight() {
if (this.advList.length > 1) {
setTimeout(() => {
let element = "#content-wrap" + this.currentIndex;
let query = uni.createSelectorQuery().in(this);
query.select(element).boundingClientRect();
query.exec((res) => {
if (res && res[0]) {
this.swiperHeight = res[0].height;
}
});
}, 10);
}
},
}
};
</script>
<style lang="scss">
.container-box {
width: 100%;
.item-wrap {
border-radius: 10rpx;
.image-box {
border-radius: 10rpx;
}
image {
width: 100%;
height: auto;
border-radius: 10rpx;
will-change: transform;
}
}
}
</style>

View File

@@ -10,9 +10,9 @@
</view>
<view class="birthday-title-desc" v-else>感谢您一直以来的支持,在您生日到来之际,特为您送上最真诚的祝福!</view>
<view class="birthday-title-hint">
<image :src="$util.img('public/uniapp/birthday_gift/birthday_gift_left.png')" mode="" class="birthday-img-all" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/birthday_gift/birthday_gift_left.png')" mode="" class="birthday-img-all"/>
<view class="font-size-toolbar">生日贺礼</view>
<image :src="$util.img('public/uniapp/birthday_gift/birthday_gift_right.png')" mode="" class="birthday-img-all" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/birthday_gift/birthday_gift_right.png')" mode="" class="birthday-img-all"/>
</view>
<scroll-view scroll-y="true" class="register-box">
<view class="reward-content">
@@ -80,10 +80,14 @@
</template>
<script>
import uniPopup from '../uni-popup/uni-popup.vue';
// 注册奖励弹出层
export default {
name: 'ns-birthday-gift',
components: {
uniPopup
},
data() {
return {
birthday: {
@@ -161,7 +165,7 @@
};
</script>
<style scoped>
.register-box ::v-deep .uni-scroll-view {
.register-box /deep/ .uni-scroll-view {
background: unset !important;
}
@@ -171,11 +175,11 @@
/* margin-top:350rpx; */
}
::v-deep .uni-popup__wrapper-box {
/deep/ .uni-popup__wrapper-box {
background-color: transparent !important;
}
::v-deep .birthday-title-hint uni-image {
/deep/ .birthday-title-hint uni-image {
width: 113rpx !important;
height: 24rpx !important;
}

View File

@@ -1,170 +1,171 @@
<template>
<view class="contact-wrap">
<slot></slot>
<!-- #ifdef MP-ALIPAY -->
<view class="contact-button" @click="contactServicer">
<contact-button :tnt-inst-id="config.instid" :scene="config.scene" size="1000rpx"
v-if="config.type == 'aliapp'" />
</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<!-- 微信小程序官方客服按钮 -->
<button v-if="useOfficialService" type="default" hover-class="none" open-type="contact"
class="contact-button" sessionFrom="weapp" showMessageCard="true"
:send-message-title="sendMessageTitle" :send-message-path="sendMessagePath"
:send-message-img="sendMessageImg"></button>
<!-- 微信小程序自定义客服按钮 -->
<button v-else type="default" hover-class="none" class="contact-button" @click="contactServicer"></button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN && MP-ALIPAY -->
<!-- 其他平台保持原逻辑 -->
<button type="default" hover-class="none" :open-type="openType" class="contact-button" @click="contactServicer"
:send-message-title="sendMessageTitle" :send-message-path="sendMessagePath"
:send-message-img="sendMessageImg" :show-message-card="true"></button>
<!-- #endif -->
<uni-popup ref="servicePopup" type="center">
<view class="service-popup-wrap">
<view class="head-wrap" @click="$refs.servicePopup.close()">
<text>联系客服</text>
<text class="iconfont icon-close"></text>
</view>
<view class="body-wrap">{{ siteInfo.site_tel ? '请联系客服,客服电话是' + siteInfo.site_tel : '抱歉,商家暂无客服,请线下联系' }}
</view>
</view>
</uni-popup>
</view>
</template>
<!-- 客服组件 -->
<script>
import { createCustomerService } from '@/common/js/customer-service.js';
export default {
name: 'ns-contact',
props: {
niushop: {
type: Object,
default: function () {
return {};
}
},
sendMessageTitle: {
type: String,
default: ''
},
sendMessagePath: {
type: String,
default: ''
},
sendMessageImg: {
type: String,
default: ''
}
},
data() {
return {
customerService: null,
buttonConfig: null
};
},
computed: {
/**
* 是否使用官方客服
*/
useOfficialService() {
if (!this.buttonConfig) return true;
// #ifdef MP-WEIXIN
// 如果是微信小程序,检查配置
if (this.buttonConfig.type === 'weapp') {
// 默认使用官方客服,除非明确设置为false
return this.buttonConfig.useOfficial !== false;
}
// #endif
return false;
},
/**
* 客服配置
*/
config() {
return this.customerService?.getPlatformConfig() || {};
},
/**
* 打开类型
*/
openType() {
return this.buttonConfig?.openType || '';
}
},
created() {
// 初始化客服服务
this.customerService = createCustomerService(this);
this.buttonConfig = this.customerService.getButtonConfig();
},
methods: {
/**
* 联系客服
*/
contactServicer() {
// 如果是微信/支付宝小程序客服,由系统自动处理
if (this.buttonConfig.openType === 'contact') {
return;
}
// 使用统一客服处理
this.customerService.handleCustomerClick({
niushop: this.niushop,
sendMessageTitle: this.sendMessageTitle,
sendMessagePath: this.sendMessagePath,
sendMessageImg: this.sendMessageImg
});
}
}
};
</script>
<style lang="scss">
.contact-wrap {
width: 100%;
height: 100%;
position: relative;
.contact-button {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 5;
padding: 0;
margin: 0;
opacity: 0;
overflow: hidden;
}
}
.service-popup-wrap {
width: 600rpx;
.head-wrap {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;
height: 90rpx;
}
.body-wrap {
text-align: center;
padding: 30rpx;
height: 100rpx;
}
}
<template>
<view class="contact-wrap">
<slot></slot>
<!-- #ifdef MP-ALIPAY -->
<view class="contact-button" @click="contactServicer">
<contact-button :tnt-inst-id="config.instid" :scene="config.scene" size="1000rpx" v-if="config.type == 'aliapp'"/>
</view>
<!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<button
type="default"
hover-class="none"
:open-type="openType"
class="contact-button"
@click="contactServicer"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:send-message-img="sendMessageImg"
:show-message-card="true"></button>
<!-- #endif -->
<uni-popup ref="servicePopup" type="center">
<view class="service-popup-wrap">
<view class="head-wrap" @click="$refs.servicePopup.close()">
<text>联系客服</text>
<text class="iconfont icon-close"></text>
</view>
<view class="body-wrap">{{ siteInfo.site_tel ? '请联系客服,客服电话是' + siteInfo.site_tel : '抱歉,商家暂无客服,请线下联系' }}</view>
</view>
</uni-popup>
</view>
</template>
<!-- 客服组件 -->
<script>
export default {
name: 'ns-contact',
props: {
niushop: {
type: Object,
default: function() {
return {};
}
},
sendMessageTitle: {
type: String,
default: ''
},
sendMessagePath: {
type: String,
default: ''
},
sendMessageImg: {
type: String,
default: ''
}
},
data() {
return {
config: null,
openType: ''
};
},
created() {
if (this.servicerConfig) {
// #ifdef H5
this.config = this.servicerConfig.h5;
// #endif
// #ifdef MP-WEIXIN
this.config = this.servicerConfig.weapp;
if (this.config.type == 'weapp') this.openType = 'contact';
// #endif
// #ifdef MP-ALIPAY
this.config = this.servicerConfig.aliapp;
if (this.config.type == 'aliapp') this.openType = 'contact';
// #endif
}
},
methods: {
/**
* 联系客服
*/
contactServicer() {
if (this.config.type == 'none') {
this.$refs.servicePopup.open();
}
if (this.openType == 'contact') return;
switch (this.config.type) {
case 'wxwork':
// #ifdef H5
location.href = this.config.wxwork_url;
// #endif
// #ifdef MP-WEIXIN
wx.openCustomerServiceChat({
extInfo: { url: this.config.wxwork_url },
corpId: this.config.corpid,
showMessageCard: true,
sendMessageTitle: this.sendMessageTitle,
sendMessagePath: this.sendMessagePath,
sendMessageImg: this.sendMessageImg
});
// #endif
break;
case 'third':
location.href = this.config.third_url;
break;
case 'niushop':
this.$util.redirectTo('/pages_tool/chat/room', this.niushop);
break;
default:
this.makePhoneCall();
}
},
/**
* 店铺联系方式
*/
makePhoneCall() {
this.$api.sendRequest({
url: '/api/site/shopcontact',
success: res => {
if (res.code == 0 && res.data.mobile) uni.makePhoneCall({
phoneNumber: res.data
.mobile
});
}
});
}
}
};
</script>
<style lang="scss">
.contact-wrap {
width: 100%;
height: 100%;
position: relative;
.contact-button {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 5;
padding: 0;
margin: 0;
opacity: 0;
overflow: hidden;
}
}
.service-popup-wrap {
width: 600rpx;
.head-wrap {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;
height: 90rpx;
}
.body-wrap {
text-align: center;
padding: 30rpx;
height: 100rpx;
}
}
</style>

View File

@@ -10,7 +10,7 @@
</view>
<view v-if="copyright && copyright.gov_record" class="gov-wrap" @click="toHref(copyright.gov_url)" target="_blank">
<image :src="$util.img('public/uniapp/common/gov_record.png')" alt="公安备案" show-menu-by-longpress/>
<image :src="$util.img('public/uniapp/common/gov_record.png')" alt="公安备案" />
<text>{{ copyright.gov_record }}</text>
</view>
</view> -->

View File

@@ -1,6 +1,6 @@
<template>
<view class="empty" :class="{ fixed: fixed }">
<view class="empty_img"><image :src="$util.img('public/uniapp/common/common-empty.png')" mode="aspectFit" show-menu-by-longpress></image></view>
<view class="empty_img"><image :src="$util.img('public/uniapp/common/common-empty.png')" mode="aspectFit"></image></view>
<view class="color-tip margin-top title" :style="{ color: textColor + ' !important' }">{{ text }}</view>
<view class="color-tip margin-bottom font-size-sub">{{ subText }}</view>
<button type="primary" size="mini" class="button mini" @click="goIndex()" v-if="isIndex">{{ emptyBtn.text }}</button>
@@ -45,7 +45,7 @@ export default {
if (this.emptyBtn.url) {
this.$util.redirectTo(this.emptyBtn.url, {}, 'redirectTo');
} else {
this.$util.redirectTo(this.$util.INDEX_PAGE_URL);
this.$util.redirectTo('/pages/index/index');
}
},
re(text) {

View File

@@ -89,7 +89,7 @@
</view>
<view class="box img-boxs">
<view class="img-box" v-for="(v, k) in item.img_lists" :key="k" @click="uploadImg(index)">
<image :src="$util.img(v)" mode="aspectFill" show-menu-by-longpress></image>
<image :src="$util.img(v)" mode="aspectFill"></image>
<text class="iconfont icon-guanbi" @click.stop="delImg(k, index)"></text>
</view>
<view class="img-box" @click="addImg(index)"><text class="iconfont icon-add1"></text></view>
@@ -200,8 +200,12 @@
</template>
<script>
import pickRegions from '@/components/pick-regions/pick-regions.vue';
export default {
name: 'ns-form',
components: {
pickRegions
},
props: {
data: {
type: Array,

View File

@@ -1,96 +1,96 @@
<template>
<view class="action-buttom-wrap disabled" v-if="disabled" @click="clickEvent">{{ disabledText }}</view>
<view class="action-buttom-wrap"
:class="[backgroundClass, textPrice ? 'has-second' : '', background ? 'color-join-cart' : 'color-base-bg']"
:style="{background:backgroundColor+'!important', 'color':textColor ? textColor : '#ffffff'}" v-else
@click="clickEvent">
<text class="price-font">{{ textPrice }}</text>
<text>{{ text }}</text>
</view>
</template>
<script>
export default {
name: 'ns-goods-action-button',
props: {
// 商品底部按钮文字
text: {
type: String,
default: ''
},
// 商品底部按钮价格文字
textPrice: {
type: String,
default: ''
},
// 背景色
background: {
type: String,
default: ''
},
// 背景色样式
backgroundClass: {
type: String,
default: ''
},
//
backgroundColor: {
type: String,
default: ''
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// 禁用文字提示
disabledText: {
type: String,
default: ''
},
// 文字颜色
textColor: {
type: String,
default: ''
},
},
computed: {},
methods: {
clickEvent() {
this.$emit('click');
}
}
};
</script>
<style lang="scss">
.action-buttom-wrap {
flex: 1;
height: 70rpx;
font-weight: 600;
font-size: 30rpx;
line-height: 70rpx;
border: none;
color: #fff;
text-align: center;
border-radius: 10rpx;
margin-right: 20rpx;
}
.action-buttom-wrap.has-second {
line-height: 50rpx;
}
.action-buttom-wrap.has-second text {
display: block;
line-height: 1.2;
}
.action-buttom-wrap:active {
opacity: 0.8;
}
.action-buttom-wrap.disabled {
background: $color-disabled;
}
<template>
<view class="action-buttom-wrap disabled" v-if="disabled" @click="clickEvent">{{ disabledText }}</view>
<view class="action-buttom-wrap"
:class="[backgroundClass, textPrice ? 'has-second' : '', background ? 'color-join-cart' : 'color-base-bg']"
:style="{background:backgroundColor+'!important', 'color':textColor ? textColor : '#ffffff'}" v-else
@click="clickEvent">
<text class="price-font">{{ textPrice }}</text>
<text>{{ text }}</text>
</view>
</template>
<script>
export default {
name: 'ns-goods-action-button',
props: {
// 商品底部按钮文字
text: {
type: String,
default: ''
},
// 商品底部按钮价格文字
textPrice: {
type: String,
default: ''
},
// 背景色
background: {
type: String,
default: ''
},
// 背景色样式
backgroundClass: {
type: String,
default: ''
},
//
backgroundColor: {
type: String,
default: ''
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// 禁用文字提示
disabledText: {
type: String,
default: ''
},
// 文字颜色
textColor: {
type: String,
default: ''
},
},
computed: {},
methods: {
clickEvent() {
this.$emit('click');
}
}
};
</script>
<style lang="scss">
.action-buttom-wrap {
flex: 1;
height: 70rpx;
font-weight: 600;
font-size: 30rpx;
line-height: 70rpx;
border: none;
color: #fff;
text-align: center;
border-radius: 10rpx;
margin-right: 20rpx;
}
.action-buttom-wrap.has-second {
line-height: 50rpx;
}
.action-buttom-wrap.has-second text {
display: block;
line-height: 1.2;
}
.action-buttom-wrap:active {
opacity: 0.8;
}
.action-buttom-wrap.disabled {
background: $color-disabled;
}
</style>

View File

@@ -20,6 +20,7 @@
</template>
<script>
import nsContact from '@/components/ns-contact/ns-contact.vue';
export default {
name: 'ns-goods-action-icon',
props: {
@@ -71,6 +72,9 @@ export default {
}
}
},
components:{
nsContact
},
methods: {
clickEvent() {
this.$emit('click');

View File

@@ -6,38 +6,38 @@
<text class="promotion-mark ">限时折扣</text>
<text class="title">当前商品正在参加{{ item.promotion_name }}</text>
<text class="iconfont icon-right"></text>
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" show-menu-by-longpress/></view> -->
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" /></view> -->
</view>
<view v-else-if="item.promotion_type == 'groupbuy'" class="item" @click="redirectTo('/pages_promotion/groupbuy/detail', { groupbuy_id: item.groupbuy_id })">
<!-- <view v-else-if="item.promotion_type == 'groupbuy'" class="item" @click="redirectTo('/pages_promotion/groupbuy/detail', { id: item.groupbuy_id })"> -->
<text class="promotion-mark ">团购</text>
<text class="title">当前商品正在参加{{ item.promotion_name }}</text>
<text class="iconfont icon-right"></text>
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" show-menu-by-longpress/></view> -->
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" /></view> -->
</view>
<view v-else-if="item.promotion_type == 'pintuan'" class="item" @click="redirectTo('/pages_promotion/pintuan/detail', { pintuan_id: item.pintuan_id })">
<text class="promotion-mark ">拼团</text>
<text class="title">当前商品正在参加{{ item.promotion_name }}</text>
<text class="iconfont icon-right"></text>
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" show-menu-by-longpress/></view> -->
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" /></view> -->
</view>
<view v-else-if="item.promotion_type == 'seckill'" class="item" @click="redirectTo('/pages_promotion/seckill/detail', { seckill_id: item.id })">
<text class="promotion-mark ">秒杀</text>
<text class="title">当前商品正在参加{{ item.promotion_name }}</text>
<text class="iconfont icon-right"></text>
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" show-menu-by-longpress/></view> -->
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" /></view> -->
</view>
<view v-else-if="item.promotion_type == 'topic'" class="item" @click="redirectTo('/pages_promotion/topics/goods_detail', { id: item.id })">
<text class="promotion-mark ">专题活动</text>
<text class="title">当前商品正在参加{{ item.promotion_name }}</text>
<text class="iconfont icon-right"></text>
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" show-menu-by-longpress/></view> -->
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" /></view> -->
</view>
<view v-else-if="item.promotion_type == 'bargain'" class="item" @click="redirectTo('/pages_promotion/bargain/detail', { b_id: item.bargain_id })">
<text class="promotion-mark ">砍价</text>
<text class="title">当前商品正在参加{{ item.promotion_name }}</text>
<text class="iconfont icon-right"></text>
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" show-menu-by-longpress/></view> -->
<!-- <view class="img-wrap"><image :src="$util.img('public/uniapp/goods/detail_more.png')" mode="aspectFit" /></view> -->
</view>
<view v-else-if="item.promotion_type == 'pinfan'" class="item" @click="redirectTo('/pages_promotion/pinfan/detail', { pinfan_id: item.pintuan_id })">
<text class="promotion-mark ">拼团返利</text>

View File

@@ -3,9 +3,16 @@
</template>
<script>
import nsLoading from '@/components/ns-loading/ns-loading.vue';
import nsGoodsSkuIndex from '@/components/ns-goods-sku/ns-goods-sku-index.vue';
// 商品推荐
export default {
name: 'ns-goods-recommend',
components: {
nsLoading,
nsGoodsSkuIndex
},
data() {
return {
list: [],

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More