36 Commits

Author SHA1 Message Date
ee6c777fb1 chore:进入客服页面不乱跳了 2025-12-16 14:07:59 +08:00
5503758854 chore:删除了气泡底下的时间 2025-12-16 11:35:55 +08:00
8d84306747 chore:往上翻历史记录,不在乱窜了 2025-12-16 11:32:40 +08:00
c45f3e69da chore:解决了key问题 2025-12-13 16:33:22 +08:00
80428e625f chore:可以看到之前历史对话了,但是获取时会晃动不完整 2025-12-13 16:19:29 +08:00
a06ee95482 chore:可以看见历史记录了 2025-12-12 16:41:54 +08:00
b4aed459c5 chore:目前为止加了历史会话,正常运行没有出错 2025-12-12 16:23:00 +08:00
aa03abf651 chore:ai客服解析流式数据成功 2025-12-12 10:48:26 +08:00
af23505a74 chore:AI客服正常流式聊天 2025-12-11 17:35:34 +08:00
3898518ad0 chore: 可以连接到流式请求 2025-12-11 17:24:14 +08:00
f0d3d1986f chore:把 message替换成 query 2025-12-11 09:42:28 +08:00
2750d8012f chore(merge): 这个版本正常运行 2025-12-10 15:30:39 +08:00
89fbfcaca6 Merge branch 'feat-ai-agent' of http://git.aigc-quickapp.com/Uniapp/lucky_shop into feat-ai-agent 2025-12-10 15:25:35 +08:00
80c172ed77 合并
Squashed commit of the following:

commit 2416eab34f
Author: jinhhanhan <1683105490@qq.com>
Date:   Fri Dec 5 17:12:14 2025 +0800

    chore:加了dify

commit c4f2cea1a9
Author: jinhhanhan <1683105490@qq.com>
Date:   Fri Dec 5 16:47:53 2025 +0800

    chore:加了智能体

commit 227ab42e5a
Author: jinhhanhan <1683105490@qq.com>
Date:   Thu Dec 4 14:27:46 2025 +0800

    chore:挂上了智能客服
2025-12-10 15:21:32 +08:00
a0ddcd673d Squashed commit of the following:
commit 2416eab34f
Author: jinhhanhan <1683105490@qq.com>
Date:   Fri Dec 5 17:12:14 2025 +0800

    chore:加了dify

commit c4f2cea1a9
Author: jinhhanhan <1683105490@qq.com>
Date:   Fri Dec 5 16:47:53 2025 +0800

    chore:加了智能体

commit 227ab42e5a
Author: jinhhanhan <1683105490@qq.com>
Date:   Thu Dec 4 14:27:46 2025 +0800

    chore:挂上了智能客服
2025-12-10 14:52:52 +08:00
c50fab3d3a chore:没有太大关系的代码 2025-12-10 14:35:40 +08:00
578d914e9b chore:客服正常对话 2025-12-10 14:32:38 +08:00
1b194bf3e1 chore:健康检查中加了一个date空值 2025-12-10 14:22:00 +08:00
b685a91598 chore:加了文档中智能客服聊天功能,健康系统检测,流式聊天测试,创建会话接口 2025-12-10 11:37:29 +08:00
7da168e1b2 chore:让智能客服到AI气泡上方 2025-12-10 10:10:18 +08:00
179a9089b7 chore:加了用户自定义昵称 2025-12-10 09:23:04 +08:00
57a0bb9b5a chore:改了 2025-12-09 18:31:47 +08:00
4cfbfa7d8f chore:用户气泡可以随着字数改变而改变 2025-12-09 17:53:25 +08:00
eb189ae9f7 chore:加了用户自定义头像,背景颜色 2025-12-09 17:14:43 +08:00
d489f352db chore:增加了粉色机器人头像 2025-12-08 18:09:38 +08:00
7dbf455341 chore:ai智能客服可以正常对话 2025-12-08 17:16:10 +08:00
2416eab34f chore:加了dify 2025-12-05 17:12:14 +08:00
c4f2cea1a9 chore:加了智能体 2025-12-05 16:47:53 +08:00
227ab42e5a chore:挂上了智能客服 2025-12-04 14:27:46 +08:00
4cf19e417f chore:修改了 // 商户ID uniacid: 460
//api请求地址
    baseUrl: 'https://xcx30.5g-quickapp.com/',
    // baseUrl: 'http://localhost:8010/',

    // 图片域名
    imgDomain: 'https://xcx30.5g-quickapp.com/',
    //imgDomain: 'http://localhost:8010/',

    // H5端域名
    h5Domain: 'https://xcx30.5g-quickapp.com/',
    // h5Domain: 'http://localhost:8010/',
2025-12-01 08:42:50 +08:00
97f6971bd0 临时保存代码 2025-11-11 09:10:36 +08:00
526c813d8d chore: 从源码中移除 ai-chat-float 及 ai-chat-popup组件 2025-11-04 16:17:05 +08:00
29280f6f57 chore: 保留ai-chat-popup 及 ai-chat-flaot组件 2025-11-04 16:16:03 +08:00
1c2fee28ec chore: 初步聊天布局展示 2025-11-03 18:33:06 +08:00
5b9114aeac chore: 修复输入区导致的高度问题 2025-11-03 17:10:49 +08:00
2dfb2e0316 chore: 添加AI聊天对话框 2025-11-03 16:31:53 +08:00
516 changed files with 48717 additions and 61436 deletions

View File

@@ -1,43 +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',
},
})['2811']; // 选择要使用的环境配置
export default localDevConfig;

View File

@@ -1,43 +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',
},
})['2811']; // 选择要使用的环境配置
export default localDevConfig;

21
App.vue
View File

@@ -1,17 +1,17 @@
<script>
import auth from 'common/js/auth.js';
import configExternal from 'common/js/config-external.js'
import colorList from 'common/js/style_color.js'
import {
Weixin
} from 'common/js/wx-jssdk.js';
export default {
mixins: [auth],
onLaunch: async function(options) {
// 方式支持快应用从url中query部分获取uniacid或useragent中获取uniacid
onLaunch: function(options) {
// console.log(options.query.uniacid)
if(options.query.uniacid){
uni.setStorageSync('uniacid', options.query.uniacid);
console.log(uni.getStorageSync('uniacid'))
}
uni.hideTabBar();
@@ -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,9 +61,7 @@
// 主题风格
if (uni.getStorageSync('themeStyle')) {
const themeData = await configExternal.loadTheme(uni.getStorageSync('themeStyle'));
this.$store.commit('setThemeStyle', themeData);
this.$store.dispatch('themeColorSet');
this.$store.commit('setThemeStyle', colorList[uni.getStorageSync('themeStyle')]);
}
// 插件是否存在
@@ -100,11 +98,6 @@
if (uni.getStorageSync('servicerConfig')) {
this.$store.commit('setServicerConfig', uni.getStorageSync('servicerConfig'));
}
// 企业微信配置
if (uni.getStorageSync('wxworkConfig')) {
this.$store.commit('setWxworkConfig', uni.getStorageSync('wxworkConfig'));
}
// 版权信息
if (uni.getStorageSync('copyright')) {
@@ -303,7 +296,7 @@
this.shareConfig();
}
},
// 代表在watch里声明了firstName这个方法之后立即先去执行handler方法
// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
immediate: true
}
}

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -1,11 +1,10 @@
import Config from './config.js'
import http from './http.js'
import store from '@/store/index.js'
let currentConversationId = null;
const CONVERSATION_KEY = 'ai_conversation_id';
// 初始化时从本地读取会话ID
// 初始化时从本地读取
try {
const saved = uni.getStorageSync(CONVERSATION_KEY);
if (saved) {
@@ -14,14 +13,16 @@ try {
} catch (e) {
console.warn('读取会话ID失败:', e);
}
export default {
/**
* 发送普通消息blocking 模式)
* 发送消息到Dify API
* @param {string} message 用户消息内容
* @param {Object} options 配置选项
* @returns {Promise}
*/
async sendMessage(message, options = {}) {
try {
const aiConfig = store.getters.globalAIKefuConfig;
const aiConfig = store.getters.globalAIKefuConfig
const params = {
url: '/api/kefu/chat',
data: {
@@ -29,142 +30,225 @@ export default {
stream: false,
inputs: {},
query: message,
response_mode: 'blocking', // 强制 blocking
response_mode: options.stream ? 'streaming' : 'blocking',
user: store.state.memberInfo?.id || 'anonymous',
conversation_id: this.getConversationId() || ''
conversation_id: this.getConversationId() || ''
},
header: {
'Content-Type': 'application/json'
}
};
console.log('Sending blocking request to:', params.url);
}
console.log('Sending request to:', params.url);
console.log('Request data:', params.data);
const response = await http.sendRequest({
...params,
async: false
});
const result = this.handleResponse(response);
if (result.conversationId) {
this.setConversationId(result.conversationId);
}
return result;
})
const result = this.handleResponse(response, options);
if (result.conversationId) {
this.setConversationId(result.conversationId);
}
return result;
} catch (error) {
console.error('Dify API请求失败:', error)
throw new Error('AI服务暂时不可用请稍后重试')
}
},
/**
* 流式消息处理
*/
async sendStreamMessage(message, onChunk, onComplete) {
try {
return this.sendHttpStream(message, onChunk, onComplete)
} catch (error) {
console.error('Dify API请求失败:', error);
throw new Error('AI服务暂时不可用请稍后重试');
console.error('流式消息发送失败:', error)
throw error
}
},
/**
* 流式消息入口(自动适配平台)
* EventSource 流式聊天
*/
async sendStreamMessage(message, onChunk, onComplete) {
// #ifdef MP-WEIXIN
return new Promise((resolve, reject) => {
const socketTask = wx.connectSocket({
url: 'wss://dev.aigc-quickapp.com/ws/aikefu',
header: {}
});
let content = '';
let conversationId = '';
let isAuthenticated = false;
socketTask.onOpen(() => {
console.log('WebSocket 连接成功,开始认证...');
socketTask.send({
data: JSON.stringify({
action: 'auth',
uniacid: store.state.uniacid || '1',
token: store.state.token || 'test_token',
user_id: store.state.memberInfo?.id || 'anonymous'
})
});
});
socketTask.onMessage((res) => {
try {
const data = JSON.parse(res.data);
console.log('收到 WebSocket 消息:', data);
if (data.type === 'auth_success') {
console.log('认证成功,发送聊天消息...');
isAuthenticated = true;
socketTask.send({
data: JSON.stringify({
action: 'chat',
uniacid: store.state.uniacid || '1',
query: message,
user_id: store.state.memberInfo?.id || 'anonymous',
conversation_id: this.getConversationId() || ''
})
});
} else if (data.type === 'auth_failed') {
const errorMsg = '认证失败,请重新登录';
console.error(errorMsg, data);
reject(new Error(errorMsg));
if (onComplete) onComplete({ error: errorMsg });
socketTask.close();
}
// 处理流式消息块
else if (data.type === 'message' || data.event === 'message') {
const text = data.answer || data.content || data.text || '';
content += text;
if (onChunk) onChunk(text);
}
// 处理流结束
else if (data.event === 'message_end' || data.type === 'message_end') {
conversationId = data.conversation_id || '';
if (conversationId) {
this.setConversationId(conversationId);
}
if (onComplete) {
onComplete({ content, conversation_id: conversationId });
}
resolve({ content, conversation_id: conversationId });
socketTask.close();
}
// 可选:处理 done
else if (data.type === 'done') {
console.log('对话完成:', data);
}
} catch (e) {
console.error('WebSocket 消息解析失败:', e, '原始数据:', res.data);
}
});
socketTask.onError((err) => {
const errorMsg = 'WebSocket 连接失败';
console.error(errorMsg, err);
reject(new Error(errorMsg));
if (onComplete) onComplete({ error: errorMsg });
});
socketTask.onClose(() => {
console.log('WebSocket 连接已关闭');
});
const timeout = setTimeout(() => {
if (!isAuthenticated || content === '') {
console.warn('WebSocket 超时,强制关闭');
socketTask.close();
reject(new Error('AI服务响应超时'));
if (onComplete) onComplete({ error: 'AI服务响应超时' });
}
}, 10000);
});
// #endif
},
chatWithEventSource(message, conversationId = '', onMessage, onComplete, onError) {
if (window.currentEventSource) {
window.currentEventSource.close();
}
const params = new URLSearchParams({
uniacid: store.state.uniacid || '1',
user_id: store.state.memberInfo?.id || '123456',
query: message,
conversation_id: conversationId || '',
stream: 'true'
});
const url = `/api/kefu/chat?${params.toString()}`;
try {
const eventSource = new EventSource(url);
window.currentEventSource = eventSource;
let aiMessage = '';
eventSource.addEventListener('message', (event) => {
try {
const data = JSON.parse(event.data);
if (data.event === 'message') {
aiMessage += data.answer || '';
if (onMessage) onMessage(data.answer || '');
}
if (data.event === 'message_end') {
if (onComplete) onComplete({
conversation_id: data.conversation_id,
message: aiMessage
});
}
if (data.conversation_id) {
conversationId = data.conversation_id;
}
} catch (error) {
console.error('解析消息失败:', error);
}
});
eventSource.addEventListener('done', (event) => {
try {
const data = JSON.parse(event.data);
if (onComplete) onComplete(data);
} catch (error) {
console.error('解析完成事件失败:', error);
}
});
eventSource.addEventListener('close', (event) => {
try {
const data = JSON.parse(event.data);
console.log('连接正常结束:', data);
} catch (error) {
console.error('解析关闭事件失败:', error);
}
window.currentEventSource = null;
});
eventSource.addEventListener('error', (error) => {
console.error('EventSource错误:', error);
if (onError) onError({ error: 'EventSource连接错误' });
window.currentEventSource = null;
});
return eventSource;
} catch (error) {
console.error('创建EventSource失败:', error);
if (onError) onError({ error: error.message });
return null;
}
},
/**
* HTTP 流式请求(仅 H5 使用)
* Fetch API 流式聊天
*/
async sendHttpStream(message, onChunk, onComplete) {
async chatWithFetchStream(message, conversationId = '', onMessage, onComplete, onError) {
try {
let requestData;
let headers = {
'Accept': 'text/event-stream'
};
requestData = {
uniacid: store.state.uniacid || '1',
user_id: store.state.memberInfo?.id || '123456',
query: message,
conversation_id: conversationId || '',
stream: true,
inputs: {},
response_mode: 'streaming',
user: store.state.memberInfo?.id || '123456'
};
headers['Content-Type'] = 'application/json';
const response = await fetch('/api/kefu/chat', {
method: 'POST',
headers: headers,
body: JSON.stringify(requestData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
if (!response.body) {
throw new Error('响应体不可用');
}
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = '';
let aiMessage = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
let lineEnd;
while ((lineEnd = buffer.indexOf('\n')) !== -1) {
const line = buffer.substring(0, lineEnd);
buffer = buffer.substring(lineEnd + 1);
if (line.startsWith('data: ')) {
try {
const data = JSON.parse(line.substring(6));
if (data.event === 'message' || data.event === 'text_message') {
const textContent = data.answer || data.text || '';
aiMessage += textContent;
if (onMessage) onMessage(textContent);
} else if (data.event === 'message_end' || data.event === 'done') {
if (onComplete) onComplete({
conversation_id: data.conversation_id,
message: aiMessage,
...data
});
} else if (data.event === 'error' && onError) {
onError(data);
}
if (data.conversation_id) {
conversationId = data.conversation_id;
}
} catch (e) {
console.warn('解析流式数据失败:', e);
}
}
}
}
if (buffer.startsWith('data: ')) {
try {
const data = JSON.parse(buffer.substring(6));
if ((data.event === 'message' || data.event === 'text_message') && onMessage) {
const textContent = data.answer || data.text || '';
onMessage(textContent);
} else if ((data.event === 'message_end' || data.event === 'done') && onComplete) {
onComplete({
conversation_id: data.conversation_id,
message: aiMessage,
...data
});
}
} catch (e) {
console.warn('解析剩余数据失败:', e);
}
}
} catch (error) {
console.error('Fetch流式聊天请求失败:', error);
if (onError) onError({ error: error.message });
}
},
/**
* HTTP流式请求修复conversationId未定义
*/
async sendHttpStream(message, onChunk, onComplete) {
const params = {
url: '/api/kefu/chat',
data: {
query: message,
conversation_id: '',
user_id: store.state.memberInfo?.id || 'anonymous',
stream: true,
uniacid: store.state.uniacid,
inputs: {},
response_mode: 'streaming',
user: store.state.memberInfo?.id || 'anonymous'
},
header: {
'Content-Type': 'application/json'
}
}
// #ifdef H5
try {
const url = Config.baseUrl + `/api/kefu/chat`;
@@ -179,139 +263,105 @@ export default {
inputs: {},
query: message,
response_mode: 'streaming',
user_id: store.state.memberInfo?.id || 'anonymous',
conversation_id: this.getConversationId() || ''
user_id: store.state.memberInfo?.id || 'anonymous'
})
});
if (!response.ok || !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 reader = response.body.getReader()
const decoder = new TextDecoder()
let content = ''
let buffer = ''
// 修复声明conversationId变量
let conversationId = '';
function processStreamData(buffer, callback) {
const lines = buffer.split('\n');
buffer = 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 data = JSON.parse(jsonStr);
buffer = lines.pop() || '';
lines.forEach(line => {
line = line.trim();
if (!line) return;
if (line.startsWith('data:')) {
const dataPart = line.slice(5).trim();
if (dataPart) {
try {
const data = JSON.parse(dataPart);
if (data.event === 'message') {
const text = data.answer || data.text || '';
content += text;
if (onChunk) onChunk(text);
callback(data.answer || '');
}
if (data.conversation_id) {
conversationId = data.conversation_id;
}
if (data.event === 'message_end') {
// 可提前结束
console.log('对话完成');
}
} catch (error) {
console.error('解析流式数据失败:', error);
}
} catch (e) {
console.warn('解析失败:', e, line);
}
}
}
});
return buffer;
}
// 处理最后残留的 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;
}
while (true) {
const { done, value } = await reader.read()
if (done) break
buffer += decoder.decode(value, { stream: true });
buffer = processStreamData(buffer, (newData) => {
if (newData) {
content += newData;
if (onChunk) onChunk(newData);
}
} catch (e) {
console.warn('最后 buffer 解析失败:', e);
}
});
}
if (onComplete) {
onComplete({ content, conversation_id: conversationId });
}
return { content, conversation_id: conversationId };
if (onComplete) onComplete({ content, conversation_id: conversationId });
return { content, conversation_id: conversationId };
} catch (error) {
console.error('H5 流式请求失败:', error);
throw error;
console.error('HTTP流式请求失败:', error)
throw error
}
// #endif
// #ifndef H5
const response = await http.sendRequest({
...params,
async: false
})
if (response.success && response.data) {
const content = response.data
const chunkSize = 3
let index = 0
const streamInterval = setInterval(() => {
if (index < content.length) {
const chunk = content.substring(index, index + chunkSize)
index += chunkSize
if (onChunk) onChunk(chunk)
} else {
clearInterval(streamInterval)
if (onComplete) onComplete(content)
}
}, 100)
}
// #endif
},
/**
* 处理API响应(统一格式)
* 处理API响应
*/
handleResponse(response) {
handleResponse(response, options) {
if (response.code === 0 || response.success) {
return {
success: true,
content: response.data?.answer || response.data?.content || response.data?.reply || response.data,
content: response.data?.answer || response.data?.content || response.data?.reply|| response.data,
conversationId: response.data?.conversation_id,
messageId: response.data?.message_id
};
} else {
throw new Error(response.message || 'AI服务返回错误');
}
},
/**
* 获取当前会话ID
*/
getConversationId() {
return currentConversationId;
},
/**
* 设置并持久化会话ID
*/
setConversationId(id) {
if (id && id !== currentConversationId) {
currentConversationId = id;
try {
uni.setStorageSync(CONVERSATION_KEY, id);
} catch (e) {
console.error('保存会话ID失败:', e);
}
} else {
throw new Error(response.message || 'AI服务返回错误')
}
},
/**
* 清除会话ID
*/
clearConversationId() {
currentConversationId = null;
try {
uni.removeStorageSync(CONVERSATION_KEY);
} catch (e) {
console.error('清除会话ID失败:', e);
}
},
/**
* 生成新会话(如需)
* 生成会话ID
*/
async generateConversationId() {
const params = {
@@ -324,16 +374,16 @@ export default {
header: {
'Content-Type': 'application/json'
}
};
}
const response = await http.sendRequest({
...params,
async: false
});
return this.handleResponse(response);
})
return this.handleResponse(response)
},
/**
* 获取服务状态
* 获取AI服务状态
*/
async getServiceStatus() {
try {
@@ -341,23 +391,22 @@ export default {
url: '/api/kefu/health',
async: false,
data: {}
});
const available = [response?.data?.status, response?.data?.components?.ai_service_config?.status]
.filter(item => item === 'healthy').length > 0;
})
const available = [response?.data?.status, response?.data?.components?.ai_service_config?.status].filter(item => item === 'healthy').length > 0;
return {
available,
reason: available ? '服务正常' : '服务异常'
};
}
} catch (error) {
return {
available: false,
reason: '服务检查失败'
};
}
}
},
/**
* 清除会话历史(调用后端接口)
* 清除会话历史
*/
async clearConversation(conversationId) {
try {
@@ -365,13 +414,36 @@ export default {
url: '/api/kefu/clear-conversation',
data: { conversation_id: conversationId },
async: false
});
return response.success;
})
return response.success
} catch (error) {
console.error('清除会话失败:', error);
return false;
console.error('清除会话失败:', error)
return false
}
},
getConversationId() {
return currentConversationId;
},
setConversationId(id) {
if (id && id !== currentConversationId) {
currentConversationId = id;
try {
uni.setStorageSync(CONVERSATION_KEY, id);
} catch (e) {
console.error('保存会话ID失败:', e);
}
}
},
clearConversationId() {
currentConversationId = null;
try {
uni.removeStorageSync(CONVERSATION_KEY);
} catch (e) {
console.error('清除会话ID失败:', e);
}
},
/**
* 获取会话历史
@@ -413,80 +485,5 @@ export default {
console.error('获取会话历史失败:', error);
throw new Error(error.message || '获取会话历史时发生错误,请稍后重试');
}
},
// ================================
// 以下方法仅用于 H5小程序无效
// ================================
/**
* [H5 Only] EventSource 流式聊天(备用)
*/
chatWithEventSource(message, conversationId = '', onMessage, onComplete, onError) {
// #ifdef H5
if (window.currentEventSource) {
window.currentEventSource.close();
}
const params = new URLSearchParams({
uniacid: store.state.uniacid || '1',
user_id: store.state.memberInfo?.id || '123456',
query: message,
conversation_id: conversationId || '',
stream: 'true'
});
const url = `${Config.baseUrl}/api/kefu/chat?${params.toString()}`;
try {
const eventSource = new EventSource(url);
window.currentEventSource = eventSource;
let aiMessage = '';
eventSource.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.event === 'message') {
aiMessage += data.answer || '';
if (onMessage) onMessage(data.answer || '');
}
if (data.event === 'message_end') {
if (onComplete) onComplete({
conversation_id: data.conversation_id,
message: aiMessage
});
}
} catch (error) {
console.error('解析消息失败:', error);
}
};
eventSource.onerror = (error) => {
console.error('EventSource错误:', error);
if (onError) onError({ error: '连接失败' });
window.currentEventSource = null;
};
return eventSource;
} catch (error) {
console.error('创建EventSource失败:', error);
if (onError) onError({ error: error.message });
return null;
}
// #endif
// #ifdef MP-WEIXIN
console.warn('chatWithEventSource 不支持微信小程序');
return null;
// #endif
},
/**
* [H5 Only] Fetch 流式聊天(备用)
*/
async chatWithFetchStream(message, conversationId = '', onMessage, onComplete, onError) {
// #ifdef H5
// 实际逻辑已在 sendHttpStream 中实现,此处可复用或留空
return this.sendHttpStream(message, onMessage, (res) => {
onComplete?.({ message: res.content, conversation_id: res.conversation_id });
});
// #endif
// #ifdef MP-WEIXIN
console.warn('chatWithFetchStream 不支持微信小程序');
return null;
// #endif
}
};
}

View File

@@ -1,132 +0,0 @@
// 外置配置管理
// 用于管理需要外置的配置项,如语言包、主题配置等
// 语言包配置
export const langConfig = {
// 语言列表
langList: ['zh-cn', 'en-us'],
// 默认语言
defaultLang: 'zh-cn',
// 语言包加载方式:'lazy'(按需加载)或 'preload'(预加载)
loadMode: 'lazy'
};
// 主题配置
export const themeConfig = {
// 主题列表
themeList: ['default', 'red', 'green', 'blue', 'pink', 'gold', 'purple', 'yellow', 'black'],
// 默认主题
defaultTheme: 'default'
};
// API配置
export const apiConfig = {
// API请求超时时间
timeout: 30000,
// 是否开启重试
retry: true,
// 重试次数
retryCount: 3,
// 重试间隔时间(毫秒)
retryDelay: 1000
};
// 配置外置管理类
class ConfigExternal {
constructor() {
this.loadedConfigs = {};
this.loadPromises = {};
}
/**
* 加载语言包
* @param {string} lang - 语言类型
* @returns {Promise} - 加载结果
*/
async loadLang(lang = langConfig.defaultLang) {
if (this.loadedConfigs[`lang_${lang}`]) {
return this.loadedConfigs[`lang_${lang}`];
}
if (this.loadPromises[`lang_${lang}`]) {
return this.loadPromises[`lang_${lang}`];
}
this.loadPromises[`lang_${lang}`] = new Promise((resolve, reject) => {
try {
// 动态加载语言包
const langData = require(`@/lang/${lang}/common.js`).lang;
this.loadedConfigs[`lang_${lang}`] = langData;
resolve(langData);
} catch (error) {
console.error(`加载语言包 ${lang} 失败:`, error);
reject(error);
}
});
return this.loadPromises[`lang_${lang}`];
}
/**
* 加载页面语言包
* @param {string} lang - 语言类型
* @param {string} pagePath - 页面路径
* @returns {Promise} - 加载结果
*/
async loadPageLang(lang = langConfig.defaultLang, pagePath) {
const key = `page_${lang}_${pagePath}`;
if (this.loadedConfigs[key]) {
return this.loadedConfigs[key];
}
if (this.loadPromises[key]) {
return this.loadPromises[key];
}
this.loadPromises[key] = new Promise((resolve, reject) => {
try {
// 动态加载页面语言包
const pageLangData = require(`@/lang/${lang}/${pagePath}.js`).lang;
this.loadedConfigs[key] = pageLangData;
resolve(pageLangData);
} catch (error) {
console.error(`加载页面语言包 ${lang}/${pagePath} 失败:`, error);
resolve({});
}
});
return this.loadPromises[key];
}
/**
* 加载主题配置(异步方式)
* @param {string} theme - 主题名称
* @returns {Promise} - 加载结果
*/
async loadTheme(theme = themeConfig.defaultTheme) {
if (this.loadedConfigs[`theme_${theme}`]) {
return this.loadedConfigs[`theme_${theme}`];
}
if (this.loadPromises[`theme_${theme}`]) {
return this.loadPromises[`theme_${theme}`];
}
this.loadPromises[`theme_${theme}`] = new Promise((resolve, reject) => {
try {
// 动态加载主题配置
const themeData = require(`@/common/js/style_color.js`)['default'][theme];
console.log('async themeData => ', themeData);
this.loadedConfigs[`theme_${theme}`] = themeData;
resolve(themeData);
} catch (error) {
console.error(`加载主题 ${theme} 失败:`, error);
reject(error);
}
});
return this.loadPromises[`theme_${theme}`];
}
}
export default new ConfigExternal();

View File

@@ -1,81 +1,18 @@
// 发行版本,配置说明
let releaseCfg = undefined;
// #ifdef APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-QQ || MP-TOUTIAO
try {
if (site) { // 从site.js文件中获取配置, 针对微信小程序类
if (site) {
releaseCfg = {
baseUrl: site.baseUrl,
imgDomain: site.baseUrl,
h5Domain: site.baseUrl,
uniacid: site.uniacid,
}
} else {
console.warn('小程序发行环境下必须配置site.js文件, 不然将使用默认配置,影响小程序定制分发!');
}
} catch (e) {}
// #endif
// 线上版本部署域名, 注意: 必须以 '/' 结尾,适用于小程序/H5/快应用等场景
// 默认域名, 自定义发行时可以修改
let defaultDomain = '';
// #ifdef H5_XCX_5G_QUICKAPP_COM
defaultDomain = 'https://xcx20.5g-quickapp.com';
// #endif
// #ifdef H5_XCX_AIGC_QUICKAPP_COM
defaultDomain = 'https://xcx.aigc-quickapp.com/';
// #endif
// #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
// 确保域名以 '/' 结尾
if (defaultDomain && !defaultDomain.endsWith('/')) {
defaultDomain += '/';
}
// 本地调试配置示例文件
// 复制.local.config.js.example 并重命名为 .local.config.js 以使用自定义本地配置
let localDevConfig = { uniacid: 0, domain: defaultDomain };
// #ifndef PRODUCTION
// 尝试动态加载本地配置文件
if (process?.env?.NODE_ENV === 'development') {
try {
// 尝试从项目根目录加载本地配置文件
// 使用相对路径的方式,确保在不同平台下都能正确解析
let customConfig = require('@/.local.config.js').default;
if (customConfig) {
localDevConfig = customConfig;
}
} catch (e) {
// 如果本地配置文件不存在或加载失败,保持使用默认配置
// 只在开发模式下输出提示信息
// #ifdef WEB
console.log('本地配置文件 .local.config.js 不存在,使用默认配置');
// #endif
}
}
// #endif
const { uniacid = 0, domain = defaultDomain } = localDevConfig ?? { uniacid: 0, domain: defaultDomain }
export default {
/**
* 1.开发调试模式
* 去掉注释 ...defaultCfg;
* 注释掉 ...releaseCfg,
* 2.发行/发布模式,例如通过`HBuilder>发行>小程序微信`的时候,原理是:
* 然后将 `import site from "../site.js";`追加到 `unpackage\dist\build\mp-weixin\common\vendor.js` 文件内容开头部分
* 然后将 site.js 文件放到 `unpackage\dist\build\mp-weixin\` 目录下面
*/
// 调试版本,配置说明
const devCfg = {
// 商户ID
uniacid: 1, //825
@@ -89,6 +26,7 @@ export default {
// H5端域名
h5Domain: 'https://dev.aigc-quickapp.com/',
// h5Domain: 'http://localhost:8010/',
// // api请求地址
// baseUrl: 'https://tsaas.liveplatform.cn/',
@@ -107,20 +45,31 @@ export default {
// // H5端域名
// h5Domain: 'http://saas.cn/',
};
// 发行版本配置
...(releaseCfg || {}),
var config = {
/**
* 1.开发调试模式
* 去掉注释 ...devCfg;
* 注释掉 ...releaseCfg,
* 2.发行/发布模式,例如通过`HBuilder>发行>小程序微信`的时候,原理是:
* 然后将 `import site from "../site.js";`追加到 `unpackage\dist\build\mp-weixin\common\vendor.js` 文件内容开头部分
* 然后将 site.js 文件放到 `unpackage\dist\build\mp-weixin\` 目录下面
*/
...(releaseCfg ?? devCfg),
// 腾讯地图key
mpKey: 'TUHBZ-CNWKU-UHAVP-GZQ26-HNZFO-3YBF4',
// 客服地址
//客服地址
webSocket: '{{$webSocket}}',
// 本地端主动给服务器ping的时间, 0 则不开启 , 单位秒
//本地端主动给服务器ping的时间, 0 则不开启 , 单位秒
pingInterval: 1500,
// 版本号
version: '1.0'
};
};
export default config;

View File

@@ -1,511 +0,0 @@
/**
* 客服统一处理服务
* 整合各种客服方式,提供统一的调用接口
*/
export class CustomerService {
constructor(vueInstance, externalConfig = null) {
this.vm = vueInstance;
this.externalConfig = externalConfig; // 外部传入的最新配置(优先级最高)
this.latestPlatformConfig = null;
}
/**
* 强制刷新配置(支持传入外部配置)
* @param {Object} externalConfig 外部最新配置
*/
refreshConfig(externalConfig = null) {
this.externalConfig = externalConfig || this.externalConfig;
this.latestPlatformConfig = null;
return this.getPlatformConfig();
}
/**
* 获取平台配置
* @returns {Object} 平台对应的客服配置
*/
getPlatformConfig() {
if (this.latestPlatformConfig) {
return this.latestPlatformConfig;
}
// 优先级:外部传入的最新配置 > 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) : null;
// #endif
// #ifdef MP-WEIXIN
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) : null;
// #endif
// #ifdef PC
platformConfig = servicerConfig.pc ? (typeof servicerConfig.pc === 'object' ? servicerConfig.pc : null) : null;
// #endif
// 处理空数组情况你的配置中pc/aliapp是空数组转为null
if (Array.isArray(platformConfig)) {
platformConfig = null;
}
this.latestPlatformConfig = platformConfig;
return platformConfig;
}
/**
* 获取企业微信配置
* @returns {Object} 企业微信配置
*/
getWxworkConfig() {
return this.vm.$store.state.wxworkConfig || {};
}
/**
* 检查客服配置是否可用
* @returns {boolean} 是否有可用配置
*/
isConfigAvailable() {
const config = this.getPlatformConfig();
return config && typeof config === 'object' && config.type;
}
/**
* 验证客服配置完整性
* @returns {Object} 验证结果
*/
validateConfig() {
const config = this.getPlatformConfig();
const wxworkConfig = this.getWxworkConfig();
const result = {
isValid: true,
errors: [],
warnings: []
};
if (!config) {
result.isValid = false;
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) {
result.isValid = false;
result.errors.push('企业微信配置不存在');
} else {
if (!wxworkConfig.enable) {
result.warnings.push('企业微信功能未启用');
}
if (!wxworkConfig.contact_url) {
result.warnings.push('企业微信活码链接未配置,将使用原有客服方式');
}
}
}
return result;
}
/**
* 跳转到Dify客服页面
*/
openDifyService() {
try {
if (this.vm.setAiUnreadCount) {
this.vm.setAiUnreadCount(0);
}
// 强制跳转,忽略框架层的封装
uni.redirectTo({
url: '/pages_tool/ai-chat/index',
fail: (err) => {
// 兜底使用window.location跳转H5
// #ifdef H5
window.location.href = '/pages_tool/ai-chat/index';
// #endif
console.error('跳转Dify客服失败:', err);
uni.showToast({
title: '跳转客服失败',
icon: 'none'
});
}
});
} catch (e) {
console.error('跳转Dify客服异常:', e);
uni.showToast({
title: '跳转客服失败',
icon: 'none'
});
}
}
/**
* 处理客服点击事件
* @param {Object} options 选项参数
*/
handleCustomerClick(options = {}) {
const validation = this.validateConfig();
if (!validation.isValid) {
console.error('客服配置验证失败:', validation.errors);
this.showConfigErrorPopup(validation.errors);
return;
}
if (validation.warnings.length > 0) {
console.warn('客服配置警告:', validation.warnings);
}
const config = this.getPlatformConfig();
const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
if (config.type === 'none') {
this.showNoServicePopup();
return;
}
// 核心分支根据最新的type处理
switch (config.type) {
case 'aikefu':
this.openDifyService();
break;
case 'wxwork':
this.openWxworkService(false, config, options);
break;
case 'third':
this.openThirdService(config);
break;
case 'niushop':
this.openNiushopService(niushop);
break;
case 'weapp':
this.openWeappService(config, options);
break;
case 'aliapp':
this.openAliappService(config);
break;
default:
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 (wxworkConfig?.enable && wxworkConfig?.contact_url && !useOriginalService) {
wx.navigateToMiniProgram({
appId: 'wxeb490c6f9b154ef9',
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig.contact_url)}`,
success: () => console.log('跳转企业微信成功'),
fail: (err) => {
console.error('跳转企业微信失败:', err);
this.fallbackToOriginalService();
}
});
} else {
wx.openCustomerServiceChat({
extInfo: { url: config.wxwork_url },
corpId: config.corpid,
showMessageCard: true,
sendMessageTitle,
sendMessagePath,
sendMessageImg
});
}
// #endif
// #ifdef H5
if (wxworkConfig?.enable && wxworkConfig?.contact_url) {
window.location.href = wxworkConfig.contact_url;
} else if (config.wxwork_url) {
location.href = config.wxwork_url;
} else {
this.fallbackToPhoneCall();
}
// #endif
}
/**
* 打开第三方客服
* @param {Object} config 客服配置
*/
openThirdService(config) {
if (config.third_url) {
window.location.href = config.third_url;
} else {
this.fallbackToPhoneCall();
}
}
/**
* 打开牛商客服
* @param {Object} niushop 牛商参数
*/
openNiushopService(niushop) {
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 = {}) {
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 = [];
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: 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.thirdPartyServiceUrl) {
// #ifdef H5
window.open(config.thirdPartyServiceUrl, '_blank');
// #endif
// #ifdef MP-WEIXIN
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) {
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
});
} else {
uni.showToast({
title: '暂无客服电话',
icon: 'none'
});
}
},
fail: () => {
uni.showToast({
title: '获取客服电话失败',
icon: 'none'
});
}
});
}
/**
* 显示无客服弹窗
*/
showNoServicePopup() {
const siteInfo = this.vm.$store.state.siteInfo || {};
const message = siteInfo?.site_tel
? `请联系客服,客服电话是${siteInfo.site_tel}`
: '抱歉,商家暂无客服,请线下联系';
uni.showModal({
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: '无法直接添加企业微信客服,是否使用其他方式联系客服?',
success: (res) => {
if (res.confirm) {
this.openWxworkService(true);
}
}
});
}
/**
* 获取客服按钮配置
* @returns {Object} 按钮配置
*/
getButtonConfig() {
const config = this.getPlatformConfig();
if (!config) return { openType: '' };
let openType = '';
// #ifdef MP-WEIXIN
if (config.type === 'weapp') {
openType = config.useOfficial !== false ? 'contact' : '';
}
// #endif
// #ifdef MP-ALIPAY
if (config.type === 'aliapp') openType = 'contact';
// #endif
return { ...config, openType };
}
/**
* 判断是否应该使用自定义客服处理
* @param {Object} config 客服配置
* @returns {boolean} 是否使用自定义客服
*/
shouldUseCustomService(config) {
// #ifdef MP-WEIXIN
if (config?.type === 'weapp') {
return config.useOfficial === false;
}
// #endif
return true;
}
}
/**
* 创建客服服务实例
* @param {Object} vueInstance Vue实例
* @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 {
@@ -336,11 +334,7 @@ export default {
let diyDataValue = res.data;
if (diyDataValue.value) {
this.diyData = JSON.parse(diyDataValue.value);
// 导航栏标题要根据语言环境切换
const title = this.isEnEnv ? this.diyData?.global?.en_title : this.diyData?.global?.title;
if (title) this.$langConfig.title(title);
this.$langConfig.title(this.diyData.global.title);
this.mpCollect = this.diyData.global.mpCollect;
this.setPublicShare();
/* if (this.diyData.global.popWindow && this.diyData.global.popWindow.imageUrl) {

View File

@@ -110,7 +110,7 @@ class EventBus {
// 异步触发事件,支持取消传播,并支持在监听处理后调用异步函数 defaultAsyncHandler
// 使用方式await eventBus.emit(eventName, data, defaultAsyncHandler)
// defaultAsyncHandler 会在监听器执行后被调用,签名为 defaultAsyncHandler(event, handler, handlerResult)
// defaultAsyncHandler 会在每个监听器执行后被调用,签名为 defaultAsyncHandler(event, handler, handlerResult)
// 如果 defaultAsyncHandler 返回 Promise会等待其 resolve
// 如果 allowContinuePropagation 为 false事件触发后将立即返回不继续传播
// 如果 stopOnError 为 true在任意监听器抛出错误后立即停止传播
@@ -123,7 +123,6 @@ class EventBus {
// helper to call defaultAsyncHandler only when allowed
const callDefaultAsyncHandler = async (evt, handler, handlerResult) => {
// console.log('callDefaultAsyncHandler', {evt, handler, handlerResult});
if (typeof defaultAsyncHandler !== 'function' || !allowAsyncHandlerRun) return
try {
const res = defaultAsyncHandler(evt, handler, handlerResult)
@@ -153,7 +152,7 @@ class EventBus {
return !event.defaultPrevented
}
// 否则继续走普通 EventBus 处理fallthrough
}
}
// 普通 EventBus 触发
const handlers = this.events.get(eventName)
@@ -190,7 +189,6 @@ class EventBus {
}
// 在每个监听器执行后,如果允许并且提供了 defaultAsyncHandler就调用并等待它
// console.log('==> callDefaultAsyncHandler', {event, handler, awaitedResult})
await callDefaultAsyncHandler(event, handler, awaitedResult)
} catch (error) {
console.error(`EventBus ${eventName} error:`, error)

View File

@@ -1,19 +1,25 @@
export default {
onLoad() { },
data() {
return {
// 页面样式,动态设置主色调
themeColor: '' //''--base-color:#fa5d14;--base-help-color:#ff7e00;'
}
},
onLoad() {},
onShow() {
// 刷新多语言
this.$langConfig.refresh();
let time = setInterval(() => {
let theme = this.themeStyle;
if (theme && theme.main_color) {
this.themeColorSet();
clearInterval(time);
}
}, 50);
},
computed: {
// 是否是英文环境
isEnEnv() {
return uni.getStorageSync('lang') === 'en-us';
},
themeStyle() {
return this.$store.state.themeStyle;
},
themeColor() {
return this.$store.state.themeColor;
},
// 插件是否存在
addonIsExist() {
@@ -65,18 +71,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;
},
@@ -109,7 +107,25 @@ export default {
}
},
methods: {
themeColorSet() {
let theme = this.themeStyle;
this.themeColor = `--base-color:${theme.main_color};--base-help-color:${theme.aux_color};`;
if (this.tabBarHeight != '56px') this.themeColor += `--tab-bar-height:${this.tabBarHeight};`
Object.keys(theme).forEach(key => {
let data = theme[key];
if (typeof(data) == "object") {
Object.keys(data).forEach(k => {
this.themeColor += '--' + k.replace(/_/g, "-") + ':' + data[k] + ';';
});
} else if (typeof(key) == "string" && key) {
this.themeColor += '--' + key.replace(/_/g, "-") + ':' + data + ';';
}
});
for (let i = 9; i >= 5; i--) {
let color = this.$util.colourBlend(theme.main_color, '#ffffff', (i / 10));
this.themeColor += `--base-color-light-${i}:${color};`;
}
},
// 颜色变浅(>0、变深函数<0
lightenDarkenColor(color, amount) {
@@ -153,7 +169,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

@@ -183,7 +183,7 @@ export default {
};
if (this.$refs.goodsPromotion) this.$refs.goodsPromotion.refresh(this.goodsSkuDetail.goods_promotion);
if (this.goodsRoute != '/pages_goods/detail') this.setPublicShare();
if (this.goodsRoute != '/pages/goods/detail') this.setPublicShare();
// this.getBarrageData();
if (this.addonIsExist.form) {
@@ -240,11 +240,11 @@ 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; // 开启预览,禁止任何操作和跳转
this.$util.redirectTo('/pages_goods/cart');
this.$util.redirectTo('/pages/goods/cart');
},
//-------------------------------------关注-------------------------------------
//更新商品信息

View File

@@ -49,7 +49,7 @@ export default {
}
var method = params.data != undefined ? 'POST' : 'GET', // 请求方式
url = (Config.baseUrl + params.url).replace(/(?<!:)\/+/g, '/'), // 请求路径
url = Config.baseUrl + params.url, // 请求路径
data = {
app_type,
app_type_name
@@ -57,8 +57,7 @@ export default {
// token
data.token = store.state.token || '';
data.uniacid = uni.getStorageSync('uniacid') || Config.uniacid; // 从缓存中获取uniacid或使用默认uniacid支持快应用
data.uniacid = Config.uniacid
// 门店id
var default_store_info = store.state.defaultStoreInfo;
if (default_store_info) {

View File

@@ -1,161 +1,129 @@
import { langConfig } from './config-external.js';
const langList = ['zh-cn', 'en-us'];
// 缓存已加载的语言
const loadedLangPacks = {};
// 处理页面目录映射
function processRoutePath(route) {
let routeParts = route.split("/");
// ---- 处理页面目录映射 <begin> 分包造成的,需要根据实际目录结构进行映射----
if (routeParts[0] === 'pages_tool') {
routeParts = [routeParts[1], ...routeParts.slice(2)];
} else if (routeParts[0] === 'pages_goods') {
routeParts[0] = 'goods';
} else if (routeParts[0] === 'pages_member') {
routeParts[0] = 'member';
} else if (routeParts[0] === 'pages_order') {
routeParts[0] = 'order';
} else if (routeParts[0] === 'pages_promotion') {
const promotionModules = ['point', 'fenxiao', 'merch'];
if (routeParts[1] && promotionModules.includes(routeParts[1])) {
routeParts = [routeParts[1], ...routeParts.slice(2)];
}
}
// ---- 处理页面目录映射 <end>----
if (routeParts[0] === 'pages') {
routeParts = routeParts.slice(1);
}
return routeParts.join("/");
}
// 加载语言包(同步方式)
function loadLangPackSync(lang, path) {
try {
if (loadedLangPacks[`${lang}_${path}`]) {
return loadedLangPacks[`${lang}_${path}`];
}
const langData = require(`@/lang/${lang}/${path}.js`).lang;
loadedLangPacks[`${lang}_${path}`] = langData;
return langData;
} catch (error) {
console.error(`加载语言包 ${lang}/${path} 失败:`, error);
return {};
}
}
var locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
export default {
langList: langConfig.langList,
/**
* 解析多语言
*/
lang(field) {
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
langList: ['zh-cn', 'en-us'],
/**
* * 解析多语言
* @param {Object} field
*/
lang(field) {
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
const locale = uni.getStorageSync('lang') || "zh-cn";
var value = '';
let newRoute;
try {
//公共语言包
var lang = require('../../lang/' + locale + '/common.js').lang;
//当前页面语言包
let route = _this.route.split("/");
newRoute = route.slice(1, route.length);
let currentPageLang = require('../../lang/' + locale + '/' + newRoute.join("/") + '.js').lang;
let value = '';
let langPath = '';
for (let f in currentPageLang) {
lang[f] = currentPageLang[f];
}
try {
var lang = loadLangPackSync(locale, 'common');
let route = _this.route;
langPath = processRoutePath(route);
let currentPageLang = loadLangPackSync(locale, langPath);
var arr = field.split(".");
if (arr.length > 1) {
for (let i in arr) {
var next = parseInt(i) + 1;
if (next < arr.length) {
value = lang[arr[i]][arr[next]];
}
}
} else {
value = lang[field];
}
} catch (e) {
if (field.indexOf("common.") != -1 || field.indexOf("tabBar.") != -1) {
value = lang[field];
} else {
value = field;
}
}
let mergedLang = { ...lang, ...currentPageLang };
if (arguments.length > 1) {
//有参数,需要替换
for (var i = 1; i < arguments.length; i++) {
value = value.replace("{" + (i - 1) + "}", arguments[i]);
}
}
if (value == undefined || (value == 'title' && field == 'title')) value = ''; // field
return value;
},
//切换语言
change(value) {
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
var arr = field.split(".");
if (arr.length > 1) {
let temp = mergedLang;
let found = true;
for (let key of arr) {
if (temp[key] !== undefined) {
temp = temp[key];
} else {
found = false;
break;
}
}
value = found ? temp : field;
} else {
value = mergedLang[field] !== undefined ? mergedLang[field] : field;
}
} catch (e) {
console.error('解析语言包失败:', e, { langPath, field, locale });
value = field;
}
uni.setStorageSync("lang", value);
locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
this.refresh();
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
value = value.replace("{" + (i - 1) + "}", arguments[i]);
}
}
if (value == undefined || (value == 'title' && field == 'title')) value = '';
uni.reLaunch({
url: '/pages/member/index'
});
},
//刷新标题、tabbar
refresh() {
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
this.title(this.lang("title"));
if (field == value) {
console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
}
return value;
},
/**
* 切换语言
*/
change(value, url = '/pages_tool/member/index') {
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
uni.setStorageSync("lang", value);
const locale = uni.getStorageSync('lang') || "zh-cn";
// ✅ 关键修复:清空所有语言包缓存(不再保留任何旧缓存)
for (let key in loadedLangPacks) {
delete loadedLangPacks[key];
}
this.refresh();
if (url) {
uni.reLaunch({ url: url });
}
},
//刷新标题、tabbar
refresh() {
let _this = getCurrentPages()[getCurrentPages().length - 1];
if (!_this) return;
const locale = uni.getStorageSync('lang') || "zh-cn";
this.title(this.lang("title"));
},
title(str) {
if (str) {
uni.setNavigationBarTitle({
title: str
});
}
},
// 获取语言包列表
list() {
var list = [];
try {
for (var i = 0; i < langConfig.langList.length; i++) {
let langType = langConfig.langList[i];
let item = loadLangPackSync(langType, 'common');
list.push({
name: item.common ? item.common.name : langType,
value: langType
});
}
} catch (e) {
console.error('获取语言包列表失败:', e);
}
return list;
}
}
//设置tabbar的文字语言
// uni.setTabBarItem({
// index: 0,
// text: this.lang("tabBar.home")
// });
// uni.setTabBarItem({
// index: 1,
// text: this.lang("tabBar.category")
// });
// uni.setTabBarItem({
// index: 2,
// text: this.lang("tabBar.cart")
// });
// uni.setTabBarItem({
// index: 3,
// text: this.lang("tabBar.member")
// });
},
title(str) {
if (str) {
uni.setNavigationBarTitle({
title: str,
success: function (res) {
},
fail: function (err) {
}
});
}
},
// 获取语言包列表
list() {
var list = [];
try {
//公共语言包
for (var i = 0; i < langList.length; i++) {
let item = require('../../lang/' + langList[i] + '/common.js').lang;
list.push({
name: item.common.name,
value: langList[i]
});
}
} catch (e) {
// "没有找到语言包:", '../../lang/' + locale + '/common.js'
}
return list;
}
}

View File

@@ -1,4 +1,3 @@
import util from '@/common/js/util.js'
import TransformCoordinate from './transformCoordinate.js'
function openMapByDefault(latitude, longitude, name) {
@@ -86,8 +85,7 @@ export default {
openMap(latitude, longitude, name, coord_type = 'gcj02') {
let arr = getCoordByType(longitude, latitude, coord_type)
// #ifdef APP-PLUS
let platform = util.getDeviceInfo().platform;
switch (platform) {
switch (uni.getSystemInfoSync().platform) {
case 'android':
console.log('运行Android上')
openMapByAndroid(arr[1], arr[0], name)

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() {
@@ -60,7 +59,7 @@ export class NavigationHelper {
// 微信小程序精确计算
try {
const menuButtonInfo = wx.getMenuButtonBoundingClientRect()
let systemInfo = util.getDeviceInfo();
const systemInfo = uni.getSystemInfoSync()
const height = menuButtonInfo.bottom +
(menuButtonInfo.top - systemInfo.statusBarHeight)
@@ -120,7 +119,7 @@ export class NavigationHelper {
// 获取状态栏高度
getStatusBarHeight() {
// #ifdef MP-WEIXIN
let systemInfo = util.getDeviceInfo();
const systemInfo = uni.getSystemInfoSync()
return systemInfo.statusBarHeight || 20
// #endif
// #ifdef H5
@@ -139,7 +138,7 @@ export class NavigationHelper {
// 获取安全区域
getSafeAreaInsets() {
try {
let systemInfo = util.getDeviceInfo();
const systemInfo = uni.getSystemInfoSync()
return systemInfo.safeArea || {
top: 0,
bottom: 0,

View File

@@ -1,460 +1,419 @@
/**
* 颜色配置
* 包含默认颜色和其他颜
* 特别注意:
* 1. 分组不会被计算成Key分组下的属性会被计算成Key
* 2. 分组下的属性如果有相同的Key会被覆盖
* 3. 例如hoverNavhoverNav_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

@@ -5,135 +5,16 @@ import {
Weixin
} from 'common/js/wx-jssdk.js';
// 关于页面路径,使用常量导出
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';
// 当前最新的tabBar.list (参见pages.json 中的tabBar.list 配置)
export const systemTabBarList = [
INDEX_PAGE_URL,
CATEGORY_PAGE_URL,
CONTACT_PAGE_URL,
MEMBER_PAGE_URL
];
/**
* 适配子包路径
* @param {string} url
* @returns
*/
export const adaptSubpackageUrl = (url) => {
/**
* 特别注意:
* 由于老版本或者后台系统服务未同步更新可以作为tabBarList的最新分包路径。历史遗留问题需要与当前最新分包机制版本保持一致。
* 系统当前的支持tarbarList包含动态tabBar,注意这是实际分包后的路径
* 根据匹配映射关系修改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/',
};
// 构建正则表达式
const regex = new RegExp(
Object.keys(urlPrefixMap).map(key =>
key.replace(/\//g, '\\/').replace(/\*/g, '.*')
).join('|'),
'g'
);
// 替换函数
function replacePrefix(str) {
return str.replace(regex, match => {
for (const [oldPrefix, newPrefix] of Object.entries(urlPrefixMap)) {
if (match.startsWith(oldPrefix)) {
return match.replace(oldPrefix, newPrefix);
}
}
return match; // 默认返回原匹配
});
}
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,
/**
* 页面跳转
* @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);
let tabbarList = ['/pages/index/index', '/pages/goods/category', '/pages/vr/index', '/pages/contact/contact', '/pages/member/index'];
if (param != undefined) {
Object.keys(param).forEach(function (key) {
if (url.indexOf('?') != -1) {
@@ -143,40 +24,35 @@ export default {
}
});
}
// 针对tabBar.list中的路径直接切换tabBar
for (let i = 0; i < systemTabBarList.length; i++) {
const tabBarUrl = systemTabBarList[i];
if (url.indexOf(tabBarUrl) == 0) {
// 首页特殊处理采用switchTab, 其他页面采用redirectTo, 不能返回,不能退回
(tabBarUrl == INDEX_PAGE_URL ? uni.switchTab : uni.redirectTo)({ url });
for (let i = 0; i < tabbarList.length; i++) {
if (url.indexOf(tabbarList[i]) == 0) {
uni.switchTab({
url
});
return;
}
}
// 如果url不包含tabBarList中的路径根据mode判断跳转方式
switch (mode) {
case 'tabbar':
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。重置页面栈,仅保留 tabBar 页面
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
uni.switchTab({
url
});
break;
case 'redirectTo':
// 关闭当前页面,跳转到应用内的某个页面。替换栈顶页面长度不变上限10层
// 关闭当前页面,跳转到应用内的某个页面。
uni.redirectTo({
url
});
break;
case 'reLaunch':
// 关闭所有页面,打开到应用内的某个页面。清空栈后打开新页面,长度=1
// 关闭所有页面,打开到应用内的某个页面。
uni.reLaunch({
url
});
break;
default:
// 保留当前页面,跳转到应用内的某个页面,新增页面到栈顶,长度+1上限10层
console.log('保留当前页面navigateTo跳转到应用内的某个页面', url);
// 保留当前页面,跳转到应用内的某个页面
uni.navigateTo({
url
});
@@ -188,6 +64,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) {
@@ -203,7 +81,7 @@ export default {
// if(img_path.indexOf('attachment') == -1){
// img_path = arr.join(".");
// }
}
if (img_path.indexOf("http://") == -1 && img_path.indexOf("https://") == -1) {
path = Config.imgDomain + "/" + img_path;
@@ -212,7 +90,7 @@ export default {
path = img_path;
}
}
// path += '?t=' + parseInt(new Date().getTime() / 1000);
return path;
},
@@ -501,36 +379,6 @@ export default {
return false;
}
},
/**
* 判断是否在微信小程序的web-view中打开H5
* @returns {boolean} 是否在微信小程序的web-view中
*/
isWeChatMiniProgram() {
const userAgent = navigator.userAgent.toLowerCase();
// 微信小程序的web-view User-Agent会包含以下特征之一
const miniProgramIndicators = [
'miniprogram', // 普通微信小程序
'wxwork', // 企业微信小程序
'micromessenger/[0-9]+\.[0-9]+\.[0-9]+ nettype/wifi wxwebviewtype/1'
];
return miniProgramIndicators.some(indicator => {
if (typeof indicator === 'string' && indicator.includes('/')) {
// 正则表达式匹配
const regex = new RegExp(indicator, 'i');
return regex.test(userAgent);
}
return userAgent.includes(indicator);
});
},
/**
* 判断是否在微信浏览器中打开H5非小程序的web-view
* @returns {boolean} 是否在微信浏览器中打开的H5
*/
isWeChatBrowser() {
return isWeiXin() && !isWeChatMiniProgram();
},
/**
* 显示消息提示框
* @param {Object} params 参数
@@ -547,7 +395,7 @@ export default {
* 检测苹果X以上的手机
*/
isIPhoneX() {
let res = this.getDeviceInfo();
let res = uni.getSystemInfoSync();
if (res.model.search('iPhone X') != -1) {
return true;
}
@@ -555,33 +403,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
@@ -603,46 +431,16 @@ export default {
}
return cloneObj
},
/**
* 打开微信企业客服
* @param {Function} fallbackFunc 降级处理函数
*/
openWxWorkServiceChat(fallbackFunc) {
// #ifdef MP-WEIXIN
let wxworkConfig = store.state?.wxworkConfig
if (wxworkConfig?.enable && wxworkConfig?.contact_url) {
// 直接使用活码链接跳转
wx.navigateToMiniProgram({
appId: 'wxeb490c6f9b154ef9', // 是企业微信官方小程序的AppID固定值, 由腾讯企业微信团队维护, 不需要修改,用于展示"添加企业微信联系人"的官方页面)
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig?.contact_url)}`,
success: () => {
console.log('跳转企业微信成功');
},
fail: (err) => {
console.error('跳转企业微信失败:', err);
// 降级处理:使用原有客服方式
fallbackFunc && fallbackFunc();
}
});
} else {
fallbackFunc && fallbackFunc();
}
// #endif
},
/**
* 自定义模板的跳转链接
* @param {Object} link
*/
diyRedirectTo(link) {
//if (link == null || Object.keys(link).length == 1) return;
// 外部链接
if (link.wap_url && link.wap_url.indexOf('http') != -1) {
if (link.wap_url && link.wap_url.indexOf('http') != -1 || link.wap_url && link.wap_url.indexOf('http') != -1) {
// #ifdef H5
window.location.href = link.wap_url;
// #endif
@@ -696,19 +494,16 @@ export default {
// #endif
// #ifdef MP-WEIXIN
this.openWxWorkServiceChat(() => {
wx.openCustomerServiceChat({
extInfo: {
url: config.wxwork_url
},
corpId: config.corpid,
showMessageCard: true,
sendMessageTitle: 'this.sendMessageTitle',
sendMessagePath: 'this.sendMessagePath',
sendMessageImg: 'this.sendMessageImg'
});
wx.openCustomerServiceChat({
extInfo: {
url: config.wxwork_url
},
corpId: config.corpid,
showMessageCard: true,
sendMessageTitle: 'this.sendMessageTitle',
sendMessagePath: 'this.sendMessagePath',
sendMessageImg: 'this.sendMessageImg'
});
// #endif
break;
case 'third':
@@ -759,7 +554,7 @@ export default {
*/
uniappIsIPhoneX() {
let isIphoneX = false;
let systemInfo = this.getDeviceInfo();
let systemInfo = uni.getSystemInfoSync();
// #ifdef MP
if (systemInfo.model.search('iPhone X') != -1 || systemInfo.model.search('iPhone 11') != -1 || systemInfo.model.search('iPhone 12') != -1 || systemInfo.model.search('iPhone 13') != -1) {
isIphoneX = true;
@@ -786,7 +581,7 @@ export default {
*/
uniappIsIPhone11() {
let isIphone11 = false;
let systemInfo = this.getDeviceInfo();
let systemInfo = uni.getSystemInfoSync();
// #ifdef MP
if (systemInfo.model.search('iPhone 11') != -1) {
isIphone11 = true;
@@ -797,7 +592,7 @@ export default {
// #ifdef H5
//判断该浏览器是否为safaria浏览器
isSafari() {
let res = this.getDeviceInfo();
let res = uni.getSystemInfoSync();
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf('applewebkit') > -1 && ua.indexOf('mobile') > -1 && ua.indexOf('safari') > -1 &&
ua.indexOf('linux') === -1 && ua.indexOf('android') === -1 && ua.indexOf('chrome') === -1 &&
@@ -836,7 +631,7 @@ 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 {
@@ -912,12 +707,11 @@ export default {
* 微信订阅消息
*/
subscribeMessage(keywords) {
let url = ""
// #ifdef MP-WEIXIN
url = '/weapp/api/weapp/messagetmplids';
let url = '/weapp/api/weapp/messagetmplids';
// #endif
// #ifdef MP-ALIPAY
url = '/aliapp/api/aliapp/messagetmplids';
let url = '/aliapp/api/aliapp/messagetmplids';
// #endif
Http.sendRequest({
url,
@@ -961,7 +755,7 @@ export default {
if (!path) {
let route = this.getCurrentRoute();
path = route.path;
if (path == '/pages_tool/member/index') {
if (path == '/pages/member/index') {
return new Promise((resolve, reject) => {
resolve({})
});
@@ -1126,11 +920,11 @@ export default {
var points_E = [];
const DIST_AB = Math.sqrt(Math.pow(points[1]['x'] - points[0]['x'], 2) + Math.pow(points[1]['y'] - points[0][
'y'
], 2));
], 2));
// 邻控制BC点间距
const DIST_BC = Math.sqrt(Math.pow(points[2]['x'] - points[1]['x'], 2) + Math.pow(points[2]['y'] - points[1][
'y'
], 2));
], 2));
// D每次在AB方向上移动的距离
if (points[0]['x'] > points[2]['x']) {
var EACH_MOVE_AD = -(DIST_AB / times);
@@ -1192,47 +986,5 @@ export default {
verifyMobile(mobile) {
var parse = /^\d{11}$/.test(mobile);
return parse;
},
/**
* 判断是否为快应用环境
* @returns {boolean} 是否为快应用
*/
isQuickApp() {
// #ifndef QUICKAPP-WEBVIEW
let _isQuickApp = false;
try {
const ua = navigator?.userAgent?.toLowerCase();
console.log('ua = ', ua);
_isQuickApp = ua.indexOf('quickapp') !== -1;
if (!_isQuickApp) {
// 特殊说明由于网站是嵌入到快应用的Webview组件中<web>UA中不会包含quickapp字符串
// 但是会包含uniacid参数所以这里通过uniacid参数来判断是否为快应用环境
_isQuickApp = ua.indexOf('uniacid=') !== -1;
}
} catch (e) {}
if (!_isQuickApp) {
const systemInfo = this.getDeviceInfo();
_isQuickApp = systemInfo?.platform === 'quickapp' || process?.env?.UNI_PLATFORM === 'quickapp';
}
return _isQuickApp;
// #endif
return true;
},
/**
* 判断是否为华为快应用环境
* @returns {boolean} 是否为华为快应用
*/
isHuaweiQuickApp() {
if (!this.isQuickApp()) return false;
// #ifndef QUICKAPP-WEBVIEW-HUAWEI
const systemInfo = this.getDeviceInfo();
return systemInfo.brand === 'HUAWEI' || systemInfo.manufacturer === 'HUAWEI' ||
(typeof qh !== 'undefined' && qh.platform === 'huawei');
// #endif
return true;
}
}

View File

@@ -1,187 +0,0 @@
/**
* 企业微信JS-SDK调用
*/
let WxWork = function () {
// 企业微信JS-SDK
this.wxwork = null;
/**
* 初始化企业微信JS-SDK
* @param {Object} params - 初始化参数
* @param {string} params.corpId - 企业ID
* @param {string} params.agentId - 应用ID
* @param {string} params.timestamp - 时间戳
* @param {string} params.nonceStr - 随机字符串
* @param {string} params.signature - 签名
* @param {Array} params.jsApiList - 需要使用的JS接口列表
*/
this.init = function (params) {
if (typeof wx !== 'undefined' && wx.config) {
// 小程序环境下的企业微信
this.wxwork = wx;
} else if (typeof WWOpenData !== 'undefined') {
// H5环境下的企业微信
this.wxwork = WWOpenData;
} else {
console.error('企业微信JS-SDK未加载');
return false;
}
this.wxwork.config({
beta: true, // 必须这么写否则wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式
corpId: params.corpId, // 必填,企业号的唯一标识
agentId: params.agentId, // 必填企业微信应用ID
timestamp: params.timestamp, // 必填,生成签名的时间戳
nonceStr: params.nonceStr, // 必填,生成签名的随机串
signature: params.signature, // 必填,签名
jsApiList: params.jsApiList || [
'openUserProfile',
'openEnterpriseChat',
'getContext',
'getCurExternalContact',
'openExistedChatWithMsg'
] // 必填需要使用的JS接口列表
});
return true;
};
/**
* 添加企业微信联系人
* @param {Object} params - 参数
* @param {string} params.userId - 用户ID
* @param {Function} success - 成功回调
* @param {Function} fail - 失败回调
*/
this.addContact = function (params, success, fail) {
if (!this.wxwork) {
console.error('企业微信JS-SDK未初始化');
if (fail) fail('企业微信JS-SDK未初始化');
return;
}
this.wxwork.ready(() => {
this.wxwork.invoke('openUserProfile', {
type: 'external', // 外部联系人
userId: params.userId // 用户ID
}, (res) => {
if (res.err_msg === 'openUserProfile:ok') {
if (success) success(res);
} else {
console.error('打开用户资料失败:', res);
if (fail) fail(res.err_msg);
}
});
});
};
/**
* 打开企业微信客服会话
* @param {Object} params - 参数
* @param {string} params.corpId - 企业ID
* @param {string} params.url - 客服URL
* @param {string} params.name - 会话名称
* @param {Function} success - 成功回调
* @param {Function} fail - 失败回调
*/
this.openCustomerService = function (params, success, fail) {
if (!this.wxwork) {
console.error('企业微信JS-SDK未初始化');
if (fail) fail('企业微信JS-SDK未初始化');
return;
}
this.wxwork.ready(() => {
// #ifdef MP-WEIXIN
if (typeof wx !== 'undefined' && wx.openCustomerServiceChat) {
// 微信小程序环境
wx.openCustomerServiceChat({
extInfo: {
url: params.url
},
corpId: params.corpId,
showMessageCard: true,
sendMessageTitle: params.sendMessageTitle || '',
sendMessagePath: params.sendMessagePath || '',
sendMessageImg: params.sendMessageImg || ''
});
if (success) success();
}
// #endif
// #ifdef H5
else if (typeof WWOpenData !== 'undefined') {
// H5环境
window.location.href = params.url;
if (success) success();
}
// #endif
else {
// 直接跳转链接
window.location.href = params.url;
if (success) success();
}
});
};
/**
* 生成企业微信活码链接
* @param {Object} params - 参数
* @param {string} params.configId - 活码配置ID
* @param {string} params.userId - 用户ID
* @returns {string} 活码链接
*/
this.generateContactUrl = function (params) {
// 企业微信活码链接格式
const baseUrl = 'https://work.weixin.qq.com/kfid';
if (params.configId) {
return `${baseUrl}/${params.configId}`;
}
return null;
};
/**
* 检查环境是否支持企业微信
* @returns {boolean} 是否支持
*/
this.isSupported = function () {
// #ifdef MP-WEIXIN
return typeof wx !== 'undefined' && wx.openCustomerServiceChat;
// #endif
// #ifdef H5
return typeof WWOpenData !== 'undefined' || /wxwork/i.test(navigator.userAgent);
// #endif
return false;
};
/**
* 获取当前环境信息
* @returns {Object} 环境信息
*/
this.getEnvironment = function () {
// #ifdef MP-WEIXIN
return {
platform: 'miniprogram',
isWxWork: false,
supportContact: typeof wx !== 'undefined' && wx.openCustomerServiceChat
};
// #endif
// #ifdef H5
const isWxWork = /wxwork/i.test(navigator.userAgent);
return {
platform: 'h5',
isWxWork: isWxWork,
supportContact: isWxWork || typeof WWOpenData !== 'undefined'
};
// #endif
return {
platform: 'unknown',
isWxWork: false,
supportContact: false
};
};
}
export {
WxWork
}

View File

@@ -1,265 +0,0 @@
<template>
<x-skeleton data-component-name="diy-article" type="list" :loading="loading" :configs="skeletonConfig">
<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"
: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" @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)" />
</view>
<view class="info-wrap">
<text class="title">{{ item.article_title }}</text>
<text class="desc"
style="color:#888;font-size: 24rpx; display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;text-overflow: ellipsis;">{{
item.article_abstract }}</text>
<view class="read-wrap">
<block v-if="item.category_name">
<text class="category-icon"></text>
<text>{{ item.category_name }}</text>
</block>
<text class="date">{{ $util.timeStampTurnTime(item.create_time, 'date')
}}</text>
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
</x-skeleton>
</template>
<script>
import DiyMinx from './minx.js'
// 文章
export default {
name: 'diy-article',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
list: [],
loading: true,
skeletonConfig: {
gridRows: 1,
gridRowsGap: '40rpx',
headWidth: '160rpx',
headHeight: '160rpx',
textRows: 2
}
};
},
created() {
this.getList();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getList();
}
},
computed: {
// 获取swiper配置默认空对象
swiperConfig() {
return this.value?.swiperConfig || {};
},
// 安全的display-multiple-items值确保不大于swiper-item数量
safeDisplayMultipleItems() {
const displayCount = this.swiperConfig.displayMultipleItems || 3;
const actualCount = this.list.length;
return actualCount > 0 ? Math.min(displayCount, actualCount) : 1;
},
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
},
// swiper容器样式
swiperStyle() {
// 从swiperConfig获取高度默认600rpx
const height = this.swiperConfig.swiperHeight || 600;
return {
height: height + 'rpx',
width: '100%'
};
},
// 子项样式
itemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color;
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color;
}
return obj;
}
},
methods: {
getList() {
var data = {
num: this.value.count
};
if (this.value.sources == 'diy') {
data.num = 0;
data.article_id_arr = this.value.articleIds.toString();
}
this.$api.sendRequest({
url: '/api/article/lists',
data: data,
success: res => {
if (res.code == 0 && res.data) {
let data = res.data;
this.list = data;
}
this.loading = false;
}
});
},
toDetail(item) {
this.$util.redirectTo('/pages_tool/article/detail', {
article_id: item.article_id
});
},
imgError(index) {
if (this.list[index]) this.list[index].cover_img = this.$util.getDefaultImage().article;
}
}
};
</script>
<style lang="scss">
.article-wrap {
.list-wrap {
.auto-scroll-swiper {
height: 600rpx;
/* 可以根据需要调整高度 */
width: 100%;
.swiper-item-content {
padding: 10rpx 20rpx;
box-sizing: border-box;
}
}
.item {
margin: 0;
margin-bottom: 24rpx;
}
.style-1 .item {
padding: 20rpx;
}
&.style-1 {
.item {
display: flex;
margin-top: 0;
&:first-of-type {
margin-top: 0;
}
.article-img {
margin-right: 20rpx;
width: 160rpx;
height: 160rpx;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
image {
width: 100%;
}
}
.info-wrap {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
font-weight: bold;
margin-bottom: 10rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: 30rpx;
line-height: 1.5;
}
.abstract {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: $font-size-tag;
}
.read-wrap {
display: flex;
color: #999ca7;
justify-content: flex-start;
align-items: center;
margin-top: 10rpx;
line-height: 1;
text {
font-size: $font-size-tag;
}
.iconfont {
font-size: 36rpx;
vertical-align: bottom;
margin-right: 10rpx;
}
.category-icon {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: $base-color;
margin-right: 10rpx;
}
.date {
margin-left: 20rpx;
}
}
}
}
}
}
}
</style>

View File

@@ -1,453 +0,0 @@
<template>
<view data-component-name="diy-audio">
<view class="fui-audio style1" :style="{ background: value.background }" v-if="value.type == 'style-2'">
<view class="content" style="padding-top: 20rpx;">
<view class="name" :style="{ color: value.textcolor }">{{ value.text }}</view>
<view class="author" :style="{ color: value.subtitlecolor }">{{ value.desc }}----{{ value.id }}</view>
</view>
<view class="progress">
<view class="progressBar" :style="{ width: audiowidth }"></view>
</view>
<view class="time" :style="{ color: value.timecolor }">
{{ audiotime }}
</view>
<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)"></image>
</view>
<view class="content">
<view class="name" :style="{ color: value.textcolor }">{{ value.text }}</view>
<view class="author" :style="{ color: value.subtitlecolor }">{{ value.desc }}</view>
</view>
<view class="progress">
<view class="progressBar" :style="{ width: audiowidth }"></view>
</view>
<view class="time" :style="{ color: value.timecolor }">
<!-- {{audios[value.id].audiotime}} -->
{{ audiotime }}
</view>
<view @click="play()" class="start" :class="status ? 'iconj icon-07zanting' : 'iconj icon-bofang'"></view>
</view>
</view>
</template>
<script>
import DiyMinx from './minx.js'
// 音频
export default {
name: 'diy-audio',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
audiosObj: [],
audios: {},
audioContext: null,
audiotime: '00:01',
audiowidth: 0,
status: 0,//1播放0停止
};
},
created() {
// console.log(this.value)
this.audios[this.value.id] = {
audiotime: '00:01',
audiowidth: 0
}
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
videoWarpCss: function () {
var obj = '';
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;
}
},
methods: {
play() {
var t = this.value.id, a = this.audiosObj[t] || !1;
var e = {
audio: this.$util.img(this.value.audioUrl),
}
if (!a) {
a = uni.createInnerAudioContext("audio_" + t);
var i = this.audiosObj;
i[t] = a, this.audiosObj = i
// uni.setStorageSync('audio_list',audio_list)
var audio_list = uni.getStorageSync('audio_list') ? uni.getStorageSync('audio_list') : []
if (audio_list.includes(t) == false) {
audio_list.push(t)
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);
s < 10 && (s = "0" + s);
var u = s + ":" + o, c = n.audios;
// console.log(i)
c[t].audiowidth = i, c[t].Time = e, c[t].audiotime = u, c[t].seconds = r, n.audios = c;
}, 1e3);
});
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, 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;
// console.log(this.audiosObj[this.value.id]);
var i = this.audiosObj[this.value.id], a = this.value.id
// console.log(i)
// console.log(a)
// if (a != e) {
// i.pause();
// var n = t.audios;
// n[a] && (n[a].status = !1, this.audios=n);
// }
var audios = document.getElementsByTagName("audio");
// 暂停函数
function pauseAll() {
var self = this;
[].forEach.call(audios, function (i) {
// 将audios中其他的audio全部暂停
i !== self && i.pause();
})
}
// 给play事件绑定暂停函数
[].forEach.call(audios, function (i) {
i.addEventListener("play", pauseAll.bind(i));
})
// var audio_list = uni.getStorageSync('audio_list')
// audio_list.forEach(function(value, index) {
// if (value != e) {
// console.log(e)
// uni.createInnerAudioContext("audio_" + value).pause();
// }
// });
// this.audiosObj.forEach(function(value, index) {
// console.log(value);
// });
// this.each(this.audiosObj, function(a, i) {
// if (a != e) {
// i.pause();
// var n = t.data.audios;
// n[a] && (n[a].status = !1, t.setData({
// audios: n
// }));
// }
// });
},
play_bak() {
var t = this.value.id
this.audioContext = uni.createInnerAudioContext("audio_" + this.value.id);
this.audioContext.src = this.$util.img(this.value.audioUrl);
var that = this
if (this.status == 1) {
this.audioContext.pause();
this.status = 0
return false
}
this.audioContext.play();
this.status = 1
this.audioContext.onCanplay(function (s) {
var e = setInterval(function () {
var i = parseFloat(that.audioContext.currentTime) / parseFloat(that.audioContext.duration) * 100 + "%", s = Math.floor(Math.ceil(that.audioContext.currentTime) / 60), o = (Math.ceil(that.audioContext.currentTime) % 60 / 100).toFixed(2).slice(-2), r = Math.ceil(that.audioContext.currentTime);
s < 10 && (s = "0" + s);
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
});
}
}
};
</script>
<style scoped>
.fui-audio {
width: 100%;
border: 1rpx solid #eeeeee;
padding: 0 30rpx 0 20rpx;
box-sizing: border-box;
position: relative;
overflow: hidden;
background: #fff;
}
.fui-audio .img {
width: 100rpx;
height: 100rpx;
background: #000;
}
.fui-audio .img image {
width: 100%;
height: 100%;
}
.fui-audio .name {
font-size: 26rpx;
color: #333;
}
.fui-audio .author {
font-size: 26rpx;
color: #666;
}
.fui-audio .time {
font-size: 24rpx;
color: #999;
}
.fui-audio .start {
border: 0;
padding: 0;
margin: 0;
font-size: 28rpx;
}
.progressBar {
height: 2rpx;
width: 0;
background: #333;
}
.fui-audio.style1 {
height: 86rpx;
line-height: 82rpx;
}
.fui-audio.style1 .img,
.fui-audio.style2 .img {
display: none;
}
.fui-audio.style1 .name,
.fui-audio.style2 .name {
float: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 300rpx;
}
.fui-audio.style1 .author,
.fui-audio.style2 .author {
float: left;
margin-left: 12rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200rpx;
}
.fui-audio.style1 .time,
.fui-audio.style4 .time {
display: none;
}
.fui-audio.style1 .start {
position: absolute;
top: 0rpx;
right: 40rpx;
width: 40rpx;
height: 40rpx;
color: #000;
}
.fui-audio.style1 .progress {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
.fui-audio.style2 {
height: 86rpx;
line-height: 82rpx;
}
.fui-audio.style2 .img {
display: none;
}
.fui-audio.style2 .time {
position: absolute;
top: 0;
right: 30rpx;
}
.fui-audio.style2 .name {
margin-left: 70rpx;
}
.fui-audio.style2 .start {
position: absolute;
top: 0rpx;
left: 30rpx;
width: 30rpx;
height: 30rpx;
color: #000;
}
.fui-audio.style2 .progress,
.fui-audio.style3 .progress {
display: none;
}
.fui-audio.style3 {
padding: 8rpx;
}
.fui-audio.style3 .start {
position: absolute;
top: 30rpx;
left: 28rpx;
width: 56rpx;
height: 56rpx;
color: #fff;
/* border: 2rpx solid #fff; */
border-radius: 50%;
text-indent: 18rpx;
line-height: 56rpx;
}
.fui-audio.style3 .img,
.fui-audio.style4 .img {
float: left;
margin-right: 20rpx;
}
.fui-audio.style3 .content {
width: 468rpx;
}
.fui-audio.style3 .content,
.fui-audio.style4 .content {
float: left;
height: 100rpx;
display: flex;
flex-direction: column;
justify-content: center;
}
.fui-audio.style3 .content .name {
height: 40rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fui-audio.style3 .content .author {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fui-audio.style3 .time {
position: absolute;
top: 40rpx;
right: 30rpx;
}
.fui-audio.style4 {
padding: 10rpx;
}
.fui-audio.style4 .content {
padding-bottom: 18rpx;
height: 82rpx;
width: 500rpx;
}
.fui-audio.style4 .start {
position: absolute;
top: 32rpx;
right: 30rpx;
width: 30rpx;
height: 30rpx;
color: #000;
}
.fui-audio.style4 .name {
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fui-audio.style4 .author {
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fui-audio.style4 .progress {
background: #f5f5f5;
height: 4rpx;
position: absolute;
bottom: 24rpx;
left: 130rpx;
right: 30rpx;
border-radius: 2rpx;
overflow: hidden;
}
.fui-audio.style4 .progressBar {
height: 4rpx;
}
.diy-audio>>>.uni-video-container {
background-color: transparent;
}
</style>

View File

@@ -1,777 +0,0 @@
<template>
<x-skeleton data-component-name="diy-bargain" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
<view class="diy-bargain" :class="[value.template, value.style]" :style="warpCss">
<!-- 商品头部 -->
<view v-if="value.titleStyle.isShow && list && list.length"
:class="[value.titleStyle.style, 'bargain-head']"
:style="{ backgroundImage: 'url(' + $util.img(value.titleStyle.backgroundImage) + '), linear-gradient(to right,' + value.titleStyle.bgColorStart + ',' + value.titleStyle.bgColorEnd + ')' }">
<view v-if="value.titleStyle.leftStyle == 'text'" class="left-text"
: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"></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 }"
@click="$util.redirectTo('/pages_promotion/bargain/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" @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)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.btnStyle.control">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="progress" v-if="value.style == 'style-2'">
<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')" />
</view>
</view>
<view class="num" v-if="item.is_bargaining">
已砍
<text>{{ (item.price - item.curr_price).toFixed(2) }}</text>
仅差
<text>{{ item.curr_price }}</text>
</view>
<view class="num" v-else>
最低可砍至
<text>{{ item.floor_price }}</text>
</view>
</view>
<view class="progress" v-if="value.style == 'style-3'">
最低可砍至
<text class="num">{{ item.floor_price }}</text>
</view>
<view class="price-wrap">
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.price.split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">.{{
item.price.split('.')[1] }}</text>
</view>
<button v-if="value.btnStyle.control" :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'
}">
{{ item.is_bargaining ? '继续砍价' : value.btnStyle.text }}
</button>
</view>
</view>
</view>
</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" @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" />
<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" />
<view class="num"
v-if="value.saleStyle.control && value.template == 'horizontal-slide' && value.style != 'style-2'"
:style="{ color: value.theme == 'diy' ? value.saleStyle.color : '' }">
已砍{{ item.sale_num }}
</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="discount-price"
v-if="value.priceStyle.mainControl && value.template == 'horizontal-slide' && value.style != 'style-2'">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.floor_price.split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
'.' + item.floor_price.split('.')[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl"
:style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">
¥{{ item.price }}
</view>
</view>
</view>
</scroll-view>
<swiper v-if="value.slideMode == 'slide'" :autoplay="false" class="swiper"
:style="{ height: swiperHeight }">
<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"
@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" />
<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" />
<view class="num"
v-if="value.saleStyle.control && value.template == 'horizontal-slide' && value.style != 'style-2'"
:style="{ color: value.theme == 'diy' ? value.saleStyle.color : '' }">
已砍{{ item.sale_num }}
</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="discount-price"
v-if="value.priceStyle.mainControl && value.template == 'horizontal-slide' && value.style != 'style-2'">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.floor_price.split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
'.' + item.floor_price.split('.')[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl"
:style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">
¥{{ item.price }}
</view>
</view>
</view>
</swiper-item>
</swiper>
</template>
</view>
</x-skeleton>
</template>
<script>
import DiyMinx from './minx.js'
// 砍价商品
export default {
name: 'diy-bargain',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
list: [],
page: 1,
loading: true,
skeletonType: '',
skeletonConfig: {}
};
},
components: {},
async created() {
this.initSkeleton();
if (this.value.template == 'row1-of1' && this.value.style == 'style-2') await this.getDataing();
this.getData();
},
watch: {
// 组件刷新监听
componentRefresh: async function (nval) {
if (this.value.template == 'row1-of1' && this.value.style == 'style-2') await this.getDataing();
this.getData();
}
},
computed: {
warpCss() {
var obj = '';
if (this.value.componentBgColor) obj += 'background:' + this.value.componentBgColor + ';';
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;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color + ';';
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color + ';';
}
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(this
.value.goodsMarginNum * 2);
else width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this.rpxUpPx(this.value
.margin.both * 2) * 2] / 6;
obj += 'margin-left:' + width + 'px;';
obj += 'margin-right:' + width + 'px;';
}
return obj;
},
swiperHeight() {
if (this.value.nameLineMode == 'multiple') {
if (this.value.ornament.type == 'shadow') return '420rpx';
else return '400rpx';
}
if (this.value.ornament.type == 'shadow') return '386rpx';
else return '378rpx';
}
},
methods: {
initSkeleton() {
if (this.value.template == 'row1-of1') {
// 单列 风格
this.skeletonType = 'list';
this.skeletonConfig = {
textRows: 2
};
} else if (this.value.template == 'horizontal-slide') {
// 横向滑动 风格
this.skeletonType = 'waterfall';
this.skeletonConfig = {
gridRows: 1,
gridColumns: 3,
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '80%']
};
}
},
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
// 查找自己参与的砍价
async getDataing() {
var res = await this.$api.sendRequest({
url: '/bargain/api/goods/bargainingList',
data: {},
async: false
});
res.data &&
res.data.forEach((item, index) => {
item.is_bargaining = 1;
});
this.list = res.data || [];
this.loading = false;
},
// 查找可砍价的商品
getData() {
var data = {
num: this.value.count,
is_exclude_bargaining: 1
};
if (this.value.sources == 'diy') {
data.num = 0;
data.id_arr = this.value.goodsId.toString();
}
this.$api.sendRequest({
url: '/bargain/api/goods/lists',
data: data,
success: res => {
if (res.code == 0) {
if (this.value.template == 'row1-of1' && this.value.style == 'style-2') this.list =
this.list.concat(res.data).splice(0, this.value.count);
else this.list = res.data;
// 切屏滚动,每页显示固定数量
if (this.value.template == 'horizontal-slide' && this.value.slideMode == 'slide') {
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
}
this.loading = false;
}
});
},
progress(data) {
// 214 表示当前进度条的宽度
let progress = (((parseFloat(data.price) - parseFloat(data.curr_price)) / parseFloat(data.price)) * 214)
.toFixed();
if (progress == 'NaN') {
progress = 0;
}
return progress;
},
toDetail(e) {
this.$util.redirectTo('/pages_promotion/bargain/detail', {
b_id: e.bargain_id
});
},
imageError(index) {
this.list[index].goods_image = this.$util.getDefaultImage().goods;
this.$forceUpdate();
}
}
};
</script>
<style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
touch-action: none;
}
.diy-bargain {
overflow: hidden;
// 头部
.bargain-head {
&.style-1 {
display: flex;
justify-content: space-between;
align-items: center;
height: 88rpx;
box-sizing: border-box;
padding: 0 20rpx;
background-repeat: no-repeat;
background-size: cover;
margin-bottom: 20rpx;
border-radius: 18rpx 18rpx 0 0;
.left-img {
height: 40rpx;
width: 156rpx;
}
.head-content {
position: relative;
color: #fff;
font-size: $font-size-tag;
margin-right: auto;
margin-left: 20rpx;
line-height: 1;
&::after {
content: '';
position: absolute;
width: 2rpx;
height: 24rpx;
background-color: #fff;
top: 50%;
transform: translateY(-50%);
left: -12rpx;
}
}
.head-right {
display: flex;
align-items: center;
font-size: $font-size-sub;
color: #fff;
}
}
&.style-2 {
display: flex;
justify-content: space-between;
align-items: center;
height: 88rpx;
box-sizing: border-box;
padding: 0 20rpx;
background-repeat: no-repeat;
background-size: cover;
margin-bottom: 20rpx;
border-radius: 18rpx 18rpx 0 0;
.left-img {
height: 40rpx;
width: 156rpx;
}
.head-right {
display: flex;
align-items: center;
justify-content: center;
height: 36rpx;
background: linear-gradient(270deg, #ffbd5b 0%, #fd882e 100%);
border-radius: 24rpx;
padding: 2rpx;
text:nth-child(1) {
position: relative;
left: 6rpx;
transform: scale(0.9);
}
text:nth-child(2) {
padding: 6rpx 4rpx 4rpx;
background-color: #fff;
color: #ffbd5b;
border-radius: 50%;
transform: scale(0.6);
font-weight: bold;
line-height: 1;
}
}
}
}
// 商品列表
&.row1-of1 {
.item {
display: flex;
margin-bottom: 20rpx;
padding: 16rpx;
&.shadow {
margin: 8rpx 8rpx 20rpx 8rpx;
}
&:last-child {
margin-bottom: 0;
padding-bottom: 20rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
>image {
width: 200rpx;
}
}
.content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 6rpx 0 6rpx 20rpx;
.goods-name {
&.multi-hidden {
line-height: 1.3;
}
}
.price-wrap {
display: flex;
justify-content: space-between;
align-items: center;
}
.discount-price {
white-space: nowrap;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: var(--price-color);
}
.price {
font-size: $font-size-toolbar;
color: var(--price-color);
}
}
button {
margin: 0;
padding: 0 20rpx;
color: var(--btn-text-color);
background-color: $base-color;
color: #fff;
min-width: 112rpx;
height: 52rpx;
line-height: 52rpx;
font-size: $font-size-tag;
font-weight: bold;
}
}
}
&.style-2 {
.discount-price {
position: relative;
}
.progress {
display: flex;
flex-direction: column;
margin-top: 10rpx;
margin-right: 16rpx;
.bg {
margin-left: 6rpx;
width: auto;
height: 20rpx;
border-radius: 20rpx;
background-color: #ffeadb;
position: relative;
&::after {
content: '';
width: 26rpx;
height: 26rpx;
border-radius: 50%;
background-color: #fa1a1a;
position: absolute;
top: 50%;
transform: translateY(-50%);
right: -18rpx;
}
.curr {
width: 0;
height: 20rpx;
border-radius: 20rpx;
background-color: #fa1a1a;
position: relative;
.progress-bar {
position: absolute;
right: -20rpx;
width: 30rpx;
height: 30rpx;
max-width: inherit !important;
max-height: inherit !important;
top: 50%;
transform: translateY(-50%);
z-index: 1;
}
}
}
.num {
font-size: $font-size-tag;
margin-top: 12rpx;
line-height: 1;
text {
color: #fa1a1a;
}
}
}
}
&.style-3 {
.progress {
display: flex;
color: $color-tip;
font-size: $font-size-sub;
.num {
color: var(--price-color);
}
}
.item {
.content {
justify-content: space-around;
}
.img-wrap {
overflow: hidden;
}
}
}
}
&.horizontal-slide {
.scroll {
width: calc(100% - 40rpx);
padding: 20rpx;
line-height: 1;
white-space: nowrap;
.item.shadow {
margin-bottom: 8rpx;
}
}
.flex-between {
justify-content: space-between;
}
.item {
display: inline-block;
width: 200rpx;
overflow: hidden;
box-sizing: border-box;
&:nth-child(3n + 3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
position: relative;
overflow: hidden;
margin: 0 auto;
>image {
width: 100%;
}
.bg {
position: absolute;
width: 100%;
height: 60rpx;
bottom: 0;
left: 0;
z-index: 2;
}
.num {
width: 180rpx;
position: absolute;
bottom: 10rpx;
padding-left: 20rpx;
font-size: 20rpx;
line-height: 1;
color: #ffffff;
z-index: 3;
}
}
.content {
padding: 10rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
&.multi-content {
height: 160rpx;
box-sizing: border-box;
}
.goods-name {
line-height: 1.3;
&.multi-hidden {
white-space: break-spaces;
}
}
.discount-price {
white-space: nowrap;
margin-top: auto;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: var(--price-color);
}
.price {
font-size: $font-size-toolbar;
color: var(--price-color);
}
}
.original-price {
margin-top: 4rpx;
font-size: $font-size-tag;
color: $color-tip;
line-height: 1;
text-decoration: line-through;
}
}
}
.swiper {
padding: 20rpx;
width: 100%;
white-space: nowrap;
box-sizing: border-box;
.swiper-item {
display: flex;
align-items: center;
}
.item {
width: 200rpx;
box-sizing: border-box;
}
}
}
}
</style>

View File

@@ -1,318 +0,0 @@
<template>
<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" @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"
:animation="cartAnimation" id="tabbarCart">
<block v-if="verify(item.link)">
<image v-if="item.selected_icon_type == 'img'"
:src="$util.img(item.selectedIconPath)" />
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath"
:value="item.selected_style ? item.selected_style : null"></diy-icon>
</block>
<block v-else>
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath"
:value="item.style ? item.style : null"></diy-icon>
</block>
<view class="cart-count-mark font-size-activity-tag"
:class="{ max: item.link.wap_url == '/pages_goods/cart' && cartNumber > 99 }"
:style="{ background: 'var(--price-color)' }" v-if="cartNumber > 0">
{{ cartNumber > 99 ? '99+' : cartNumber }}
</view>
</view>
</block>
<block v-else>
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2">
<block v-if="verify(item.link)">
<image v-if="item.selected_icon_type == 'img'"
:src="$util.img(item.selectedIconPath)" />
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath"
:value="item.selected_style ? item.selected_style : null"></diy-icon>
</block>
<block v-else>
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath"
:value="item.style ? item.style : null"></diy-icon>
</block>
</view>
</block>
<view class="label"
v-if="(tabBarList.type == 1 || tabBarList.type == 3) && tabBarList.theme == 'diy'"
:style="{ color: verify(item.link) ? tabBarList.textHoverColor : tabBarList.textColor }">
{{ lang == 'en-us' ? item.en_text : item.text }}
</view>
<view class="label"
v-if="(tabBarList.type == 1 || tabBarList.type == 3) && tabBarList.theme == 'default'"
:style="{ color: verify(item.link) ? 'var(--base-color)' : '#333333' }">
{{ lang == 'en-us' ? item.en_text : item.text }}
</view>
</view>
</view>
</view>
<!-- 解决fixed定位后底部导航栏塌陷问题 -->
<view class="tab-bar-placeholder"></view>
</view>
</template>
<script>
import { adaptSubpackageUrl, checkTabBarActive } from '@/common/js/util.js'
import DiyMinx from './minx.js'
// 底部导航栏
export default {
name: 'diy-bottom-nav',
props: {
value: {
type: Object
},
name: {
type: String,
default: ''
}
},
mixins: [DiyMinx],
data() {
return {
lang: uni.getStorageSync("lang"),
currentRoute: '', //当前页面路径
jumpFlag: true, //是否可以跳转,防止重复点击
cartAnimation: {}
};
},
mounted() {
this.updateCurrentRoute();
this.$nextTick(() => {
if (!this.$store.state.cartPosition) {
let query = uni.createSelectorQuery().in(this);
query.select('#tabbarCart')
.boundingClientRect(data => {
if (data) this.$store.commit('setCartPosition', data);
}).exec();
query.select('.tab-bar')
.boundingClientRect(data => {
if (data) this.$store.commit('setTabBarHeight', data.height +
'px');
}).exec();
}
});
// 监听页面显示事件,更新当前路由
this.$on('hook:onShow', () => {
this.updateCurrentRoute();
});
},
computed: {
cartChange() {
return this.$store.state.cartChange;
}
},
watch: {
cartChange: function (nval, oval) {
if (nval > oval) {
let animation = uni.createAnimation({
duration: 200,
timingFunction: 'ease'
});
animation.scale(1.2).step();
this.cartAnimation = animation.export();
setTimeout(() => {
animation.scale(1).step();
this.cartAnimation = animation.export();
}, 300);
}
}
},
methods: {
// 更新当前路由
updateCurrentRoute() {
let currentPage = getCurrentPages()[getCurrentPages().length - 1];
if (currentPage && currentPage.route) {
this.currentRoute = currentPage.route;
}
},
redirectTo(link) {
this.$emit('callback');
this.$util.diyRedirectTo(link);
},
verify(link) {
if (link == null || link == '' || !link.wap_url) return false;
// 标准化路径格式,确保比较的一致性
let currentPageRoute = this.currentRoute ? '/' + this.currentRoute : '';
let linkUrl = link.wap_url;
// 首页特殊处理
if (linkUrl === this.$util.INDEX_PAGE_URL && this.name === 'DIY_VIEW_INDEX') {
return true;
}
// 精确匹配当前路径
if (adaptSubpackageUrl(linkUrl) === currentPageRoute) {
return true;
}
return checkTabBarActive(linkUrl, currentPageRoute);
}
}
};
</script>
<style lang="scss">
.placeholder {
height: 112rpx;
&.bluge {
height: 180rpx;
}
}
.safe-area {
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.tab-bar {
background-color: #fff;
box-sizing: border-box;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
z-index: 998;
display: flex;
border-top: 2rpx solid #f5f5f5;
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.tabbar-border {
background-color: rgba(255, 255, 255, 0.329412);
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 2rpx;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
.item {
display: flex;
align-items: center;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex: 1;
flex-direction: column;
padding-bottom: 10rpx;
box-sizing: border-box;
.bd {
position: relative;
height: 100rpx;
flex-direction: column;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
.icon {
position: relative;
display: inline-block;
margin-top: 10rpx;
width: 40rpx;
height: 40rpx;
font-size: 40rpx;
line-height: 40rpx;
image {
width: 100%;
height: 100%;
}
>view {
height: inherit;
display: flex;
align-items: center;
}
.bar-icon {
font-size: 42rpx;
}
}
.label {
position: relative;
text-align: center;
font-size: 24rpx;
line-height: 1;
margin-top: 12rpx;
}
}
&.bulge {
.bd {
position: relative;
height: 100rpx;
flex-direction: column;
text-align: center;
.icon {
margin-top: -60rpx;
margin-bottom: 4rpx;
border-radius: 50%;
width: 100rpx;
height: 102rpx;
padding: 10rpx;
border-top: 2rpx solid #f5f5f5;
background-color: #fff;
box-sizing: border-box;
image {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.label {
position: relative;
text-align: center;
font-size: 24rpx;
height: 40rpx;
line-height: 40rpx;
}
}
}
.cart-count-mark {
position: absolute;
top: -8rpx;
right: -18rpx;
width: 24rpx;
height: 24rpx !important;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
padding: 6rpx;
border-radius: 50%;
z-index: 99;
&.max {
width: 40rpx;
border-radius: 24rpx;
right: -28rpx;
}
}
}
}
.tab-bar-placeholder {
padding-bottom: calc(constant(safe-area-inset-bottom) + 112rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 112rpx);
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,261 +0,0 @@
<template>
<view :style="componentStyle" data-component-name="diy-digit">
<scroll-view :class="['graphic-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle]"
:scroll-x="value.showStyle == 'singleSlide'">
<view class="uni-scroll-view-content">
<view v-for="(item, index) in value.list" :key="index"
:class="['graphic-nav-item', value.mode, value.mode === 'text' ? 'newright' : '']"
:style="{ width: (100 / value.rowCount + '%') + ';' }">
<view style="display:flex;">
<view :style="{
'line-height': '1.2;',
'font-size': (value.font.titlesize * 2 + 'rpx') + ';',
'font-weight': '600;',
'color': value.font.titlecolor + ';'
}">
<uv-count-to :ref="`countTo-${index}`" :autoplay="true" :startVal="30" :endVal="item.title"
:decimals="getvalue(item.title)" decimal="."></uv-count-to>
<text :style="{
'margin-left': '4rpx;',
'font-size': (value.font.unitsize * 2 + 'rpx') + ';',
'font-weight': value.font.weight + ';',
'color': value.font.unitcolor + ';'
}">{{ item.unit }}</text>
</view>
</view>
<view class="graphic-text">
<text :style="{
'font-size': (value.font.descsize * 2 + 'rpx') + ';',
'font-weight': value.font.weight + ';',
'color': value.font.desccolor + ';'
}">{{ item.desc }}</text>
</view>
</view>
</view>
</scroll-view>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
import DiyMinx from './minx.js'
// 自定义数字展示
export default {
name: 'diy-digit',
props: {
value: {
type: Object,
default: () => ({})
}
},
mixins: [DiyMinx],
data() {
return {
pageWidth: '',
indicatorDots: false,
swiperCurrent: 0
}
},
created() {
// 组件创建时的逻辑
},
watch: {
componentRefresh(newValue) {
// 监听组件刷新
}
},
computed: {
componentStyle() {
let style = '';
style += 'background-image:url(' + this.$util.img(this.value.imageUrl) + ');background-size:100% 100%;';
if (this.value.componentAngle == 'round') {
style += 'border-top-left-radius:' + (2 * this.value.topAroundRadius) + 'rpx;';
style += 'border-top-right-radius:' + (2 * this.value.topAroundRadius) + 'rpx;';
style += 'border-bottom-left-radius:' + (2 * this.value.bottomAroundRadius) + 'rpx;';
style += 'border-bottom-right-radius:' + (2 * this.value.bottomAroundRadius) + 'rpx;';
}
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 : '') + ';';
return style;
}
},
methods: {
// 获取小数位数
getvalue(value) {
return value % 1 !== 0 ? 2 : 0;
},
// 页面跳转
redirectTo(item) {
if (!item.wap_url || this.$util.getCurrRoute() != this.$util.MEMBER_PAGE_URL || this.storeToken) {
console.log(item);
this.$util.diyRedirectTo(item);
} else {
this.$refs.login.open(item.wap_url);
}
},
// 轮播切换
swiperChange(event) {
this.swiperCurrent = event.detail.current;
}
}
}
</script>
<style lang="scss" scoped>
.graphic-nav {
padding: 16rpx;
box-sizing: border-box;
&.fixed-layout {
.uni-scroll-view-content {
display: flex;
flex-wrap: wrap;
}
}
&.singleSlide {
.uni-scroll-view-content {
display: flex;
}
.graphic-nav-item {
flex-shrink: 0;
}
}
&.pageSlide {
position: relative;
.uni-swiper-dots-horizontal {
bottom: 0rpx;
}
&.straightLine {
.uni-swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
}
&.circle {
.uni-swiper-dot {
width: 14rpx;
height: 14rpx;
}
}
}
.graphic-nav-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
.graphic-nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 14rpx 0;
box-sizing: border-box;
.graphic-text {
line-height: 1.3;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
&.alone {
padding-top: 0;
}
}
&.text {
.graphic-text {
padding-top: 0;
}
}
.graphic-img {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
font-size: 90rpx;
.tag {
position: absolute;
top: -10rpx;
right: -24rpx;
color: #fff;
border-radius: 24rpx;
border-bottom-left-radius: 0;
-webkit-transform: scale(0.8);
transform: scale(0.8);
padding: 8rpx 16rpx;
line-height: 1;
font-size: 24rpx;
}
.icon {
font-size: 50rpx;
color: #606266;
}
}
}
&.pageSlide {
.graphic-nav-item {
flex-shrink: 0;
}
}
}
.newright {
margin-right: 16rpx;
}
.swiper-dot-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: -20rpx;
padding-bottom: 8rpx;
.swiper-dot {
background-color: rgba(0, 0, 0, 0.3);
margin: 8rpx;
&.active {
background-color: #000;
}
}
&.straightLine {
.swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
}
&.circle {
.swiper-dot {
width: 15rpx;
border-radius: 50%;
height: 15rpx;
}
}
}
</style>

View File

@@ -1,123 +0,0 @@
<template>
<view data-component-name="diy-float-btn" class="float-btn"
: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" @click="$util.diyRedirectTo(item.link)"
:style="{ width: value.imageSize + 'px', height: value.imageSize + 'px', fontSize: value.imageSize + 'px' }">
<image v-if="!item.iconType || item.iconType == 'img'" :src="$util.img(item.imageUrl)" mode="aspectFit"
:show-menu-by-longpress="true" />
<diy-icon v-else-if="item.iconType && item.iconType == 'icon'" :icon="item.icon"
:value="item.style ? item.style : null"></diy-icon>
</view>
</block>
</view>
</template>
<script>
// 自定义浮动按钮
import DiyMinx from './minx.js'
// 获取系统状态栏的高度
let systemInfo = uni.getSystemInfoSync();
// 自定义浮动按钮
export default {
name: 'diy-float-btn',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
mixins: [DiyMinx],
data() {
return {
navHeight: 0,
statusBarHeight: systemInfo.statusBarHeight
};
},
created() { },
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
components: {},
methods: {},
computed: {
style() {
let style = {},
height = 54;
// #ifdef MP
height = systemInfo.platform == 'ios' ? 54 : 58;
// #endif
switch (parseInt(this.value.bottomPosition)) {
case 1:
style.top = (this.navHeight + this.statusBarHeight + parseInt(this.value.btnBottom)) * 2 + 'rpx';
break;
case 2:
style.top = (this.navHeight + this.statusBarHeight + parseInt(this.value.btnBottom)) * 2 + 'rpx';
break;
case 3:
style.bottom = (100 + parseInt(this.value.btnBottom)) * 2 + 'rpx';
break;
case 4:
style.bottom = (100 + parseInt(this.value.btnBottom)) * 2 + 'rpx';
break;
}
return this.$util.objToStyle(style);
}
}
};
</script>
<style lang="scss">
.float-btn {
position: fixed;
bottom: 20%;
right: 40rpx;
z-index: 990;
&.left_top {
top: 100rpx;
left: 30rpx;
}
&.right_top {
top: 100rpx;
right: 30rpx;
}
&.left_bottom {
bottom: 160rpx;
left: 30rpx;
padding-bottom: constant(safe-area-inset-bottom);
/*兼容 IOS<11.2*/
padding-bottom: env(safe-area-inset-bottom);
/*兼容 IOS>11.2*/
}
&.right_bottom {
bottom: 160rpx;
right: 30rpx;
padding-bottom: constant(safe-area-inset-bottom);
/*兼容 IOS<11.2*/
padding-bottom: env(safe-area-inset-bottom);
/*兼容 IOS>11.2*/
}
.button-box {
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
image {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@@ -1,31 +0,0 @@
<template>
<!-- #ifdef MP -->
<view data-component-name="diy-follow-official-account" v-if="value.isShow">
<official-account></official-account>
</view>
<!--#endif -->
</template>
<script>
// 关注公众号展示
import DiyMinx from './minx.js'
export default {
name: 'diy-follow-official-account',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {};
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
methods: {}
};
</script>
<style></style>

View File

@@ -1,114 +0,0 @@
<template>
<view data-component-name="diy-form" class="diy-from" :style="style">
<view class="fui-cell-group">
<view class="fui-cell ">
<view class="fui-cell-label ">您的姓名</view>
<view class="fui-cell-info">
<input v-model="Form.realname" class="fui-input" placeholder="请输入您的姓名" value=""></input>
</view>
</view>
<view class="fui-cell ">
<view class="fui-cell-label">手机号码</view>
<view class="fui-cell-info">
<input v-model="Form.mobile" class="fui-input" maxlength="11" placeholder="请输入您的手机号"
type="number"></input>
</view>
</view>
<view class="fui-cell ">
<view class="fui-cell-label">您的邮箱</view>
<view class="fui-cell-info">
<input v-model="Form.mailbox" class="fui-input" placeholder="请输入您的邮箱" type="text"></input>
</view>
</view>
<view class="fui-cell">
<view class="fui-cell-label">所在城市</view>
<view class="fui-cell-info">
<input v-model="Form.citys" class="fui-input" placeholder="请输入您的所在地" value=""></input>
</view>
</view>
<view class="fui-cell">
<view class="fui-cell-label">备注</view>
<view class="fui-cell-info">
<input v-model="Form.remark" class="fui-input" placeholder="请输入备注" value=""></input>
</view>
</view>
</view>
<view @click="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
</view>
</template>
<script>
// 自定义表单
import DiyMinx from './minx.js'
export default {
name: 'diy-from',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
loading: true,
markers: [],
Form: {
realname: '',
mobile: '',
mailbox: '',
citys: '',
remark: '',
}
};
},
created() {
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
// this.getDataList();
}
},
computed: {
markerst() {
return [{
id: 1,
latitude: this.value.list[0].lat,
longitude: this.value.list[0].lng
}]
},
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return css;
}
},
methods: {
submitform() {
this.$api.sendRequest({
url: '/api/member/information',
data: this.Form,
success: res => {
this.$util.showToast({
title: res.message
});
}
});
}
}
};
</script>
<style lang="scss">
.diy-from {
background: #fff;
padding-bottom: 20rpx;
border-radius: 10rpx;
}
</style>

View File

@@ -1,166 +0,0 @@
<template>
<x-skeleton data-component-name="diy-goods-brand" type="waterfall" :loading="loading" :configs="skeletonConfig">
<view :class="['brand-wrap', value.ornament.type]" :style="warpCss">
<view :class="[value.style]">
<view class="title-wrap" v-show="value.title"
:style="{ color: value.textColor, fontWeight: value.fontWeight ? 'bold' : '' }">{{ value.title }}
</view>
<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"
@click="handlerClick(item)" @tap="handlerClick(item)" @error="imgError(index)"
:style="itemCss" />
</view>
</view>
</view>
</view>
</x-skeleton>
</template>
<script>
// 商品品牌
import DiyMinx from './minx.js'
// 自定义商品品牌展示
export default {
name: 'diy-goods-brand',
props: {
value: {
type: Object
}
},
data() {
return {
list: [],
loading: true,
skeletonConfig: {
gridRows: 2,
gridColumns: 4,
gridRowsGap: '20rpx',
headWidth: '120rpx',
headHeight: '120rpx',
textShow: false
}
};
},
created() {
this.getBrandList();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getBrandList();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color;
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color;
}
return obj;
},
// 子项样式
itemCss() {
var obj = '';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return obj;
}
},
methods: {
getBrandList() {
var data = {
page: 1,
page_size: this.value.count
};
if (this.value.sources == 'diy') {
data.page_size = 0;
data.brand_id_arr = this.value.brandIds.toString();
}
this.$api.sendRequest({
url: '/api/goodsbrand/page',
data: data,
success: res => {
if (res.code == 0 && res.data) {
let data = res.data;
this.list = data.list;
}
this.loading = false;
}
});
},
toDetail(item) {
this.$util.redirectTo('/pages_goods/list', {
brand_id: item.brand_id
});
},
imgError(index) {
if (this.list[index]) this.list[index].image_url = this.$util.getDefaultImage().goods;
},
async handlerClick(item) {
await this.__$emitEvent({
eventName: 'goods-brand-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.toDetail(item);
}
})
},
}
};
</script>
<style lang="scss">
.brand-wrap {
&.shadow {
margin-left: 8rpx;
margin-right: 8rpx;
margin-top: 8rpx;
margin-bottom: 8rpx;
}
.style-1 {
.title-wrap {
text-align: center;
padding: 20rpx 0 10rpx;
}
.ul-wrap {
display: flex;
flex-wrap: wrap;
padding: 20rpx;
.li-item {
display: flex;
align-items: center;
justify-content: center;
width: calc(100% / 4 - 20rpx) !important;
height: 124rpx;
margin: 10rpx;
background-color: #fff;
.brand-pic {
width: 100%;
height: 100%;
}
}
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,626 +0,0 @@
<template>
<x-skeleton data-component-name="diy-goods-recommend" type="waterfall" :loading="loading" :configs="skeletonConfig">
<view v-if="list.length" :class="['goods-list', goodsValue.style]" :style="goodsListWarpCss">
<view class="top-wrap" v-if="goodsValue.topStyle.support">
<text :class="['js-icon', goodsValue.topStyle.icon.value]"
:style="{ backgroundColor: goodsValue.topStyle.icon.bgColor, color: goodsValue.topStyle.icon.color }"></text>
<text class="title" :style="{ color: goodsValue.topStyle.color }">{{ goodsValue.topStyle.title }}</text>
<text class="line" :style="{ color: goodsValue.topStyle.subColor }"></text>
<text class="sub" :style="{ color: goodsValue.topStyle.subColor }">{{ goodsValue.topStyle.subTitle
}}</text>
</view>
<swiper :autoplay="false" class="swiper" :style="{ height: swiperHeight }">
<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"
@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" />
<view class="sell-out" v-if="dataItem.stock <= 0">
<text class="iconfont icon-shuqing"></text>
</view>
</div>
<view :class="['info-wrap', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="goodsValue.goodsNameStyle.control || goodsValue.priceStyle.mainControl || goodsValue.priceStyle.lineControl || goodsValue.labelStyle.support">
<view v-if="goodsValue.goodsNameStyle.control" class="goods-name"
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.goodsNameStyle.color : '', fontWeight: goodsValue.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': goodsValue.nameLineMode == 'single' }, { 'multi-hidden': goodsValue.nameLineMode == 'multiple' }]">
{{ isEnEnv ? dataItem.en_goods_name : dataItem.goods_name }}
</view>
<view class="pro-info">
<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" />
<text>{{ goodsValue.labelStyle.title }}</text>
</view>
<view class="discount-price">
<view class="price-wrap" v-if="goodsValue.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.priceStyle.mainColor + '!important' : '' }"></text>
<text class="price price-style large"
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.priceStyle.mainColor + '!important' : '' }">{{
showPrice(dataItem).split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.priceStyle.mainColor + '!important' : '' }">{{
'.' + showPrice(dataItem).split('.')[1] }}</text>
</view>
<view v-if="goodsValue.priceStyle.lineControl && showMarketPrice(dataItem)"
class="delete-price price-font"
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.priceStyle.lineColor : '' }">
{{ showMarketPrice(dataItem) }}</view>
<view class="sale" v-if="goodsValue.saleStyle.control"
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.saleStyle.color : '' }">
{{ dataItem.sale_num }}{{ dataItem.unit ? dataItem.unit : '件' }}
</view>
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</x-skeleton>
</template>
<script>
// 自定义商品推荐展示
import DiyMinx from './minx.js'
export default {
name: 'diy-goods-recommend',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
mixins: [DiyMinx],
data() {
return {
loading: true,
skeletonConfig: {
gridRows: 1,
gridColumns: 3,
headWidth: '200rpx',
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '60%'],
},
list: [],
goodsValue: {},
page: 1
};
},
created() {
this.goodsValue = this.value;
this.getGoodsList();
},
watch: {
'globalStoreInfo.store_id': {
handler(nval, oval) {
if (nval != oval) {
this.getGoodsList();
}
},
deep: true
},
// 组件刷新监听
componentRefresh: function (nval) {
this.getGoodsList();
}
},
computed: {
goodsListWarpCss() {
var obj = '';
obj += 'background-color:' + this.goodsValue.componentBgColor + ';';
if (this.goodsValue.componentAngle == 'round') {
obj += 'border-top-left-radius:' + this.goodsValue.topAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.goodsValue.topAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.goodsValue.bottomAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.goodsValue.bottomAroundRadius * 2 + 'rpx;';
}
if (this.goodsValue.bgUrl) {
obj += `background-image: url('${this.$util.img(this.goodsValue.bgUrl)}');`;
}
return obj;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.goodsValue.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.goodsValue.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.goodsValue.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.goodsValue.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.goodsValue.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.goodsValue.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.goodsValue.ornament.color + ';';
}
if (this.goodsValue.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.goodsValue.ornament.color + ';';
}
const screenWidth = uni.getSystemInfoSync().windowWidth;
var width = '';
if (this.goodsValue.style != 'style-2') {
width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this.rpxUpPx(this.value.margin
.both * 2) * 2] / 6;
} else {
width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this
.rpxUpPx(this.value.margin.both * 2) * 2
] / 6;
}
obj += 'margin-left:' + width + 'px;';
obj += 'margin-right:' + width + 'px;';
return obj;
},
swiperHeight() {
if (this.goodsValue.style == 'style-3') {
return '330rpx';
} else if (this.goodsValue.style != 'style-2') {
if (this.value.nameLineMode == 'multiple') {
return '348rpx';
}
return '312rpx';
} else {
if (this.value.nameLineMode == 'multiple') {
return '360rpx';
}
return '320rpx';
}
}
},
methods: {
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
getGoodsList() {
var data = {
num: this.goodsValue.count
};
if (this.goodsValue.sources == 'category') {
data.category_id = this.goodsValue.categoryId;
data.category_level = 1;
} else if (this.goodsValue.sources == 'diy') {
data.num = 0;
data.goods_id_arr = this.goodsValue.goodsId.toString();
}
data.order = this.goodsValue.sortWay;
this.$api.sendRequest({
url: '/api/goodssku/components',
data: data,
success: res => {
if (res.code == 0 && res.data) {
let data = res.data;
this.list = data;
// 切屏滚动,每页显示固定数量
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
this.loading = false;
}
});
},
toDetail(item) {
this.$util.redirectTo('/pages_goods/detail', {
goods_id: item.goods_id
});
},
imgError(pageIndex, index) {
this.list[pageIndex][index].goods_image = this.$util.getDefaultImage().goods;
},
showPrice(data) {
let price = data.discount_price;
if (data.member_price && parseFloat(data.member_price) < parseFloat(price)) price = data.member_price;
return price;
},
showMarketPrice(item) {
let price = this.showPrice(item);
if (item.market_price > 0) {
return item.market_price;
} else if (item.price > price) {
return item.price;
}
return '';
},
}
};
</script>
<style lang="scss" scoped>
.goods-list {
.goods-item {
line-height: 1;
.sale {
line-height: 1;
color: $color-tip;
font-size: $font-size-activity-tag;
}
.info-wrap {
.goods-name {
margin-bottom: 10rpx;
line-height: 1.3;
}
}
.sell-out {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
text {
color: #fff;
font-size: 180rpx;
}
}
}
}
// 商品列表横向滚动样式
.goods-list.style-1 {
width: 100%;
white-space: nowrap;
background-repeat: round;
.top-wrap {
display: flex;
align-items: center;
padding: 20rpx 0;
.js-icon {
border-radius: 50%;
font-size: 40rpx;
margin-right: 10rpx;
width: 70rpx;
height: 70rpx;
text-align: center;
line-height: 70rpx;
}
.line {
height: 28rpx;
margin: 0 10rpx;
border: 2rpx solid;
}
.title {
font-weight: bold;
font-size: $font-size-toolbar;
}
.sub {
font-size: $font-size-tag;
}
}
.flex-between {
justify-content: space-between;
}
.swiper {
display: flex;
flex-wrap: wrap;
margin: 0 20rpx;
.swiper-item {
display: flex;
align-items: center;
}
}
.goods-item {
overflow: hidden;
width: 200rpx;
display: inline-block;
box-sizing: border-box;
&:nth-child(3n + 3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.goods-img,
.goods-img-wrap {
position: relative;
width: 100%;
height: 196rpx;
}
.info-wrap {
display: flex;
flex-direction: column;
padding: 10rpx;
&.multi-content {
height: 130rpx;
box-sizing: border-box;
}
.goods-name {
font-size: $font-size-sub;
&.multi-hidden {
white-space: break-spaces;
}
}
.pro-info {
margin-top: auto;
display: flex;
flex-direction: column;
justify-content: space-between;
.discount-price {
display: flex;
justify-content: space-between;
align-items: center;
.price-wrap {
line-height: 1;
white-space: nowrap;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
}
text {
font-weight: bold;
color: $base-color;
}
}
}
.delete-price {
margin-left: 10rpx;
text-decoration: line-through;
flex: 1;
line-height: 28rpx;
color: $color-tip;
font-size: $font-size-activity-tag;
}
}
}
}
}
// 商品列表横向滚动样式
.goods-list.style-2 {
width: 100%;
white-space: nowrap;
background-repeat: round;
padding-bottom: 20rpx;
.top-wrap {
display: flex;
align-items: center;
padding: 20rpx;
.js-icon {
border-radius: 50%;
font-size: 40rpx;
margin-right: 20rpx;
width: 70rpx;
height: 70rpx;
text-align: center;
line-height: 70rpx;
}
.line {
height: 28rpx;
margin: 0 10rpx;
border: 2rpx solid;
}
.title {
font-weight: bold;
font-size: $font-size-toolbar;
}
.sub {
font-size: $font-size-tag;
}
}
.swiper {
display: flex;
flex-wrap: wrap;
margin: 0 20rpx;
padding: 20rpx;
border-radius: 20rpx;
background-color: #fff;
}
.goods-item {
overflow: hidden;
width: 200rpx;
display: inline-block;
box-sizing: border-box;
&.shadow {
margin-top: 8rpx;
width: 200rpx;
}
.goods-img,
.goods-img-wrap {
position: relative;
width: 100%;
height: 200rpx;
}
.info-wrap {
padding: 10rpx;
.goods-name {
line-height: 1;
&.multi-hidden {
line-height: 1.3;
height: 68rpx;
white-space: break-spaces;
}
}
.pro-info {
display: flex;
flex-direction: column;
justify-content: space-between;
.discount-price {
display: flex;
justify-content: space-between;
align-items: center;
.price-wrap {
line-height: 1.3;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
text {
font-weight: bold;
color: $base-color;
&:last-of-type {
font-size: 32rpx;
}
}
}
}
.delete-price {
margin-left: 10rpx;
text-decoration: line-through;
flex: 1;
line-height: 28rpx;
color: $color-tip;
font-size: $font-size-activity-tag;
}
}
}
}
}
.goods-list.style-3 {
background-position: bottom;
.swiper {
display: flex;
flex-wrap: wrap;
margin: 0 20rpx;
padding: 10rpx 0;
.swiper-item {
display: flex;
align-items: center;
}
}
.goods-item {
overflow: hidden;
width: 200rpx;
display: inline-block;
box-sizing: border-box;
&.shadow {
// margin-top: 20rpx;
}
.goods-img,
.goods-img-wrap {
position: relative;
width: 100%;
height: 200rpx;
}
.info-wrap {
display: flex;
flex-direction: column;
padding: 10rpx;
.pro-info {
text-align: center;
.label-wrap {
border-radius: 40rpx;
display: inline-block;
margin: 10rpx 0;
position: relative;
padding-left: 52rpx;
padding-right: 16rpx;
line-height: 1.7;
image {
position: absolute;
top: -2rpx;
left: -2rpx;
width: 46rpx;
height: 46rpx;
}
text {
font-size: $font-size-tag;
}
}
.discount-price {
.price-wrap {
line-height: 1;
white-space: nowrap;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
}
text {
font-weight: bold;
color: $base-color;
}
}
}
}
}
}
}
</style>

View File

@@ -1,318 +0,0 @@
<template>
<view data-component-name="diy-graphic-nav" :style="componentStyle">
<block v-if="value.showStyle == 'pageSlide'">
<swiper :class="['graphic-nav', 'pageSlide', value.carousel.type]" circular :indicator-dots="false"
:style="swiperHeight" @change="swiperChange">
<swiper-item class="graphic-nav-wrap"
v-for="(numItem, numIndex) in Math.ceil(value.list.length / (value.pageCount * value.rowCount))">
<!-- #ifdef MP -->
<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 + '%' }" @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 + '%' }" @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' }">
<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="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>
<text class="tag" v-if="item.label.control"
:style="{ color: item.label.textColor, backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')' }">
{{ item.label.text }}
</text>
</view>
<text v-if="value.mode != 'img'" class="graphic-text"
:style="{ fontSize: value.font.size * 2 + 'rpx', fontWeight: value.font.weight, color: value.font.color }">
{{ item.title }}
</text>
<!-- #ifdef H5 -->
</view>
<!-- #endif -->
<!-- #ifdef MP -->
</view>
<!-- #endif -->
</swiper-item>
</swiper>
<view class="swiper-dot-box" v-if="isIndicatorDots" :class="value.carousel.type">
<view v-for="(numItem, numIndex) in Math.ceil(value.list.length / (value.pageCount * value.rowCount))"
:key="numIndex">
<view class="swiper-dot" :class="{ 'active': numIndex == swiperCurrent }"></view>
</view>
</view>
</block>
<scroll-view v-else :scroll-x="value.showStyle == 'singleSlide'"
:class="['graphic-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle]">
<!-- #ifdef MP -->
<view class="uni-scroll-view-content">
<!-- #endif -->
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list" :key="index"
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
<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="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>
<text :class="['tag', { alone: value.mode == 'text' }]" v-if="item.label.control"
:style="{ color: item.label.textColor, backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')' }">
{{ item.label.text }}
</text>
</view>
<text v-if="value.mode != 'img'" class="graphic-text"
:style="{ fontSize: value.font.size * 2 + 'rpx', fontWeight: value.font.weight, color: value.font.color }">
{{ item.title }}
</text>
</view>
<!-- #ifdef MP -->
</view>
<!-- #endif -->
</scroll-view>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
// 自定义图形导航
import DiyMinx from './minx.js'
export default {
name: 'diy-graphic-nav',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
pageWidth: '',
indicatorDots: false,
swiperCurrent: 0
};
},
created() { },
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
componentStyle() {
var css = '';
css += 'background-color:' + this.value.componentBgColor + ';';
if (this.value.componentAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
}
css += 'box-shadow:' + (this.value.ornament.type == 'shadow' ? '0 0 10rpx ' + this.value.ornament
.color :
'') + ';';
css += 'border:' + (this.value.ornament.type == 'stroke' ? '2rpx solid ' + this.value.ornament.color :
'') + ';';
return css;
},
// 滑块容器的高度
swiperHeight() {
var css = '';
var height = 0;
if (this.value.mode == 'graphic') {
height = (21 + 6 + 14 + 8 + this.value.imageSize) * this.value
.pageCount; // 21 = 文字高度8 = 文字上边距14 = 上下内边距8 = 外边距
} else if (this.value.mode == 'img') {
height = (14 + 8 + this.value.imageSize) * this.value.pageCount; // 14 = 上下内边距8 = 外边距
} else if (this.value.mode == 'text') {
height = (21 + 14 + 8) * this.value.pageCount; // 21 = 文字高度14 = 上下内边距8 = 外边距
}
css += 'height:' + height * 2 + 'rpx';
return css;
},
// 是否显示轮播点
isIndicatorDots() {
var bool = true;
bool = this.value.carousel.type == 'hide' || Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount)) == 1 ? false : true;
return bool;
}
},
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);
return;
}
}
console.log(link)
this.$util.diyRedirectTo(link);
},
swiperChange(e) {
this.swiperCurrent = e.detail.current
}
}
};
</script>
<style>
/* 固定显示 */
.graphic-nav.fixed-layout>>>.uni-scroll-view-content {
display: flex;
flex-wrap: wrap;
}
/* 单行滑动 */
.graphic-nav.singleSlide>>>.uni-scroll-view-content {
display: flex;
}
.graphic-nav.pageSlide>>>.uni-swiper-dots-horizontal {
bottom: 0rpx;
}
.graphic-nav.pageSlide.straightLine>>>.uni-swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
.graphic-nav.pageSlide.circle>>>.uni-swiper-dot {
width: 14rpx;
height: 14rpx;
}
</style>
<style lang="scss">
.graphic-nav {
padding: 16rpx;
box-sizing: border-box;
&.singleSlide {
.graphic-nav-item {
flex-shrink: 0;
}
}
&.pageSlide {
position: relative;
.graphic-nav-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
}
.graphic-nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 14rpx 0;
box-sizing: border-box;
.graphic-text {
padding-top: 12rpx;
line-height: 1.5;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
&.alone {
padding-top: 0;
}
}
&.text {
.graphic-text {
padding-top: 0;
}
}
.graphic-img {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
font-size: 90rpx;
.tag {
position: absolute;
top: -10rpx;
right: -24rpx;
color: #fff;
border-radius: 24rpx;
border-bottom-left-radius: 0;
transform: scale(0.8);
padding: 8rpx 16rpx;
line-height: 1;
font-size: 24rpx;
}
.icon {
font-size: 50rpx;
color: $color-sub;
}
}
}
}
.swiper-dot-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: -20rpx;
padding-bottom: 8rpx;
.swiper-dot {
background-color: rgba(0, 0, 0, .3);
margin: 8rpx;
&.active {
background-color: rgba(0, 0, 0, 1);
}
}
&.straightLine {
.swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
}
&.circle {
.swiper-dot {
width: 15rpx;
border-radius: 50%;
height: 15rpx;
}
}
}
</style>

View File

@@ -1,500 +0,0 @@
<template>
<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" @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)">
</image>
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl || value.btnStyle.control">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.groupbuy_price.split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
'.' + item.groupbuy_price.split('.')[1] }}</text>
</view>
<button v-if="value.btnStyle.control" :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'
}">
{{ value.btnStyle.text }}
</button>
</view>
</view>
</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" @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)" />
<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"
:style="{ color: value.theme == 'diy' ? value.saleStyle.color : '' }">
已团{{ item.sell_num }}
</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.groupbuy_price.split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
'.' + item.groupbuy_price.split('.')[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl"
:style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">¥{{
item.price }}</view>
</view>
</view>
</scroll-view>
<swiper v-if="value.slideMode == 'slide'" :autoplay="false" class="swiper"
:style="{ height: swiperHeight }">
<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"
@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)" />
<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"
:style="{ color: value.theme == 'diy' ? value.saleStyle.color : '' }">已团{{
item.sell_num }}</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.groupbuy_price.split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
'.' + item.groupbuy_price.split('.')[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl"
:style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">¥{{
item.price }}</view>
</view>
</view>
</swiper-item>
</swiper>
</template>
</view>
</x-skeleton>
</template>
<script>
// 自定义团购展示
import DiyMinx from './minx.js'
export default {
name: 'diy-groupbuy',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
loading: true,
skeletonType: '',
skeletonConfig: {},
list: [],
page: 1
};
},
created() {
this.initSkeleton();
this.getData();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getData();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color + ';';
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color + ';';
}
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(this
.value.goodsMarginNum * 2);
else width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this.rpxUpPx(this.value
.margin.both * 2) * 2] / 6;
obj += 'margin-left:' + width + 'px;';
obj += 'margin-right:' + width + 'px;';
}
return obj;
},
swiperHeight() {
if (this.value.nameLineMode == 'multiple') return this.value.ornament.type == 'shadow' ? '404rpx' :
'392rpx';
return this.value.ornament.type == 'shadow' ? '376rpx' : '368rpx';
}
},
methods: {
initSkeleton() {
if (this.value.template == 'row1-of1') {
// 单列 风格
this.skeletonType = 'list';
this.skeletonConfig = {
textRows: 2
};
} else if (this.value.template == 'horizontal-slide') {
// 横向滑动 风格
this.skeletonType = 'waterfall';
this.skeletonConfig = {
gridRows: 1,
gridColumns: 3,
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '80%']
};
}
},
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
getData() {
var data = {
num: this.value.count
};
if (this.value.sources == 'diy') {
data.num = 0;
data.goods_id_arr = this.value.goodsId.toString();
}
this.$api.sendRequest({
url: '/groupbuy/api/goods/lists',
data: data,
success: res => {
if (res.code == 0) {
this.list = res.data;
// 切屏滚动,每页显示固定数量
if (this.value.template == 'horizontal-slide' && this.value.slideMode == 'slide') {
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
this.loading = false;
}
}
});
},
toDetail(e) {
this.$util.redirectTo('/pages_promotion/groupbuy/detail', {
groupbuy_id: e.groupbuy_id
});
},
imageError(index) {
this.list[index].goods_image = this.$util.getDefaultImage().goods;
this.$forceUpdate();
}
}
};
</script>
<style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
touch-action: none;
}
.diy-groupbuy {
&.row1-of1 {
.item {
display: flex;
margin-bottom: 20rpx;
padding: 16rpx;
&.shadow {
margin: 8rpx 8rpx 20rpx 8rpx;
}
&:last-child {
margin-bottom: 0;
padding-bottom: 20rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
>image {
width: 200rpx;
}
}
.goods-name {
margin-top: 6rpx;
line-height: 1.5;
}
.content {
flex: 1;
margin-left: 20rpx;
position: relative;
.discount-price {
white-space: nowrap;
font-weight: bold;
position: absolute;
bottom: 20rpx;
left: 0;
display: flex;
align-items: baseline;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
color: $base-color;
}
}
button {
position: absolute;
bottom: 10rpx;
right: 20rpx;
margin: 0;
padding: 0 20rpx;
background-color: $base-color;
color: #fff;
min-width: 112rpx;
height: 52rpx;
line-height: 52rpx;
font-size: $font-size-tag;
}
}
}
}
&.horizontal-slide {
.scroll {
width: calc(100% - 40rpx);
padding: 20rpx;
line-height: 1;
white-space: nowrap;
.item.shadow {
margin-bottom: 8rpx;
}
}
.flex-between {
justify-content: space-between;
}
.item {
display: inline-block;
width: 200rpx;
overflow: hidden;
box-sizing: border-box;
&:nth-child(3n + 3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
position: relative;
overflow: hidden;
margin: 0 auto;
>image {
width: 200rpx;
}
.bg {
position: absolute;
width: 100%;
height: 60rpx;
bottom: 0;
left: 0;
z-index: 2;
}
.num {
width: 180rpx;
position: absolute;
bottom: 10rpx;
padding-left: 20rpx;
font-size: 20rpx;
line-height: 1;
color: #ffffff;
z-index: 3;
}
}
.content {
padding: 10rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
&.multi-content {
height: 158rpx;
box-sizing: border-box;
}
.goods-name {
line-height: 1.3;
&.multi-hidden {
white-space: break-spaces;
}
}
.discount-price {
white-space: nowrap;
margin-top: auto;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
color: $base-color;
}
}
.original-price {
font-size: $font-size-tag;
color: $color-tip;
line-height: 1;
text-decoration: line-through;
}
}
}
.swiper {
width: 100%;
white-space: nowrap;
padding: 20rpx;
box-sizing: border-box;
.swiper-item {
display: flex;
align-items: center;
}
.item {
width: 200rpx;
}
}
}
}
</style>

View File

@@ -1,77 +0,0 @@
<template>
<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="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 + '%'
}" @click.stop="$util.diyRedirectTo(mapItem.link)"></view>
</view>
</view>
</template>
<script>
// 热区展示
import DiyMinx from './minx.js'
export default {
name: 'diy-hot-area',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
mixins: [DiyMinx],
data() {
return {};
},
created() { },
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
hotAreaWarp: function () {
var obj = '';
obj = 'background-color:' + this.value.componentBgColor + ';';
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;
}
},
methods: {}
};
</script>
<style lang="scss" scoped>
.hot-area-box {
position: relative;
width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.simple-graph-wrap {
line-height: 0;
overflow: hidden;
position: relative;
image {
width: 100%;
}
.heat-map {
position: absolute;
}
}
</style>

View File

@@ -1,88 +0,0 @@
<template>
<view data-component-name="diy-icon" class="diy-icon" :style="iconBgStyle">
<text class="js-icon" :class="iconClass" :style="iconStyle"></text>
</view>
</template>
<script>
// 图标展示
import DiyMinx from './minx.js'
export default {
name: 'diy-icon',
props: {
icon: {
type: String,
default: ''
},
value: {
type: Object,
default: function () {
return null;
}
}
},
mixins: [DiyMinx],
computed: {
iconClass() {
var _class = ' ' + this.icon;
if (this.value && this.value.iconColor.length > 1) _class += ' gradient';
return _class;
},
iconBgStyle() {
if (!this.value) return {};
var style = {
'border-radius': this.value.bgRadius + '%',
'background': ''
};
if (this.value.iconBgImg) style['background'] += 'url(' + this.$util.img(this.value.iconBgImg) + ') no-repeat bottom / contain'
if (this.value.iconBgColor.length) {
if (style.background) style.background += ',';
if (this.value.iconBgColor.length == 1) {
style.background += this.value.iconBgColor[0];
} else {
style['background'] += 'linear-gradient(' + this.value.iconBgColorDeg + 'deg, ' + this.value.iconBgColor.join(',') + ')';
}
}
return this.$util.objToStyle(style);
},
iconStyle() {
if (!this.value) return {};
var style = {
'font-size': this.value.fontSize + '%'
}
if (this.value.iconColor.length == 1) {
style.color = this.value.iconColor[0];
} else {
style['background'] = 'linear-gradient(' + this.value.iconColorDeg + 'deg, ' + this.value.iconColor.join(',') + ')';
}
return this.$util.objToStyle(style);
}
}
}
</script>
<style lang="scss">
.diy-icon {
width: 100%;
height: 100%;
font-size: 100%;
color: #000;
display: flex;
align-items: center;
justify-content: center;
.js-icon {
font-size: 50%;
line-height: 1;
padding: 1rpx;
&.gradient {
-webkit-background-clip: text !important;
-webkit-text-fill-color: transparent;
}
}
}
</style>

View File

@@ -1,273 +0,0 @@
<template>
<view :style="componentStyle">
<scroll-view :class="['image-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle]"
:scroll-x="value.showStyle == 'singleSlide'">
<view class="uni-scroll-view-content">
<view v-for="(item, index) in value.list" :key="index" :class="['image-nav-item', value.mode]"
style="margin-right: 28rpx;">
<!-- 图片部分 -->
<view v-if="value.mode != 'text'" class="image-img" :style="{
'font-size': (value.imageSize * 2 + 'rpx') + ';',
'width': (item.imgWidth / 2 + 'rpx') + ';',
'height': (item.imgHeight / 2 + 'rpx') + ';'
}">
<image v-if="item.link.wap_url" :style="{
'width': (item.imgWidth / 2 + 'rpx') + ';',
'height': (item.imgHeight / 2 + 'rpx') + ';'
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
:show-menu-by-longpress="true" @tap="redirectTo(item.link)"></image>
<image v-else :style="{
'width': (item.imgWidth / 2 + 'rpx') + ';',
'height': (item.imgHeight / 2 + 'rpx') + ';'
}" :src="$util.img(item.imageUrl) || $util.img('public/uniapp/default_img/goods.png')"
:show-menu-by-longpress="true" @tap="previewImg(item.imageUrl)"></image>
</view>
<!-- 文字部分 -->
<text class="image-text" :style="{
'width': (item.imgWidth / 2 + 'rpx') + ';',
'font-size': (value.font.size * 2 + 'rpx') + ';',
'font-weight': value.font.weight + ';',
'color': value.font.color + ';'
}">{{ item.title }}</text>
</view>
</view>
</scroll-view>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-image-nav',
props: {
value: {
type: Object,
default: () => ({})
}
},
mixins: [DiyMinx],
data() {
return {
pageWidth: '',
indicatorDots: false,
swiperCurrent: 0
}
},
created() {
// 组件创建时的逻辑
},
watch: {
componentRefresh(newValue) {
// 监听组件刷新
}
},
computed: {
componentStyle() {
let style = '';
style += 'background-color:' + this.value.componentBgColor + ';';
if (this.value.componentAngle == 'round') {
style += 'border-top-left-radius:' + (2 * this.value.topAroundRadius) + 'rpx;';
style += 'border-top-right-radius:' + (2 * this.value.topAroundRadius) + 'rpx;';
style += 'border-bottom-left-radius:' + (2 * this.value.bottomAroundRadius) + 'rpx;';
style += 'border-bottom-right-radius:' + (2 * this.value.bottomAroundRadius) + 'rpx;';
}
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 : '') + ';';
return style;
},
swiperHeight() {
let height = 0;
if (this.value.mode == 'graphic') {
height = (49 + this.value.imageSize) * this.value.pageCount;
} else if (this.value.mode == 'img') {
height = (22 + this.value.imageSize) * this.value.pageCount;
} else if (this.value.mode == 'text') {
height = 43 * this.value.pageCount;
}
return 'height:' + (2 * height) + 'rpx';
},
isIndicatorDots() {
return this.value.carousel.type != 'hide' &&
1 != Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount));
}
},
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) {
this.$util.diyRedirectTo(link);
} else {
this.$refs.login.open(link.wap_url);
}
},
// 轮播切换
swiperChange(event) {
this.swiperCurrent = event.detail.current;
}
}
}
</script>
<style lang="scss" scoped>
.image-nav {
padding: 16rpx;
box-sizing: border-box;
&.fixed-layout {
.uni-scroll-view-content {
display: flex;
flex-wrap: wrap;
}
}
&.singleSlide {
.uni-scroll-view-content {
display: flex;
}
.image-nav-item {
flex-shrink: 0;
}
}
&.pageSlide {
position: relative;
.uni-swiper-dots-horizontal {
bottom: 0rpx;
}
&.straightLine {
.uni-swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
}
&.circle {
.uni-swiper-dot {
width: 14rpx;
height: 14rpx;
}
}
}
.image-nav-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
.image-nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 14rpx 0;
box-sizing: border-box;
.image-text {
padding-top: 12rpx;
line-height: 1.5;
text-overflow: ellipsis;
overflow: hidden;
text-align: center;
&.alone {
padding-top: 0;
}
}
&.text {
.image-text {
padding-top: 0;
}
}
.image-img {
position: relative;
display: flex;
align-items: center;
justify-content: center;
font-size: 90rpx;
.tag {
position: absolute;
top: -10rpx;
right: -24rpx;
color: #fff;
border-radius: 24rpx;
border-bottom-left-radius: 0;
-webkit-transform: scale(0.8);
transform: scale(0.8);
padding: 8rpx 16rpx;
line-height: 1;
font-size: 24rpx;
}
.icon {
font-size: 50rpx;
color: #606266;
}
}
}
}
.swiper-dot-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: -20rpx;
padding-bottom: 8rpx;
.swiper-dot {
background-color: rgba(0, 0, 0, 0.3);
margin: 8rpx;
&.active {
background-color: #000;
}
}
&.straightLine {
.swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
}
&.circle {
.swiper-dot {
width: 15rpx;
border-radius: 50%;
height: 15rpx;
}
}
}
</style>

View File

@@ -1,318 +0,0 @@
<template>
<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" @click="handlerClick(imgAdsValue.list[0].link)"
@tap="handlerClick(imgAdsValue.list[0].link)">
<image :style="{ height: imgAdsValue.list[0].imgHeight }"
:src="$util.img(imgAdsValue.list[0].imageUrl)" mode="widthFix" :show-menu-by-longpress="true" />
</view>
</block>
<swiper v-else class="swiper" :style="{ height: swiperHeight }" :class="{
'swiper-left': imgAdsValue.indicatorLocation == 'left',
'swiper-right': imgAdsValue.indicatorLocation == 'right',
'ns-indicator-dots': imgAdsValue.carouselStyle == 'line'
}" :autoplay="true" :interval="imgAdsValue.interval" circular="true" :indicator-dots="isDots"
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" @click="handlerClick(item.link)" @tap="handlerClick(item.link)">
<view class="item" :style="imgAdsSwiper + 'height: ' + item.imgHeight">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
:show-menu-by-longpress="true" />
</view>
</swiper-item>
</swiper>
<!-- #ifdef MP-WEIXIN -->
<view v-if="imgAdsValue.list.length > 1 && value.indicatorIsShow" :class="[
'swiper-dot-box',
{ straightLine: imgAdsValue.carouselStyle == 'line' },
{ 'swiper-left': imgAdsValue.indicatorLocation == 'left' },
{ 'swiper-right': imgAdsValue.indicatorLocation == 'right' }
]">
<view v-for="(numItem, numIndex) in imgAdsValue.list.length" :key="numIndex"
:class="['swiper-dot', { active: numIndex == swiperIndex }]"
:style="[numIndex == swiperIndex && { backgroundColor: imgAdsValue.indicatorColor }]"></view>
</view>
<!-- #endif -->
</view>
</view>
</template>
<script>
// 图片广告
import DiyMinx from './minx.js'
export default {
name: 'diy-img-ads',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
isDots: true,
swiperHeight: 0,
imgAdsValue: null, // 深拷贝一遍数据,防止动态计算图片展示尺寸的时候,影响到父级的数据,导致二次渲染的时候,数据错误
swiperIndex: 0
};
},
created() {
this.calcSingleRow();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
imgAdsMarginWarp: function () {
var obj = '';
obj = 'background-color:' + this.value.componentBgColor + ';';
return obj;
},
imgAdsSwiper: function () {
var obj = '';
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;
},
singleGraphBg: function () {
var imgArr = [];
for (let i = 0; i < this.imgAdsValue.list.length; i++) {
let item = this.imgAdsValue.list[i];
imgArr[i] = parseFloat(item.imgHeight);
}
imgArr.sort(function (a, b) {
return b - a;
});
var obj = '';
obj += 'background-color:' + this.imgAdsValue.backgroundColor + ';';
obj += 'height:' + imgArr[0] * (this.imgAdsValue.backgroundHeight / 100) * 2 + 'rpx;';
return obj;
}
},
methods: {
swiperChange(e) {
this.swiperIndex = e.detail.current;
},
calcSingleRow() {
let minHeight = 0;
let systemInfo = uni.getSystemInfoSync()
// 深拷贝一层数据,防止数据更改越权
this.imgAdsValue = JSON.parse(JSON.stringify(this.value));
this.imgAdsValue.list.forEach((item, index) => {
var ratio = item.imgHeight / item.imgWidth;
item.imgWidth = systemInfo.windowWidth;
item.imgWidth -= this.value.margin.both * 2;
item.imgHeight = item.imgWidth * ratio;
// 获取最大高度 if (maxHeight == 0 || maxHeight < item.imgHeight) maxHeight = item.imgHeight;
if (minHeight == 0 || minHeight > item.imgHeight) minHeight = item.imgHeight;
});
this.imgAdsValue.list.forEach((item, index) => {
item.imgHeight = minHeight + 'px';
this.swiperHeight = minHeight + 'px';
});
this.imgAdsValue.indicatorColor = this.imgAdsValue.indicatorColor || '#fff';
if (this.value.indicatorIsShow === undefined) {
this.value.indicatorIsShow = true; // 控制指示点是否展示
}
// 是否显示指示器
if (this.imgAdsValue.list.length <= 1) {
this.isDots = false;
}
// #ifdef H5
this.isDots = this.value.indicatorIsShow;
// #endif
// #ifdef MP-WEIXIN
this.isDots = false;
// #endif
},
async handlerClick(link) {
await this.__$emitEvent({
eventName: 'img-ads-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.$util.diyRedirectTo(link);
}
})
},
}
};
</script>
<style lang="scss" scoped>
.single-graph {
width: 100%;
line-height: 0;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
box-sizing: border-box;
}
.simple-graph-wrap {
line-height: 0;
overflow: hidden;
position: relative;
image {
width: 100%;
}
.heat-map {
position: absolute;
}
}
.item.active text {
background: rgba(0, 0, 0, 0.3);
position: absolute;
bottom: 0;
color: #ffffff;
font-size: $font-size-tag;
width: 100%;
left: 0;
line-height: 40rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding: 0 10rpx;
text-align: center;
}
.swiper-box {
position: relative;
width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.swiper {
margin: 0 auto;
overflow: hidden;
}
.swiper-item {
width: 100%;
height: auto !important;
display: flex;
justify-content: center;
flex-direction: column;
// position: relative;
overflow: hidden;
.item {
width: 100%;
height: auto;
text-align: center;
position: relative;
overflow: hidden;
image {
width: 100%;
max-width: 100%;
height: 100%;
will-change: transform;
}
.heat-map {
position: absolute;
}
}
}
.swiper-dot-box {
position: absolute;
bottom: 20rpx;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 0 40rpx 8rpx;
box-sizing: border-box;
&.swiper-left {
justify-content: flex-start;
}
&.swiper-right {
justify-content: flex-end;
}
.swiper-dot {
background-color: #b2b2b2;
width: 15rpx;
border-radius: 50%;
height: 15rpx;
margin: 8rpx;
&.active {
background-color: rgba(0, 0, 0, 1);
}
}
&.straightLine {
.swiper-dot {
width: 18rpx;
height: 6rpx;
border-radius: 4rpx;
&.active {
width: 36rpx;
background-color: rgba(0, 0, 0, 1);
}
}
}
}
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
/deep/.uni-scroll-view::-webkit-scrollbar {
display: none;
}
.swiper /deep/ .uni-swiper-dots-horizontal {
bottom: 25rpx;
}
.swiper-left /deep/ .uni-swiper-dots-horizontal {
left: 40rpx;
transform: translate(0);
}
.swiper-right /deep/ .uni-swiper-dots-horizontal {
right: 40rpx;
display: flex;
justify-content: flex-end;
transform: translate(0);
}
.carousel-angle /deep/ .uni-swiper-dots-horizontal .uni-swiper-dot {
width: 24rpx;
border-radius: 0;
height: 8rpx;
}
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot {
width: 18rpx;
height: 6rpx;
border-radius: 4rpx;
}
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot-active {
width: 36rpx;
}
</style>

View File

@@ -1,863 +0,0 @@
<template>
<view data-component-name="diy-index-page">
<view class="bg" :style="warpCss">
<view class="index-page-content">
<view class="nav-top-category" :style="categoryCss">
<scroll-view v-if="value" scroll-with-animation class="diyIndex" scroll-x="true"
:scroll-into-view="'a' + pageIndex"
: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"
@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
}" v-if="value.styleType == 'fill'">
{{ item.short_name ? item.short_name : item.category_name }}
</view>
<view class="text-con" :class="index == pageIndex ? 'active' : ''"
:style="{ color: index == pageIndex ? value.selectColor : value.noColor }" v-else>
{{ item.short_name ? item.short_name : item.category_name }}
</view>
<view class="color-base-bg line" v-if="index == pageIndex && value.styleType != 'fill'"
:style="{ background: value.selectColor ? value.selectColor + '!important' : 'rgba(0,0,0,0)' + '!important' }">
</view>
</view>
</scroll-view>
<text class="iconfont icon-unfold unfold-arrows" :style="{ color: value.moreColor }"
@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 }]"
@click="changePageIndex(index)">
{{ item.short_name ? item.short_name : item.category_name }}
</text>
</view>
</uni-popup>
<view class="nav_top_category-fill" :style="{ height: moduleHeight }"></view>
<block v-if="pageIndex == 0">
<slot name="components"></slot>
<slot></slot>
</block>
<block v-else>
<slot name="components"></slot>
<view class="index-category-box">
<view class="category-goods" v-show="!isloading">
<mescroll-uni :top="uniPopTop" ref="mescroll" @getData="getGoodsList"
:background="'url(' + $util.img(bgUrl) + ') 0px -50px / 100% no-repeat'"
:paddingBoth="'30rpx'" @touchmove.prevent.stop>
<block slot="list">
<!-- 二级分类 -->
<view class="twoCategorylist"
v-if="twoCategorylist != 'undefined' && twoCategorylist && twoCategorylist.length > 0">
<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" @click="toCateGoodsList(item.category_id_2, 2)">
<view class="item-box">
<image :src="$util.img(item.image)" v-if="item.image"
mode="aspectFill" />
<image :src="$util.getDefaultImage().goods" v-else
mode="aspectFill" />
<view>{{ item.category_name }}</view>
</view>
</view>
</view>
</view>
<view class="twoCategory base"
v-if="twoCategorylist.length > 5 && twoCategorylist.length <= 10">
<view class="twoCategory-page">
<view class="swiper-item" v-for="(item, index) in twoCategorylist"
: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" />
<image :src="$util.getDefaultImage().goods" v-else
mode="aspectFill" />
<view>{{ item.category_name }}</view>
</view>
</view>
</view>
</view>
<swiper class="twoCategory big" :duration="500"
v-if="twoCategorylist.length > 10" @change="swiperTocategoryChange">
<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"
@click="toCateGoodsList(item.category_id_2, 2)">
<view class="item-box">
<image :src="item.image" mode="aspectFill" />
<view>{{ item.category_name }}</view>
</view>
</view>
</swiper-item>
</swiper>
<view class="dot-box">
<view class="dot-item" v-for="page in maxPage" v-if="maxPage > 1"
:key="page"
:class="twoCategorylistId == page - 1 ? 'active color-base-bg' : ''">
</view>
</view>
</view>
<!-- 分类广告 -->
<image class="category_adv" v-if="cateList[pageIndex].image_adv"
: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" @click="toDetail(item)">
<view class="goods-img">
<image :src="goodsImg(item.goods_image)" mode="widthFix"
@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)" />
</view>
</view>
<view class="info-wrap">
<view class="name-wrap">
<view class="goods-name">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
</view>
<view class="lineheight-clear">
<view class="discount-price">
<text class="unit color-base-text font-size-tag">{{
$lang('common.currencySymbol') }}</text>
<text class="price color-base-text font-size-toolbar">{{
showPrice(item) }}</text>
</view>
<view class="member-price-tag"
v-if="item.member_price && item.member_price == showPrice(item)">
<image :src="$util.img('public/uniapp/index/VIP.png')"
mode="widthFix" />
</view>
<view class="member-price-tag" v-else-if="item.promotion_type == 1">
<image :src="$util.img('public/uniapp/index/discount.png')"
mode="widthFix" />
</view>
</view>
<view class="pro-info">
<view class="delete-price font-size-activity-tag color-tip"
v-if="showMarketPrice(item)">
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
<text>{{ showMarketPrice(item) }}</text>
</view>
<view class="sale font-size-activity-tag color-tip">已售{{
item.sale_num }}{{ item.unit ? item.unit : '件' }}</view>
</view>
</view>
</view>
</view>
<view v-if="!isloading && goodsList[pageIndex].list.length == 0">
<ns-empty text="该分类下暂无商品" :isIndex="false"></ns-empty>
</view>
</block>
</mescroll-uni>
<!-- <ns-empty v-else-if="!isloading" :isIndex="false" text="该分类下暂无商品"></ns-empty> -->
</view>
<view class="loading" v-show="isloading"><ns-loading ref="loading"></ns-loading></view>
</view>
</block>
</view>
</view>
</view>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-index-page',
props: {
value: {
type: Object
},
bgUrl: {
type: String
},
scrollTop: {
type: [String, Number],
default: '0'
},
diyGlobal: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
pageIndex: 0, //当前选中分类id
cateList: [{
//header分类
category_name: '首页'
}],
twoCategorylist: [], //二级分类
twoCategorylistId: 0, //二级分类所在的swiper
goodsList: {},
isloading: true,
top: 0,
isUnfold: true, //是否展开菜单
moduleHeight: '' //组件高度
};
},
computed: {
warpCss() {
var obj = '';
obj += (this.bgUrl ? 'background:' + 'url(' + this.$util.img(this.bgUrl) + ') no-repeat 0 0/100%' : '') + ';';
return obj;
},
categoryCss() {
var obj = '';
obj += 'top:' + this.fixedTop + ';';
// obj += 'background-color:' + (this.value.componentBgColor || this.value.pageBgColor) + ';';
obj += 'background-color:' + this.topNavColor + ';';
return obj;
},
maxPage() {
let num = 0;
if (this.twoCategorylist && this.twoCategorylist.length) {
num = Math.ceil(this.twoCategorylist.length / 10);
}
return num;
},
type() {
if (this.value) {
return true;
} else {
return false;
}
},
topNavColor() {
var color = this.value.componentBgColor || this.value.pageBgColor;
if (this.diyGlobal.topNavBg && this.scrollTop > 20) color = this.diyGlobal.topNavColor;
return color;
},
fixedTop() {
let diyPositionObj = this.$store.state.diyGroupPositionObj;
let data = 0;
if (diyPositionObj.diySearch && diyPositionObj.diyIndexPage && diyPositionObj.nsNavbar) {
if (diyPositionObj.diySearch.moduleIndex > diyPositionObj.diyIndexPage.moduleIndex) data =
diyPositionObj.nsNavbar.originalVal + 'px';
else data = diyPositionObj.nsNavbar.originalVal + diyPositionObj.diySearch.originalVal + 'px';
} else if (diyPositionObj.diyIndexPage && diyPositionObj.nsNavbar) {
data = diyPositionObj.nsNavbar.originalVal + 'px';
}
return data;
},
// 分类导航展开菜单的位置
uniPopTop() {
let diyPositionObj = this.$store.state.diyGroupPositionObj;
let data = '0';
if (this.fixedTop && diyPositionObj.diyIndexPage)
data = Number.parseFloat(this.fixedTop) + diyPositionObj.diyIndexPage.originalVal + 'px';
return data;
}
},
watch: {
type(newVal, oldVal) {
if (newVal) {
this.getCategoryList();
}
}
},
mounted() {
this.getCategoryList();
setTimeout(() => {
// 获取组件的高度默认高度为4545是在375屏幕上的高度
const query = uni.createSelectorQuery();
// #ifdef H5
let cssSelect = '.page-header .u-navbar';
this.top = 100;
// #endif
// #ifdef MP
let cssSelect = '.page-header >>> .u-navbar';
this.top = 20;
// #endif
query
.select(cssSelect)
.boundingClientRect(data => {
let height;
if (this.diyGlobal.navBarSwitch) {
height = data ? data.height : 45;
} else {
height = data ? data.height : 0;
}
// #ifdef H5
this.top += height * 2;
// #endif
// #ifdef MP
this.top += height;
// #endif
})
.exec();
});
this.setModuleLocationFn();
},
methods: {
initPageIndex() {
this.pageIndex = 0;
this.showModuleFn();
},
//请求分类列表
getCategoryList() {
let url = '/api/goodscategory/tree';
let data = {
level: 3
};
this.$api.sendRequest({
url: url,
data: data,
success: res => {
if (res.code >= 0) {
let arr = [];
let obj = {
list: []
};
obj.category_name = this.value.title ? this.value.title : '首页';
arr.push(obj);
this.cateList = arr.concat(res.data);
Object.keys(this.cateList).forEach((key, index) => {
this.goodsList[key] = {
page: 1,
list: []
};
});
this.twoCategorylist = this.cateList[this.pageIndex].child_list;
}
}
});
},
//修改当前页面id
changePageIndex(e) {
this.isloading = true;
this.pageIndex = e;
this.showModuleFn();
if (e == 0) return;
this.twoCategorylist = this.cateList[this.pageIndex].child_list;
if (this.cateList[this.pageIndex].child_list) {
this.twoCategorylist = this.cateList[this.pageIndex].child_list;
this.twoCategorylist.forEach(v => {
if (v.image) {
v.image = this.$util.img(v.image);
} else {
v.image = this.$util.getDefaultImage().goods;
}
});
} else {
this.twoCategorylist = false;
}
if (this.$refs.mescroll) {
this.$refs.mescroll.refresh();
this.$refs.mescroll.myScrollTo(0);
}
},
//监听二级分类 页面切换
swiperTocategoryChange(e) {
this.twoCategorylistId = e.detail.current;
},
toDetail(item) {
this.$util.redirectTo('/pages_goods/detail', {
goods_id: item.goods_id
});
},
getGoodsList(mescroll) {
let id = this.pageIndex;
var data = {
page: mescroll.num,
page_size: mescroll.size
};
data.category_id = this.cateList[this.pageIndex].category_id_1;
data.category_level = 1;
this.$api.sendRequest({
url: '/api/goodssku/page',
data: data,
success: res => {
this.isloading = false;
let newArr = [];
let msg = res.message;
if (res.code == 0 && res.data) {
this.count = res.data.count;
newArr = res.data.list;
} else {
this.$util.showToast({
title: msg
});
}
mescroll.endSuccess(newArr.length);
//设置列表数据
if (mescroll.num == 1) this.goodsList[id].list = []; //如果是第一页需手动制空列表
this.goodsList[id].list = this.goodsList[id].list.concat(newArr); //追加新数据
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
this.$forceUpdate();
}
});
},
toCateGoodsList(e, f) {
this.$util.redirectTo('/pages_goods/list', {
category_id: e,
category_level: f
});
},
goodsImg(imgStr) {
let imgs = imgStr.split(',');
return imgs[0] ? this.$util.img(imgs[0], {
size: 'mid'
}) : this.$util.getDefaultImage().goods;
},
imgError(index) {
this.goodsList[index].goods_image = this.$util.getDefaultImage().goods;
},
showPrice(data) {
let price = data.discount_price;
if (data.member_price && parseFloat(data.member_price) < parseFloat(price)) price = data.member_price;
return price;
},
showMarketPrice(item) {
if (item.market_price_show) {
let price = this.showPrice(item);
if (item.market_price > 0) {
return item.market_price;
} else if (parseFloat(item.price) > parseFloat(price)) {
return item.price;
}
}
return '';
},
goodsTag(data) {
return data.label_name || '';
},
// 控制菜单展开关闭
unfoldMenu() {
if (this.isUnfold) this.$refs.navTopCategoryPop.open();
else this.$refs.navTopCategoryPop.close();
this.isUnfold = !this.isUnfold;
},
// 向vuex中的diyIndexPositionObj增加分类导航组件定位位置
setModuleLocationFn() {
const query = uni.createSelectorQuery().in(this);
query.select('.nav-top-category')
.boundingClientRect(data => {
let diyIndexPage = {
originalVal: data.height || 0, //自身高度 px
moduleIndex: this.value.moduleIndex //组件在diy-group的位置
};
this.moduleHeight = (data.height || 0) + 'px';
this.$store.commit('setDiyGroupPositionObj', {
diyIndexPage: diyIndexPage
});
}).exec();
},
showModuleFn() {
let searchModule = this.$root.diyData.value.filter((item, index) => {
return item.componentName == 'Search';
});
// setDiyGroupShowModule值为【】表示显示所有组件,为【null】则什么组件也不显示
if (this.pageIndex == 0) this.$store.commit('setDiyGroupShowModule', JSON.stringify([]));
else {
if (searchModule[0].positionWay == 'fixed') this.$store.commit('setDiyGroupShowModule', JSON.stringify(
['Search']));
else this.$store.commit('setDiyGroupShowModule', JSON.stringify(['null']));
}
// 特殊处理,切换分类导航导致页面无法上下滚动
// #ifdef H5
if (this.pageIndex == 0) {
// 标记当前页使用了mescroll (需延时,确保page已切换)
setTimeout(function () {
let uniPageDom = document.getElementsByTagName('uni-page')[0];
uniPageDom && uniPageDom.removeAttribute('use_mescroll');
}, 30);
}
// #endif
}
}
};
</script>
<style lang="scss">
.bg {
width: 100%;
height: 100%;
}
.nav-top-category {
display: flex;
align-items: center;
position: fixed;
z-index: 999;
transition: background 0.3s;
width: 100%;
padding: 0 24rpx;
box-sizing: border-box;
.text-fiexd {
.text-con {
line-height: 60rpx;
}
}
.unfold-arrows {
position: relative;
margin-left: 4rpx;
padding-left: 16rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
color: #fff;
}
}
.nav-topcategory-pop {
padding: 0 10rpx 20rpx;
display: flex;
flex-wrap: wrap;
background-color: #fff;
.category-item {
padding: 0 30rpx;
height: 60rpx;
text-align: center;
line-height: 56rpx;
border-radius: 40rpx;
background-color: #f0f0f0;
margin: 20rpx 10rpx 0;
font-size: 24rpx;
border: 2rpx solid transparent;
box-sizing: border-box;
&.active {
background-color: transparent;
}
}
}
.diyIndex {
width: 100%;
height: 100rpx;
white-space: nowrap;
padding: 20rpx 0 0;
box-sizing: border-box;
&.widthAuto {
width: auto;
}
.item {
position: relative;
margin-right: 40rpx;
display: inline-block;
line-height: 80rpx;
font-size: $font-size-base;
text-align: center;
.text-con {
height: 30px;
line-height: 30px;
&.active {
font-size: $font-size-base;
font-weight: bold;
}
}
.text-con.active {
font-size: $font-size-base;
font-weight: bold;
}
.line {
position: absolute;
left: calc(50% - 14rpx);
width: 28rpx;
height: 5rpx;
border-radius: 5rpx;
}
&.fill {
border-radius: 50rpx;
padding: 0 10rpx;
.text-con.active {
font-size: $font-size-base;
font-weight: 600;
color: #fff;
}
}
}
}
.index-page-box {
width: 100%;
height: calc(100vh - 288rpx);
}
.index-page-content {
width: 100%;
// height: calc(100vh - 144px);
}
.index-category-box.active {
padding-bottom: 160rpx;
padding-bottom: calc(160rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(160rpx + env(safe-area-inset-bottom));
}
.index-category-box {
width: 100%;
padding-bottom: 110rpx;
padding-bottom: calc(110rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(110rpx + env(safe-area-inset-bottom));
.twoCategorylist {
position: relative;
}
.twoCategory.min {
height: 160rpx;
}
.twoCategory.big {
height: 340rpx;
}
.twoCategory {
width: 100%;
background: #ffffff;
border-radius: 15rpx;
overflow: hidden;
margin-top: 20rpx;
.twoCategory-page {
width: 100%;
height: 100%;
padding: 20rpx;
box-sizing: border-box;
}
.swiper-item {
width: 120rpx;
height: 120rpx;
display: inline-block;
margin-right: calc((100% - 120rpx * 5) / 4);
overflow: hidden;
.item-box {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
image {
width: 88rpx;
height: 88rpx;
}
view {
width: 100%;
font-size: 22rpx;
line-height: 1;
margin-top: 10rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
text-align: center;
}
}
}
.swiper-item:nth-child(5n) {
margin-right: 0;
}
.swiper-item:nth-child(10n + 6) {
margin-top: 15rpx;
}
}
.dot-box {
width: calc(100% - 40rpx);
height: 50rpx;
position: absolute;
bottom: 0rpx;
left: 20rpx;
background: rgba($color: #000000, $alpha: 0);
display: flex;
justify-content: center;
align-items: center;
.dot-item {
width: 12rpx;
height: 12rpx;
background: #cccccc;
border-radius: 6rpx;
margin-right: 10rpx;
}
.dot-item.active {
width: 24rpx;
}
}
.category_adv {
width: 100%;
margin: 20rpx 0;
border-radius: 15rpx;
}
.category-goods {
width: 100%;
}
}
.loading {
width: 100%;
height: 50rpx;
margin-top: 100rpx;
}
/deep/.uni-scroll-view::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
}
.goods-list.double-column {
display: flex;
flex-wrap: wrap;
margin-top: $margin-updown;
.goods-item {
flex: 1;
position: relative;
background-color: #fff;
flex-basis: 48%;
max-width: calc((100% - 30rpx) / 2);
margin-right: $margin-both;
margin-bottom: $margin-updown;
border-radius: $border-radius;
&:nth-child(2n) {
margin-right: 0;
}
.goods-img {
position: relative;
overflow: hidden;
padding-top: 100%;
border-top-left-radius: $border-radius;
border-top-right-radius: $border-radius;
image {
width: 100%;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
}
.goods-tag {
color: #fff;
line-height: 1;
padding: 8rpx 16rpx;
position: absolute;
border-bottom-right-radius: $border-radius;
top: 0;
left: 0;
font-size: $font-size-goods-tag;
}
.goods-tag-img {
position: absolute;
border-top-left-radius: $border-radius;
width: 80rpx;
height: 80rpx;
top: 0;
left: 0;
z-index: 5;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.info-wrap {
padding: 0 26rpx 26rpx 26rpx;
}
.goods-name {
font-size: $font-size-base;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin-top: 20rpx;
height: 68rpx;
}
.discount-price {
display: inline-block;
font-weight: bold;
line-height: 1;
margin-top: 16rpx;
.unit {
margin-right: 6rpx;
}
}
.pro-info {
display: flex;
margin-top: 16rpx;
.delete-price {
text-decoration: line-through;
flex: 1;
.unit {
margin-right: 6rpx;
}
}
&>view {
line-height: 1;
&:nth-child(2) {
text-align: right;
}
}
}
.member-price-tag {
display: inline-block;
width: 60rpx;
line-height: 1;
margin-left: 6rpx;
image {
width: 100%;
}
}
}
}
</style>

View File

@@ -1,74 +0,0 @@
<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">
<view class="fui-list jump" v-if="index == 0">
<view class="fui-list-media">
<image class="round" :src="$util.img(item.imageUrl)" style="border-radius:6rpx"></image>
</view>
<view class="fui-list-inner">
<view class="title" style="height: 75rpx;">
<text style="font-weight:600" :style="{ color: item.textColor }">{{ item.title }}</text>
<view class="subtitle" style="font-size:24rpx" :style="{ color: item.textColor }">{{ item.desc }}
</view>
</view>
</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 }" @click="previewSqs()">立即添加</span>
</view>
</view>
</view>
</view>
</template>
<script>
// 客服展示
import DiyMinx from './minx.js'
export default {
name: 'diy-kefu',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
loading: true,
};
},
created() {
// this.getDataList();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
// this.getDataList();
}
},
computed: {
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return css;
}
},
methods: {
previewSqs() {
var img = this.$util.img(this.value.list[1].imageUrl)
uni.previewImage({
current: img,
urls: [img]
})
}
}
};
</script>
<style lang="scss"></style>

View File

@@ -1,80 +0,0 @@
<template>
<view data-component-name="diy-listmenu" class="diy-listmenu" :style="style">
<view class="fui-cell-group">
<!-- <image mode="widthFix" style="width: 100%;" :src="$util.img(item.imageUrl)"></image> -->
<view v-for="(item, index) in value.list" @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"
:style="{ maxWidth: value.imageSize * 2 + 'rpx', maxHeight: value.imageSize * 2 + 'rpx', width: '100%', height: '100%' }"></diy-icon>
<image v-if="item.iconType == 'img'" mode="widthFix" :src="$util.img(item.imageUrl)"
style="border-radius:6rpx;width: 60rpx;"></image>
</view>
<view class="fui-cell-text" style="color:#333;">{{ item.title }}</view>
<view class="fui-cell-remark" style="font-size: 24rpx;">{{ lang == 'en-us' ? 'view' : '查看' }}</view>
</view>
</view>
</view>
</template>
<script>
// 自定义列表菜单展示
import DiyMinx from './minx.js'
export default {
name: 'diy-listmenu',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
loading: true,
lang: uni.getStorageSync("lang")//en-us 英文
};
},
created() {
// this.getDataList();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
// this.getDataList();
}
},
computed: {
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.margin.top > 0) css += 'margin-top:' + this.value.margin.top * 2 + 'rpx;';
return css;
}
},
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);
return;
}
}
this.$util.diyRedirectTo(link);
},
}
};
</script>
<style lang="scss">
.img-cell {
padding: 0 16rpx !important;
}
</style>

View File

@@ -1,259 +0,0 @@
<template>
<x-skeleton data-component-name="diy-live" type="banner" :loading="loading" :configs="skeletonConfig">
<view class="live-wrap" @click="handlerClick(liveInfo.roomid)" @tap="handlerClick(liveInfo.roomid)"
v-if="liveInfo">
<view class="banner-wrap">
<image
:src="liveInfo.banner != '' ? $util.img(liveInfo.banner) : $util.img('public/uniapp/live/live_default_banner.png')"
mode="widthFix"
@error="liveInfo.banner = $util.img('public/uniapp/live/live_default_banner.png')" />
<view class="shade"></view>
<view class="wrap">
<view class="room-name">
<text class="status-name font-size-base"
:class="{ 'color-base-bg': liveInfo.live_status == '101' }">
<text class="iconfont icon-zhibozhong font-size-sub"
v-if="liveInfo.live_status == '101'"></text>
<text class="iconfont icon-zhibojieshu font-size-sub" v-else></text>
{{ liveInfo.status_name }}
</text>
{{ liveInfo.name }}
</view>
</view>
</view>
<view class="room-info" v-if="value.isShowAnchorInfo || value.isShowLiveGood">
<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" />
<text class="anchor-name">主播{{ liveInfo.anchor_name }}</text>
</block>
<text class="separate" v-if="value.isShowAnchorInfo && value.isShowLiveGood">|</text>
<block v-if="value.isShowLiveGood">
<text class="goods-text">直播商品{{ liveInfo.goods.length }}</text>
</block>
</view>
</view>
</x-skeleton>
</template>
<script>
// 直播
import DiyMinx from './minx.js'
export default {
components: {},
name: 'diy-live',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
loading: true,
skeletonConfig: {
headHeight: '200rpx'
},
liveInfo: {
banner: '',
anchor_img: ''
}
};
},
created() {
this.getLiveInfo();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getLiveInfo();
}
},
methods: {
getLiveInfo() {
this.$api.sendRequest({
url: '/live/api/live/info',
success: res => {
if (res.code == 0 && res.data) {
this.liveInfo = res.data;
this.getLiveStatus();
} else {
this.liveInfo = null;
}
this.loading = false;
}
});
},
entryRoom(roomId) {
// #ifdef MP-WEIXIN
wx.navigateTo({
url: `plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=${roomId}`
});
// #endif
},
getLiveStatus() {
// #ifdef MP-WEIXIN
let livePlayer = requirePlugin('live-player-plugin');
livePlayer.getLiveStatus({
room_id: this.liveInfo.roomid
}).then(res => {
const liveStatus = res.liveStatus;
if (liveStatus && liveStatus != this.liveInfo.live_status) {
this.changeLiveStatus(liveStatus);
}
})
.catch(err => {
console.log('get live status', err);
});
// 往后间隔1分钟或更慢的频率去轮询获取直播状态
var timer = setInterval(() => {
livePlayer
.getLiveStatus({
room_id: this.liveInfo.roomid
})
.then(res => {
const liveStatus = res.liveStatus;
if (liveStatus && liveStatus != this.liveInfo.live_status) {
this.changeLiveStatus(liveStatus);
}
if (this.$util.inArray(liveStatus, [103, 104, 106, 107])) {
clearInterval(timer);
}
})
.catch(err => {
console.log('get live status', err);
});
}, 60000);
// #endif
},
changeLiveStatus(status) {
this.$api.sendRequest({
url: '/live/api/live/modifyLiveStatus',
data: {
room_id: this.liveInfo.roomid,
status: status
},
success: res => {
if (res.code == 0) {
this.getLiveInfo();
}
}
});
},
async handlerClick(roomid) {
await this.__$emitEvent({
eventName: 'live-tap', data: roomid, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.entryRoom(roomid);
}
})
},
}
};
</script>
<style lang="scss">
.live-wrap {
background: #fff;
border-radius: 16rpx;
overflow: hidden;
}
.banner-wrap {
width: 100%;
position: relative;
line-height: 1;
display: flex;
image {
width: 100%;
}
.shade {
width: 100%;
height: 100%;
position: absolute;
background: rgba($color: #888, $alpha: 0.3);
left: 0;
top: 0;
z-index: 5;
}
.wrap {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 10;
padding: 26rpx 20rpx;
box-sizing: border-box;
.room-name {
font-size: $font-size-toolbar;
color: #fff;
line-height: 1;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: flex;
align-items: center;
.status-name {
display: inline-block;
font-size: $font-size-activity-tag;
color: #fff;
padding: 8rpx 12rpx;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 36rpx;
margin-right: 20rpx;
.icon-zhibozhong {
font-size: $font-size-activity-tag;
color: #fff;
margin-right: 9rpx;
}
}
}
}
}
.room-info {
padding: 20rpx 30rpx;
background: #fff;
display: flex;
.anchor-img {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 20rpx;
}
.anchor-name,
.goods-text {
font-size: $font-size-base;
line-height: 60rpx;
}
.separate {
color: #808080;
margin: 0 10rpx;
line-height: 56rpx;
}
}
</style>
<style scoped>
.coupon-all>>>.uni-scroll-view::-webkit-scrollbar {
display: none;
}
</style>

View File

@@ -1,260 +0,0 @@
<template>
<view data-component-name="diy-many-goods-list" class="many-goods-list">
<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" @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 class="desc" :class="{ 'color-base-bg': index == cateIndex && item.desc }">{{ item.desc }}
</view>
</view>
</view>
</scroll-view>
<view class="many-goods-list-fill" :style="{ 'height': manyInfo.height }" v-if="fixedTop"></view>
<diy-goods-list class="many-goods-list-body" v-if="goodsValue" :value="goodsValue"
ref="diyGoodsList"></diy-goods-list>
</view>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-many-goods-list',
props: {
value: {
type: Object,
default: () => {
return {};
}
},
scrollTop: {
type: [Number, String]
},
global: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
cateIndex: 0, // 当前选中的分类id
goodsValue: null, // 商品列表数据
manyInfo: {
bodyHeight: 0,
bodyTop: 0,
height: 0,
top: 0
}
};
},
created() {
this.changeCateIndex(this.value.list[0], 0, true);
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.changeCateIndex(this.value.list[0], 0, true);
},
scrollTop: function (nval) {
const query = uni.createSelectorQuery().in(this);
query
.select('.many-goods-list')
.boundingClientRect(data => {
if (data) {
this.manyInfo.top = data.top;
}
})
.exec();
query
.select('.many-goods-list .many-goods-list-body')
.boundingClientRect(data => {
if (data) {
this.manyInfo.bodyHeight = (data.height || 0);
this.manyInfo.bodyTop = (data.top || 0);
}
})
.exec();
}
},
computed: {
fixedTop() {
let diyPositionObj = JSON.parse(JSON.stringify(this.$store.state.diyGroupPositionObj));
let positionHeight = 0;
let height = 0;
delete diyPositionObj.diyManyGoodsList;
if (diyPositionObj) {
let arr = Object.values(diyPositionObj);
arr.forEach((item, index) => {
positionHeight += item.originalVal; //定位的高度【搜索框+导航分类+自定义头部】
});
}
if (this.manyInfo.top < positionHeight && (this.manyInfo.bodyTop + this.manyInfo.bodyHeight >
positionHeight + Number.parseFloat(this.manyInfo.height))) {
height = positionHeight;
}
return height;
},
manyWrapCss() {
let html = '';
html += `position: ${this.fixedTop ? 'fixed' : 'initial'};`
html += `top: ${this.fixedTop}px;`
if (!this.global.topNavBg)
html += `background-color: #fff;`
else
html += `background-color: ${this.fixedTop ? this.global.topNavColor : 'transparent'};`
return html;
}
},
mounted() {
const query = uni.createSelectorQuery().in(this);
query
.select('.many-goods-list .many-goods-list-head')
.boundingClientRect(data => {
if (data) {
this.manyInfo.height = (data.height || 0) + 'px';
// 向vuex中的diyIndexPositionObj增加多商品组件定位位置
let diyManyGoodsList = {
originalVal: data.height || 0 //自身高度 px
}
this.$store.commit('setDiyGroupPositionObj', {
diyManyGoodsList: diyManyGoodsList
});
}
})
.exec();
},
methods: {
changeCateIndex(item, index, isFirst) {
this.cateIndex = index;
this.goodsValue = {
sources: item.sources,
categoryId: item.categoryId,
categoryName: item.categoryName,
goodsId: item.goodsId,
componentBgColor: this.value.componentBgColor,
componentAngle: this.value.componentAngle,
topAroundRadius: this.value.topAroundRadius,
bottomAroundRadius: this.value.bottomAroundRadius,
elementBgColor: this.value.elementBgColor,
elementAngle: this.value.elementAngle,
topElementAroundRadius: this.value.topElementAroundRadius,
bottomElementAroundRadius: this.value.bottomElementAroundRadius,
count: this.value.count,
nameLineMode: this.value.nameLineMode,
template: this.value.template,
style: this.value.style,
ornament: this.value.ornament,
sortWay: this.value.sortWay,
saleStyle: this.value.saleStyle,
tag: this.value.tag,
btnStyle: this.value.btnStyle,
goodsNameStyle: this.value.goodsNameStyle,
theme: this.value.theme,
priceStyle: this.value.priceStyle,
slideMode: this.value.slideMode,
imgAroundRadius: this.value.imgAroundRadius,
margin: this.value.margin,
goodsMarginType: this.value.goodsMarginType,
goodsMarginNum: this.value.goodsMarginNum
};
// 如果是第一次加载,不需要执行下面代码
if (isFirst) return;
this.$refs.diyGoodsList.goodsValue = this.goodsValue;
this.$refs.diyGoodsList.getGoodsList();
},
async handlerClick({ item, index }) {
await this.__$emitEvent({
eventName: 'many-goods-list-tap', data: { item, index }, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.changeCateIndex(item, index, false);
}
})
},
}
};
</script>
<style lang="scss" scoped>
.many-goods-list-head {
left: 0;
right: 0;
z-index: 5;
background-color: #fff;
}
scroll-view {
width: 100%;
white-space: nowrap;
box-sizing: border-box;
padding: 20rpx 0;
.scroll-item {
display: inline-block;
text-align: center;
vertical-align: top;
width: calc(25% - 40rpx);
position: relative;
padding: 0 20rpx;
&:first-child {
width: calc(25% - 20rpx);
padding-left: 0;
}
.split-line {
display: inline-block;
width: 1rpx;
height: 30rpx;
background-color: #e5e5e5;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
&.active {
.name {
font-weight: bold;
}
.desc {
color: #ffffff;
border-radius: 20rpx;
}
}
.name {
font-size: 32rpx;
color: $color-title;
line-height: 1;
}
.cate {
display: inline-block;
}
.desc {
font-size: $font-size-tag;
color: $color-tip;
height: 36rpx;
line-height: 36rpx;
margin-top: 10rpx;
min-width: 120rpx;
max-width: 220rpx;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 10rpx;
}
}
}
</style>

View File

@@ -1,82 +0,0 @@
<template>
<view data-component-name="diy-map" class="diy-map" :style="style">
<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
style="position:absolute;right:10px;bottom:30rpx;z-index:99999;background:#4390FF;padding:5px 10px;wxcs_style_padding:10rpx 20rpx;border-radius:8rpx;color: #fff;"
@click="handlerClick(item)" @tap="handlerClick(item)">
<cover-view style="font-size:24rpx">一键导航</cover-view>
</cover-view>
</map>
</view>
</view>
</template>
<script>
// 地图
import DiyMinx from './minx.js'
export default {
name: 'diy-map',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
markers: []
};
},
created() {
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
// this.getDataList();
}
},
computed: {
markerst() {
return [{
id: 1,
latitude: this.value.list[0].lat,
longitude: this.value.list[0].lng
}]
},
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return css;
}
},
methods: {
tomap(item) {
uni.openLocation({
latitude: parseFloat(item.lat),
longitude: parseFloat(item.lng),
name: "一键导航",
})
},
async handlerClick(item) {
await this.__$emitEvent({
eventName: 'map-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.tomap(item);
}
})
}
}
};
</script>
<style lang="scss"></style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,279 +0,0 @@
<template>
<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" @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" />
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_pay_shade.png') + ')'">
</view>
</template>
<template v-else>
<diy-icon :icon="value.icon.waitPay.icon" v-if="value.icon.waitPay"
:value="value.icon.waitPay.style ? value.icon.waitPay.style : null"></diy-icon>
</template>
<text v-if="orderNum.waitpay > 0" class="order-num color-base-bg price-font">{{ orderNum.waitpay
> 99 ? '99+' :
orderNum.waitpay }}</text>
</view>
<view class="title">{{ $lang('waitpay') }}</view>
</view>
<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"></image>
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_send_shade.png') + ')'">
</view>
</template>
<template v-else>
<diy-icon :icon="value.icon.waitSend.icon" v-if="value.icon.waitSend"
:value="value.icon.waitSend.style ? value.icon.waitSend.style : null"></diy-icon>
</template>
<text v-if="orderNum.waitsend > 0" class="order-num color-base-bg price-font">{{
orderNum.waitsend > 99 ? '99+'
: orderNum.waitsend }}</text>
</view>
<view class="title">{{ $lang('waitsend') }}</view>
</view>
<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" />
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_confirm_shade.png') + ')'">
</view>
</template>
<template v-else>
<diy-icon :icon="value.icon.waitConfirm.icon" v-if="value.icon.waitConfirm"
:value="value.icon.waitConfirm.style ? value.icon.waitConfirm.style : null"></diy-icon>
</template>
<text v-if="orderNum.waitconfirm > 0" class="order-num color-base-bg price-font">{{
orderNum.waitconfirm > 99 ?
'99+' : orderNum.waitconfirm }}</text>
</view>
<view class="title">{{ $lang('waitconfirm') }}</view>
</view>
<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" />
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_rate_shade.png') + ')'">
</view>
</template>
<template v-else>
<diy-icon :icon="value.icon.waitUse.icon" v-if="value.icon.waitUse"
:value="value.icon.waitUse.style ? value.icon.waitUse.style : null"></diy-icon>
</template>
<!-- <text v-if="orderNum.wait_use > 0" class="order-num color-base-bg price-font">{{ orderNum.wait_use > 99 ? '99+' : orderNum.wait_use }}</text> -->
</view>
<view class="title">{{ $lang('completed') }}</view>
</view>
<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" />
<view class="icon-shade"
:style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/refunding_shade.png') + ')'">
</view>
</template>
<template v-else>
<diy-icon :icon="value.icon.refunding.icon" v-if="value.icon.refunding"
:value="value.icon.refunding.style ? value.icon.refunding.style : null"></diy-icon>
</template>
<text v-if="orderNum.refunding > 0" class="order-num color-base-bg price-font">{{
orderNum.refunding > 99 ?
'99+' : orderNum.refunding }}</text>
</view>
<view class="title">{{ $lang('activist') }}</view>
</view>
</view>
</view>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
// 自定义会员中心——我的订单展示
import DiyMinx from './minx.js'
export default {
name: 'diy-member-my-order',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
orderNum: {
waitpay: 0,
waitsend: 0,
waitconfirm: 0,
refunding: 0,
wait_use: 0,
waitrate: 0
}
};
},
created() {
this.init();
},
watch: {
storeToken(nVal, oVal) {
this.init();
},
// 组件刷新监听
componentRefresh: function (nval) {
this.init();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
}
},
methods: {
init() {
if (this.storeToken) {
this.getOrderNum();
} else {
this.orderNum = {
waitpay: 0,
waitsend: 0,
waitconfirm: 0,
refunding: 0,
wait_use: 0,
waitrate: 0
};
}
},
/**
* 获取订单数量
*/
getOrderNum() {
this.$api.sendRequest({
url: '/api/order/num',
data: {
order_status: 'waitpay,waitsend,waitconfirm,refunding,wait_use,waitrate'
},
success: res => {
if (res.code == 0) {
this.orderNum = res.data;
} else {
this.orderNum = {
waitpay: 0,
waitsend: 0,
waitconfirm: 0,
refunding: 0,
wait_use: 0,
waitrate: 0
};
}
}
});
},
/**
* 跳转
* @param {Object} url
*/
redirect(url) {
if (this.storeToken) {
this.$util.redirectTo(url);
} else {
this.$refs.login.open(url);
}
}
}
};
</script>
<style lang="scss">
.common-wrap {
width: 100%;
box-sizing: border-box;
}
.order-wrap {
.status-wrap {
display: flex;
padding: 30rpx 0;
align-items: center;
justify-content: center;
color: #333;
}
.item-wrap {
flex: 1;
text-align: center;
background: #f6f7f9;
padding: 20rpx 0;
.icon-block {
width: 60rpx;
height: 60rpx;
font-size: 60rpx;
margin: 4rpx auto;
position: relative;
&>image {
position: absolute;
top: 5%;
right: 5%;
width: 90%;
height: 90%;
z-index: 5;
}
.icon-shade {
width: 90%;
height: 90%;
position: absolute;
z-index: 4;
top: 5%;
right: 5%;
background: $base-color;
-webkit-mask: no-repeat center / contain;
}
}
.order-num {
position: absolute;
top: 0;
right: 0;
transform: translate(50%, -50%);
box-sizing: border-box;
color: #ffffff;
line-height: 1.2;
text-align: center;
font-size: 24rpx;
padding: 0 6rpx;
min-width: 30rpx;
border-radius: 16rpx;
height: 30rpx;
display: flex;
align-items: center;
justify-content: center;
}
.title {
font-size: 26rpx;
}
}
}
</style>

View File

@@ -1,365 +0,0 @@
<template>
<view class="diy-merch-list">
<x-skeleton type="list" :loading="loading" :configs="skeletonConfig" v-if="value.ornament.type == 'default'">
<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" @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)" />
</view>
<view class="info-wrap">
<text class="title">{{ item.merch_name }}</text>
<text class="desc">{{ item.desc }}</text>
<view class="read-wrap"></view>
</view>
</view>
</view>
</view>
</x-skeleton>
<view v-else :style="warpCss">
<scroll-view :scroll-x="true" :class="['merch-nav', 'singleSlide']">
<!-- #ifdef MP -->
<view class="uni-scroll-view-content">
<!-- #endif -->
<view class="merch-nav-item graphic" v-for="(item, index) in list" :key="index"
: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="true"
style="max-width: 80rpx; max-height: 80rpx; border-radius: 50rpx;" />
</view>
<text class="graphic-text"
style="font-size: 28rpx; font-weight: normal; color: rgb(48, 49, 51);">
{{ item.merch_name }}
</text>
</view>
<!-- #ifdef MP -->
</view>
<!-- #endif -->
</scroll-view>
</view>
</view>
</template>
<script>
// 文章
import DiyMinx from './minx.js'
export default {
name: 'diy-article',
props: {
value: {
type: Object
}
},
data() {
return {
list: [
/*{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
}*/
],
loading: true,
skeletonConfig: {
gridRows: 1,
gridRowsGap: '40rpx',
headWidth: '160rpx',
headHeight: '160rpx',
textRows: 2
}
};
},
created() {
this.getList();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getList();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;';
}
console.log(obj)
return obj;
},
// 子项样式
itemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color;
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color;
}
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();
}
this.$api.sendRequest({
url: '/merch/api/merch/lists',
data: data,
success: res => {
if (res.code == 0 && res.data) {
let data = res.data;
this.list = data;
}
this.loading = false;
}
});
},
toDetail(item) {
this.$util.redirectTo('/pages_promotion/merch/detail', {
merch_id: item.merch_id
});
},
imgError(index) {
if (this.list[index]) this.list[index].merch_image = this.$util.getDefaultImage().article;
},
async handlerClick(item) {
await this.__$emitEvent({
eventName: 'merch-list-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.toDetail(item);
}
})
}
}
};
</script>
<style>
/* 单行滑动 */
.merch-nav.singleSlide>>>.uni-scroll-view-content {
display: flex;
}
</style>
<style lang="scss">
.merch-nav {
padding: 16rpx;
box-sizing: border-box;
&.singleSlide {
.merch-nav-item {
flex-shrink: 0;
}
}
&.pageSlide {
position: relative;
.merch-nav-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
}
.merch-nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 14rpx 0;
box-sizing: border-box;
.graphic-text {
padding-top: 12rpx;
line-height: 1.5;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
&.alone {
padding-top: 0;
}
}
&.text {
.graphic-text {
padding-top: 0;
}
}
.graphic-img {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
font-size: 24rpx;
.tag {
position: absolute;
top: -10rpx;
right: -24rpx;
color: #fff;
border-radius: 24rpx;
border-bottom-left-radius: 0;
transform: scale(0.8);
padding: 8rpx 16rpx;
line-height: 1;
font-size: 24rpx;
}
.icon {
font-size: 50rpx;
color: $color-sub;
}
}
}
}
.merch-wrap {
.list-wrap {
&.style-1 {
.item {
display: flex;
padding: 20rpx;
margin-top: 24rpx;
&:first-of-type {
margin-top: 0;
}
.merch-img {
margin-right: 20rpx;
width: 160rpx;
height: 160rpx;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
image {
width: 100%;
}
}
.info-wrap {
// flex: 1;
// display: flex;
// flex-direction: column;
// justify-content: space-between;
.desc {
color: #888
}
.title {
font-weight: bold;
// margin-bottom: 10rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: 30rpx;
line-height: 1.5;
}
.abstract {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: $font-size-tag;
}
.read-wrap {
display: flex;
color: #999ca7;
justify-content: flex-start;
align-items: center;
margin-top: 10rpx;
line-height: 1;
text {
font-size: $font-size-tag;
}
.iconfont {
font-size: 36rpx;
vertical-align: bottom;
margin-right: 10rpx;
}
.category-icon {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: $base-color;
margin-right: 10rpx;
}
.date {
margin-left: 20rpx;
}
}
}
}
}
}
}
</style>

View File

@@ -1,370 +0,0 @@
<template>
<x-skeleton data-component-name="diy-notes" type="list" :loading="loading" :configs="skeletonConfig">
<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" @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" @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>
<view class="notes-highlights-list" v-if="value.notesLabel == 1 && item.goods_highlights">
<text class="color-base-bg" v-for="(labelItem, labelIndex) in item.label"
:key="labelIndex">{{ labelItem }}</text>
</view>
<view class="notes-intro">
<text class="notes-label color-base-text">#{{ item.note_type == 'goods_item' ? '单品介绍' :
'掌柜说' }}#</text>
{{ item.note_abstract }}
</view>
</view>
<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" />
<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" />
</view>
<view class="notes-item-con">
<view class="notes-info"
v-if="(value.readNum == 1 && item.is_show_read_num == 1) || (value.uploadTime == 1 && item.is_show_release_time == 1)">
<view class="notes-num">
<text v-show="value.uploadTime == 1 && item.is_show_release_time == 1">{{
item.update_time_day }}</text>
</view>
<view class="notes-num">
<text v-show="value.readNum == 1 && item.is_show_read_num == 1">阅读 {{
item.initial_read_num + item.read_num }}</text>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<ns-login ref="login"></ns-login>
</view>
</x-skeleton>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-notes',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
skeletonConfig: {
itemDirection: 'column',
headWidth: '100%',
headHeight: '320rpx',
textRows: 2,
textWidth: ['100%', '80%']
},
dataList: [],
giveLikeFlag: false
};
},
created() {
this.getDataList();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getDataList();
}
},
computed: {
notesItemStyle() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return css;
}
},
methods: {
refresh() {
this.getDataList();
},
getDataList() {
var data = {
num: this.value.count
};
if (this.value.sources == 'diy') {
data.num = 0;
data.note_id_arr = this.value.noteId.toString();
}
this.$api.sendRequest({
url: '/notes/api/notes/lists',
data: data,
success: res => {
var data = res.data;
this.dataList = [];
if (data) {
for (var i = 0; i < data.length; i++) {
var item = {};
item = data[i];
if (data[i].cover_type == 1) {
item.img = data[i].cover_img.split(',');
} else {
item.img = data[i].cover_img;
}
if (data[i].upload_time) {
item.update_time_day = this.$util.timeStampTurnTime(data[i].upload_time)
.split(' ')[0];
} else {
item.update_time_day = this.$util.timeStampTurnTime(data[i].create_time)
.split(' ')[0];
}
item.label = data[i].goods_highlights.split(',');
this.dataList.push(item);
}
}
this.loading = false;
}
});
},
toMore() {
this.$util.redirectTo('/pages_tool/store_notes/note_list');
},
toDetail(id) {
this.$util.redirectTo('/pages_tool/store_notes/note_detail', {
note_id: id
});
},
/* 点赞 */
giveLike(noteId, index) {
if (!this.storeToken) {
this.$refs.login.open(this.$util.INDEX_PAGE_URL);
return;
}
if (this.giveLikeFlag) return false;
this.giveLikeFlag = true;
var url = this.dataList[index].is_dianzan == 1 ? '/notes/api/record/delete' : '/notes/api/record/add';
this.$api.sendRequest({
url: url,
data: {
note_id: noteId
},
success: res => {
this.giveLikeFlag = false;
if (res.code == 0 && res.data > 0) {
if (this.noteType != 'goods_item')
this.dataList[index].dianzan_num = this.dataList[index].is_dianzan == 1 ? this.dataList[index].dianzan_num - 1 : this.dataList[index].dianzan_num + 1;
else {
this.dataList[index].dianzan_num = this.dataList[index].is_dianzan == 1 ? this.dataList[index].dianzan_num - 1 : this.dataList[index].dianzan_num + 1;
}
this.dataList[index].is_dianzan = this.dataList[index].is_dianzan == 1 ? 0 : 1;
} else {
this.$util.showToast({
title: res.message
});
}
}
});
},
imageError(index) {
this.dataList[index].img = this.$util.getDefaultImage().goods;
this.$forceUpdate();
},
async handlerClick(item) {
await this.__$emitEvent({
eventName: 'notes-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.toDetail(item.note_id);
}
})
}
}
};
</script>
<style lang="scss">
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
touch-action: none;
}
.diy-notes {
width: 100%;
box-sizing: border-box;
}
.diy-notes-top {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
.notes-title {
width: 70%;
font-size: 28rpx;
font-weight: 600;
}
.notes-more {
font-size: $font-size-tag;
color: #858585;
}
.notes-more::after {
font-family: 'iconfont';
content: '\e6a3';
font-size: $font-size-tag;
line-height: 1;
position: relative;
margin-left: 4rpx;
}
}
.diy-notes-box {
width: 100%;
padding: 30rpx 0 20rpx;
}
.notes-box-item {
width: calc(100% - 8rpx);
margin: 0 auto;
height: 100%;
margin-bottom: 30rpx;
border-radius: 10rpx;
overflow: hidden;
-moz-box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.02);
-webkit-box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.02);
box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.02);
.notes-item {
width: 100%;
height: 100%;
padding: 20rpx;
box-sizing: border-box;
}
.notes-img-wrap {
position: relative;
height: 300rpx;
.notes-item-image {
width: 100%;
height: 300rpx;
object-fit: cover;
}
.notes-label {
display: inline-block;
position: absolute;
left: 20rpx;
bottom: 20rpx;
max-width: calc(100vh - 40rpx);
background-color: #ffffff;
line-height: 36rpx;
padding: 0 10rpx 0 4rpx;
}
}
.notes-img-wrap-list {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
height: auto;
image {
width: calc((100% - 40rpx) / 3);
height: 210rpx;
margin-top: 20rpx;
&:nth-child(-n + 3) {
margin-top: 0;
}
}
&:after {
content: '';
width: calc((100% - 40rpx) / 3);
}
}
.notes-item-con {
.notes-title {
font-size: 30rpx;
font-weight: 600;
line-height: 44rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.notes-highlights-list {
text {
display: inline-block;
color: #ffffff;
font-size: 24rpx;
line-height: 36rpx;
padding: 0 10rpx;
border-radius: 4rpx;
margin: 0 5rpx;
}
}
.notes-intro {
margin: 4rpx 0 8rpx;
line-height: 40rpx;
overflow: hidden;
text {
float: left;
margin-right: 16rpx;
}
}
.notes-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20rpx;
.notes-num {
>text {
display: flex;
align-items: center;
font-size: $font-size-tag;
color: #969799;
text.iconfont {
font-size: 26rpx;
margin-right: 6rpx;
}
}
}
}
}
}
</style>

View File

@@ -1,309 +0,0 @@
<template>
<view data-component-name="diy-notice" class="diy-notice">
<view :class="['notice', value.contentStyle]" :style="noticeWrapCss">
<image v-if="value.iconType == 'img'" class="notice-img" :src="$util.img(value.imageUrl)"
mode="heightFix" />
<diy-icon v-if="value.iconType == 'icon'" :icon="value.icon" :value="value.style ? value.style : 'null'"
:style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx', width: '100%', height: '100%' }"></diy-icon>
<view class="notice-xian"></view>
<view class="main-wrap">
<!-- 横向滚动 -->
<view class="horizontal-wrap" v-if="value.scrollWay == 'horizontal'">
<view class="marquee-wrap">
<view class="marquee" :style="marqueeStyle">
<text v-for="(item, index) in list" :key="index"
:style="{ color: value.textColor, fontSize: value.fontSize * 2 + 'rpx', fontWeight: value.fontWeight }">{{
item.title }}</text>
</view>
<view class="marquee" :style="marqueeAgainStyle">
<text v-for="(item, index) in list" :key="index"
:style="{ color: value.textColor, fontSize: value.fontSize * 2 + 'rpx', fontWeight: value.fontWeight }">{{
item.title }}</text>
</view>
</view>
</view>
<!-- 上下滚动 -->
<template v-if="value.scrollWay == 'upDown'">
<swiper :vertical="true" :duration="500" autoplay="true" circular="true">
<swiper-item v-for="(item, index) in list" :key="index" @touchmove.prevent.stop>
<text class="beyond-hiding using-hidden"
:style="{ color: value.textColor, fontSize: value.fontSize * 2 + 'rpx', fontWeight: value.fontWeight }">
{{ item.title }}
</text>
</swiper-item>
</swiper>
</template>
</view>
</view>
<view @touchmove.prevent.stop>
<uni-popup ref="noticePopup" type="center">
<view class="notice-popup">
<view class="head-wrap" @click="closeNoticePopup">
<text>公告</text>
<text class="iconfont icon-close"></text>
</view>
<view class="content-wrap">{{ notice }}</view>
<button type="primary" @click="closeNoticePopup">我知道了</button>
</view>
</uni-popup>
</view>
</view>
</template>
<script>
// 公告展示
import DiyMinx from './minx.js'
export default {
name: 'diy-notice',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
list: [],
notice: '', // 当前点击的弹框内容
marqueeWrapWidth: 0, // 容器宽度
marqueeWidth: 0, // 公告内容累加宽度
marqueeStyle: '', // 横向滚动样式
marqueeAgainStyle: '', // 横向滚动复制样式
time: 0, // 滚动完成时间
delayTime: 1000 // 动画延迟时间
};
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
if (this.value.sources == 'initial') this.getData();
}
},
created() { },
mounted() {
// 数据源:公告系统
if (this.value.sources == 'initial') {
this.getData();
} else {
this.list = this.value.list;
this.bindCrossSlipEvent();
}
},
computed: {
noticeWrapCss: function () {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
}
},
methods: {
getData() {
var data = {
page_size: 0
};
if (this.value.sources == 'initial') {
data.page_size = this.value.count;
}
if (this.value.noticeIds.length) {
data.id_arr = this.value.noticeIds.toString();
data.page_size = 0;
}
this.$api.sendRequest({
url: '/api/notice/page',
data: data,
success: res => {
if (res.code == 0 && res.data) {
this.list = res.data.list;
this.bindCrossSlipEvent();
}
}
});
},
toLink(item) {
if (this.value.sources == 'initial') {
this.$util.redirectTo('/pages_tool/notice/detail', {
notice_id: item.id
});
} else if (!item) {
this.$util.redirectTo('/pages_tool/notice/list');
} else if (Object.keys(item.link).length > 1) {
this.$util.diyRedirectTo(item.link);
} else {
// 如果不设置跳转链接,则点击弹框展示
this.notice = item.title;
this.$refs.noticePopup.open();
}
},
closeNoticePopup() {
this.$refs.noticePopup.close();
},
// 绑定横向滚动事件
bindCrossSlipEvent() {
if (this.value.scrollWay == 'horizontal') {
setTimeout(() => {
this.$nextTick(() => {
uni.createSelectorQuery()
.in(this)
.select('.marquee-wrap')
.boundingClientRect(res => {
this.marqueeWrapWidth = res.width;
const query = uni.createSelectorQuery().in(this);
query
.select('.marquee')
.boundingClientRect(data => {
this.marqueeWidth = data.width + 30; // 30px是间距
this.time = Math.ceil(this.marqueeWidth * 10);
if (this.marqueeWrapWidth > this.marqueeWidth) {
this.marqueeStyle = `animation: none;`;
this.marqueeAgainStyle = 'display:none;';
} else {
this.marqueeStyle = `
width: ${this.marqueeWidth}px;
animation-duration: ${this.time}ms;
animation-delay: ${this.delayTime}ms;
`;
this.marqueeAgainStyle = `
width: ${this.marqueeWidth}px;
left: ${this.marqueeWidth}px;
animation-duration: ${this.time}ms;
animation-delay: ${this.delayTime}ms;
`;
}
})
.exec();
})
.exec();
});
});
}
}
}
};
</script>
<style lang="scss">
.notice {
height: 80rpx;
position: relative;
display: flex;
align-items: center;
overflow: hidden;
padding: 20rpx 0 20rpx 20rpx;
font-size: 70rpx;
box-sizing: border-box;
.notice-img {
width: 44rpx;
height: 80rpx;
}
.notice-xian {
width: 1rpx;
height: 26rpx;
background-color: #e4e4e4;
margin: 0 22rpx;
}
}
.main-wrap {
display: inline-block;
width: calc(100% - 115rpx);
position: relative;
}
swiper {
height: 50rpx;
}
.beyond-hiding {
display: inline-block;
width: 100%;
white-space: nowrap;
}
.notice-popup {
padding: 0 30rpx 40rpx;
background-color: #fff;
.head-wrap {
font-size: $font-size-toolbar;
line-height: 100rpx;
height: 100rpx;
display: block;
text-align: center;
position: relative;
border-bottom: 2rpx solid $color-line;
margin-bottom: 20rpx;
.iconfont {
position: absolute;
float: right;
right: 0;
font-size: $font-size-toolbar;
}
}
.content-wrap {
max-height: 600rpx;
overflow-y: auto;
}
button {
margin-top: 40rpx;
}
}
.horizontal-wrap {
height: 30px;
line-height: 30px;
position: relative;
overflow: hidden;
width: 100%;
}
.marquee-wrap {
display: inline-block;
width: 100%;
height: 100%;
vertical-align: middle;
overflow: hidden;
box-sizing: border-box;
position: relative;
}
.marquee {
display: flex;
position: absolute;
white-space: nowrap;
animation: marquee 0s 0s linear infinite;
text {
margin-left: 40rpx;
&:first-child {
margin-left: 0;
}
}
}
@keyframes marquee {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
</style>

View File

@@ -1,92 +0,0 @@
<template>
<view data-component-name="diy-picture" class="diy-picture" :style="style">
<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" @click="handlerClick(item)" @tap="handlerClick(item)"></image>
<image mode="widthFix" style="width: 100%;height:auto" :src="$util.img(item.imageUrl)" v-else
@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>
</view> -->
</view>
</view>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-picture',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
};
},
created() {
// this.getDataList();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
// this.getDataList();
}
},
mixins: [DiyMinx],
computed: {
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return css;
}
},
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) {
this.$refs.login.open(link.wap_url);
return;
}
}
this.$util.diyRedirectTo(link);
},
async handlerClick(item) {
await this.__$emitEvent({
eventName: 'picture-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
if (item.link.wap_url) {
this.redirectTo(item.link);
} else {
this.previewImg(item.imageUrl);
}
}
})
}
}
};
</script>
<style lang="scss"></style>

View File

@@ -1,590 +0,0 @@
<template>
<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" @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)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl || value.btnStyle.control">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="tag-wrap" v-if="value.groupStyle.control || value.saleStyle.control">
<view v-if="value.groupStyle.control"
:style="{ color: value.theme == 'diy' ? value.groupStyle.bgColor : '', borderColor: value.theme == 'diy' ? value.groupStyle.bgColor : '' }">
<text class="iconfont icon-yonghu3"
:style="{ backgroundColor: value.theme == 'diy' ? value.groupStyle.bgColor : '' }"></text>
<text>{{ item.pintuan_num }}人团</text>
</view>
<view v-if="value.saleStyle.control"
:style="{ color: value.theme == 'diy' ? value.saleStyle.color : '', borderColor: value.theme == 'diy' ? value.saleStyle.color : '' }">
<text>已拼{{ item.order_num }}</text>
</view>
</view>
<view class="price-wrap">
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.pintuan_price.split(".")[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
"." + item.pintuan_price.split(".")[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl"
:style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">
¥{{ item.price }}
</view>
<button v-if="value.btnStyle.control" :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'
}">
<text class="text">{{ value.btnStyle.text }}</text>
<text class="fan" v-if="item.reward_type == 4">{{ item.reward_type_num }}积分</text>
<text class="fan" v-if="item.reward_type == 1 || item.reward_type == 2">{{
item.reward_type_num }}</text>
<text class="fan" v-if="item.reward_type == 3">返优惠券</text>
</button>
</view>
</view>
</view>
</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" @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)" />
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view v-if="value.groupStyle.control" class="num">
<text class="content-tuan-box"
:style="{ color: value.theme == 'diy' ? value.groupStyle.color : '', backgroundColor: value.theme == 'diy' ? value.groupStyle.bgColor : '' }">
{{ item.pintuan_num }}人团
</text>
<text class="content-tuan-price"
:style="{ color: value.theme == 'diy' ? value.groupStyle.bgColor : '' }"
v-if="item.reward_type == 4">
{{ item.reward_type_num }}积分
</text>
<text class="content-tuan-price"
:style="{ color: value.theme == 'diy' ? value.groupStyle.bgColor : '' }"
v-if="item.reward_type == 1 || item.reward_type == 2">
{{ item.reward_type_num }}
</text>
<text class="content-tuan-price"
:style="{ color: value.theme == 'diy' ? value.groupStyle.bgColor : '' }"
v-if="item.reward_type == 3">返优惠券</text>
</view>
<view class="price-wrap" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.pintuan_price.split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
"." + item.pintuan_price.split('.')[1] }}</text>
</view>
</view>
</view>
</scroll-view>
<swiper v-if="value.slideMode == 'slide'" :autoplay="false" class="swiper"
:style="{ height: swiperHeight }">
<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"
@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)" />
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view v-if="value.groupStyle.control" class="num">
<text class="content-tuan-box"
:style="{ color: value.theme == 'diy' ? value.groupStyle.color : '', backgroundColor: value.theme == 'diy' ? value.groupStyle.bgColor : '' }">
{{ item.pintuan_num }}人团
</text>
<text class="content-tuan-price"
:style="{ color: value.theme == 'diy' ? value.groupStyle.bgColor : '' }"
v-if="item.reward_type == 4">
{{ item.reward_type_num }}积分
</text>
<text class="content-tuan-price"
:style="{ color: value.theme == 'diy' ? value.groupStyle.bgColor : '' }"
v-if="item.reward_type == 1 || item.reward_type == 2">
{{ item.reward_type_num }}
</text>
<text class="content-tuan-price"
:style="{ color: value.theme == 'diy' ? value.groupStyle.bgColor : '' }"
v-if="item.reward_type == 3">
返优惠券
</text>
</view>
<view class="price-wrap" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
item.pintuan_price.split('.')[1] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{
"." + item.pintuan_price.split('.')[1] }}</text>
</view>
</view>
</view>
</swiper-item>
</swiper>
</template>
</view>
</x-skeleton>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-pinfan',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
loading: true,
skeletonType: '',
skeletonConfig: {},
list: [],
page: 1
};
},
created() {
this.initSkeleton();
this.getData();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getData();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color + ';';
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color + ';';
}
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(this.value.goodsMarginNum * 2);
else
width = [screenWidth - (this.rpxUpPx(20) * 2) - (this.rpxUpPx(200) * 3) - (this.rpxUpPx(this.value
.margin.both * 2) * 2)] / 6;
obj += 'margin-left:' + width + "px;";
obj += 'margin-right:' + width + "px;";
}
return obj;
},
swiperHeight() {
if (this.value.nameLineMode == 'multiple')
return this.value.ornament.type == 'shadow' ? '444rpx' : '432rpx';
return this.value.ornament.type == 'shadow' ? '404rpx' : '396rpx';
}
},
methods: {
initSkeleton() {
if (this.value.template == 'row1-of1') {
// 单列 风格
this.skeletonType = 'list';
this.skeletonConfig = {
textRows: 3
};
} else if (this.value.template == 'horizontal-slide') {
// 横向滑动 风格
this.skeletonType = 'waterfall';
this.skeletonConfig = {
gridRows: 1,
gridColumns: 3,
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '80%']
};
}
},
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = screenWidth * parseInt(res) / 750;
return Math.floor(data);
},
getData() {
var data = {
num: this.value.count
};
if (this.value.sources == 'diy') {
data.num = 0;
data.goods_id_arr = this.value.goodsId.toString();
}
this.$api.sendRequest({
url: '/pinfan/api/goods/lists',
data: data,
success: res => {
if (res.code == 0 && res.data) {
this.list = res.data;
// 切屏滚动,每页显示固定数量
if (this.value.template == 'horizontal-slide' && this.value.slideMode == 'slide') {
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
}
this.loading = false;
}
});
},
toDetail(e) {
this.$util.redirectTo('/pages_promotion/pinfan/detail', {
pinfan_id: e.pintuan_id
});
},
imageError(index) {
this.list[index].goods_image = this.$util.getDefaultImage().goods;
this.$forceUpdate();
}
}
};
</script>
<style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
touch-action: none;
}
.diy-pinfan {
&.row1-of1 {
.item {
display: flex;
margin-bottom: 20rpx;
padding: 16rpx;
&.shadow {
margin: 8rpx 8rpx 20rpx 8rpx;
}
&:last-child {
margin-bottom: 0;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
image {
width: 200rpx;
}
}
.content {
flex: 1;
margin-left: 20rpx;
position: relative;
display: flex;
justify-content: space-between;
flex-direction: column;
padding: 6rpx 0;
.goods-name {
line-height: 1.3;
}
.tag-wrap {
display: flex;
align-items: center;
margin-top: 4rpx;
>view {
height: 30rpx;
line-height: 30rpx;
border: 2rpx solid $base-color;
border-radius: 6rpx;
margin-right: 10rpx;
font-size: $font-size-activity-tag;
color: $base-color;
.iconfont {
display: inline-block;
width: 30rpx;
height: 30rpx;
font-size: $font-size-activity-tag;
color: #ffffff;
text-align: center;
margin-right: -6rpx;
background: $base-color;
}
text:last-child {
padding: 0 10rpx;
}
}
}
.price-wrap {
display: flex;
align-items: flex-end;
>view:last-of-type {
flex: 1;
}
.discount-price {
white-space: nowrap;
font-weight: bold;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
color: $base-color;
}
}
.original-price {
font-size: $font-size-tag;
color: $color-tip;
text-decoration: line-through;
margin: 0 10rpx 4rpx 10rpx;
}
}
button {
bottom: 10rpx;
height: 90rpx;
line-height: 40rpx;
padding: 0 16rpx;
margin: 0;
text-align: center;
background-color: $base-color;
color: #ffffff;
.text {
display: block;
margin-top: 6rpx;
font-size: $font-size-tag;
}
.fan {
font-size: $font-size-activity-tag;
}
}
}
}
}
&.horizontal-slide {
display: flex;
justify-content: space-around;
.scroll {
width: calc(100% - 40rpx);
padding: 20rpx;
line-height: 1;
white-space: nowrap;
.item.shadow {
margin-bottom: 8rpx;
}
}
.flex-between {
justify-content: space-between;
}
.item {
display: inline-block;
width: 200rpx;
overflow: hidden;
box-sizing: border-box;
&:nth-child(3n+3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
position: relative;
overflow: hidden;
margin: 0 auto;
>image {
width: 200rpx;
}
}
.content {
padding: 10rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
&.multi-content {
height: 188rpx;
box-sizing: border-box;
}
.goods-name {
line-height: 1.3;
&.multi-hidden {
white-space: break-spaces;
}
}
.num {
margin-top: auto;
font-size: $font-size-activity-tag;
.content-tuan-box {
border-radius: 4rpx;
color: #ffffff;
background-color: $base-color;
padding: 6rpx;
}
.content-tuan-price {
border-radius: 4rpx;
padding: 4rpx 6rpx;
border: 2rpx solid $base-color;
color: $base-color;
margin-left: -2rpx;
}
}
.price-wrap {
white-space: nowrap;
margin-top: 10rpx;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
height: 32rpx;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
color: $base-color;
}
}
}
}
.swiper {
width: 100%;
white-space: nowrap;
padding: 20rpx;
box-sizing: border-box;
.swiper-item {
display: flex;
align-items: center;
}
.item {
width: 200rpx;
}
}
}
}
</style>

View File

@@ -1,812 +0,0 @@
<template>
<x-skeleton data-component-name="diy-pintuan" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
<view class="diy-pintuan" :class="[value.template, value.style]" :style="warpCss">
<view v-if="value.titleStyle.isShow && list && list.length"
:class="[value.titleStyle.style, 'pintuan-head']" :style="{
backgroundImage:
'url(' + $util.img(value.titleStyle.backgroundImage) + '), linear-gradient(to right,' + value.titleStyle.bgColorStart + ',' + value.titleStyle.bgColorEnd + ')'
}">
<view v-if="value.titleStyle.leftStyle == 'text'" class="left-text"
: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" />
<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)" />
</block>
<block v-else>
<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 }">
<text>{{ value.titleStyle.virtualNum || headData.pintuan_count }}</text>
<text>{{ value.titleStyle.style == 'style-2' ? '人参与' : '人拼团成功' }}</text>
</view>
</view>
<view class="head-right"
:style="{ fontSize: value.titleStyle.moreFontSize * 2 + 'rpx', color: value.titleStyle.moreColor }"
@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" @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)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl || value.btnStyle.control">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="tag-wrap" v-if="value.groupStyle.control || value.saleStyle.control">
<view v-if="value.groupStyle.control" :style="{
color: value.theme == 'diy' ? value.groupStyle.bgColorStart : '',
borderColor: value.theme == 'diy' ? value.groupStyle.bgColorStart : ''
}">
<text class="iconfont icon-yonghu3"
:style="{ backgroundColor: value.theme == 'diy' ? value.groupStyle.bgColorStart : '' }"></text>
<text>{{ item.pintuan_num }}人团</text>
</view>
<view v-if="value.saleStyle.control"
:style="{ color: value.theme == 'diy' ? value.saleStyle.color : '', borderColor: value.theme == 'diy' ? value.saleStyle.color : '' }">
<text>已拼{{ item.order_num }}</text>
</view>
</view>
<view class="bottom-wrap">
<view class="price-wrap">
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ item.pintuan_price.split('.')[0] }}
</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ '.' + item.pintuan_price.split('.')[1] }}
</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl"
:style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">
¥{{ item.price }}
</view>
</view>
<button v-if="value.btnStyle.control" :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'
}">
{{ value.btnStyle.text }}
</button>
</view>
</view>
</view>
</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" @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)" />
<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 + ')' : ''
}">
{{ item.pintuan_num }}人团
</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
<view
v-if="value.goodsNameStyle.control && (value.style == 'style-1' || value.style == 'style-3')"
class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="price-wrap" v-if="value.priceStyle.mainControl && value.style != 'style-3'">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ item.pintuan_price.split('.')[0] }}
</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ '.' + item.pintuan_price.split('.')[1] }}
</text>
</view>
<view class="other-info-wrap" v-if="value.style == 'style-3'">
<view class="price-wrap" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ item.pintuan_price.split('.')[0] }}
</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ '.' + item.pintuan_price.split('.')[1] }}
</text>
</view>
<view class="sale-action">去参团</view>
</view>
<view class="sale-num" v-if="value.style == 'style-2'">已拼{{ item.sale_num }}</view>
</view>
</view>
</scroll-view>
<swiper v-if="value.slideMode == 'slide'" :autoplay="false" class="swiper"
:style="{ height: swiperHeight }">
<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"
@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)" />
<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 + ')' : ''
}">
{{ item.pintuan_num }}人团
</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
<view v-if="value.goodsNameStyle.control && value.style != 'style-2'" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="price-wrap" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ item.pintuan_price.split('.')[0] }}
</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ '.' + item.pintuan_price.split('.')[1] }}
</text>
</view>
<view class="sale-num" v-if="value.style == 'style-2'">已拼{{ item.sale_num }}</view>
</view>
</view>
</swiper-item>
</swiper>
</template>
</view>
</x-skeleton>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-pintuan',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
loading: true,
skeletonType: '',
skeletonConfig: {},
list: [],
page: 1,
scrollWidth: 0,
headData: []
};
},
created() {
this.initSkeleton();
this.getData();
this.getHeadData();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getData();
this.getHeadData();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color + ';';
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color + ';';
}
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(this
.value.goodsMarginNum * 2);
else if (this.value.template == 'horizontal-slide' && this.value.style == 'style-2')
width = [screenWidth - this.rpxUpPx(212) * 3 - this.rpxUpPx(this.value.margin.both * 2) * 2] / 6;
else width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this.rpxUpPx(this.value
.margin.both * 2) * 2] / 6;
obj += 'margin-left:' + width + 'px;';
obj += 'margin-right:' + width + 'px;';
}
return obj;
},
swiperHeight() {
if (this.value.template == 'horizontal-slide' && this.value.style == 'style-2') {
if (this.value.nameLineMode == 'multiple') {
if (this.value.ornament.type == 'shadow') return '360rpx';
else return '342rpx';
}
if (this.value.ornament.type == 'shadow') return '324rpx';
else return '308rpx';
} else {
if (this.value.nameLineMode == 'multiple') {
if (this.value.ornament.type == 'shadow') return '400rpx';
else return '382rpx';
}
if (this.value.ornament.type == 'shadow') return '364rpx';
else return '348rpx';
}
}
},
methods: {
initSkeleton() {
if (this.value.template == 'row1-of1') {
// 单列 风格
this.skeletonType = 'list';
this.skeletonConfig = {
textRows: 3
};
} else if (this.value.template == 'horizontal-slide') {
// 横向滑动 风格
this.skeletonType = 'waterfall';
this.skeletonConfig = {
gridRows: 1,
gridColumns: 3,
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '80%']
};
}
},
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
getHeadData() {
var data = {
num: 3
};
this.$api.sendRequest({
url: '/pintuan/api/order/pintuanmember',
data: data,
success: res => {
if (res.code == 0 && res.data) {
this.headData = res.data;
}
}
});
},
getData() {
var data = {
num: this.value.count
};
if (this.value.sources == 'diy') {
data.num = 6;
data.goods_id_arr = this.value.goodsId.toString();
}
this.$api.sendRequest({
url: '/pintuan/api/goods/lists',
data: data,
success: res => {
if (res.code == 0 && res.data) {
this.list = res.data;
// 切屏滚动,每页显示固定数量
if (this.value.template == 'horizontal-slide' && this.value.slideMode == 'slide') {
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
}
this.loading = false;
}
});
},
toDetail(e) {
this.$util.redirectTo('/pages_promotion/pintuan/detail', {
pintuan_id: e.pintuan_id
});
},
imageError(index) {
if (this.list[index]) this.list[index].goods_image = this.$util.getDefaultImage().goods;
this.$forceUpdate();
},
headImageError(index) {
this.headData.member_list[index].member_img = this.$util.img('public/static/img/default_img/square.png');
this.$forceUpdate();
}
}
};
</script>
<style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
touch-action: none;
}
.diy-pintuan {
overflow: hidden;
.pintuan-head {
padding: 0 24rpx;
display: flex;
justify-content: space-between;
align-items: center;
height: 88rpx;
box-sizing: border-box;
background-repeat: no-repeat;
background-size: cover;
margin-bottom: 20rpx;
border-radius: 18rpx 18rpx 0 0;
.left-img {
width: 174rpx;
height: 40rpx;
}
.head-content {
display: flex;
align-items: center;
margin-left: 50rpx;
margin-right: auto;
color: #fff;
.img-warp {
position: relative;
margin-right: 8rpx;
line-height: 1;
image {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 2rpx solid #ff3d3d;
margin-left: -14rpx;
}
&:after {
content: '';
width: 2rpx;
height: 28rpx;
background-color: #fff;
position: absolute;
left: -32rpx;
top: 50%;
transform: translateY(-50%);
}
}
}
.head-right {
display: flex;
align-items: center;
font-size: $font-size-sub;
color: #fff;
line-height: 1;
}
&.style-2 {
.head-right {
display: flex;
align-items: center;
justify-content: center;
height: 36rpx;
background: linear-gradient(270deg, #ffbd5b 0%, #fd882e 100%);
border-radius: 24rpx;
padding: 2rpx;
text:nth-child(1) {
position: relative;
left: 6rpx;
transform: scale(0.9);
}
text:nth-child(2) {
padding: 6rpx 4rpx 4rpx;
background-color: #fff;
color: #ffbd5b;
border-radius: 50%;
transform: scale(0.6);
font-weight: bold;
line-height: 1;
}
}
}
}
&.row1-of1 {
.item {
display: flex;
margin-bottom: 20rpx;
padding: 16rpx;
&.shadow {
margin: 8rpx 8rpx 20rpx 8rpx;
}
&:last-child {
margin-bottom: 0;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
image {
width: 200rpx;
}
}
.content {
flex: 1;
margin-left: 20rpx;
position: relative;
display: flex;
justify-content: space-between;
flex-direction: column;
padding: 6rpx 0;
.tag-wrap {
display: flex;
align-items: center;
>view {
height: 30rpx;
line-height: 30rpx;
border: 2rpx solid $base-color;
border-radius: 6rpx;
margin-right: 10rpx;
font-size: $font-size-activity-tag;
color: $base-color;
.iconfont {
display: inline-block;
width: 30rpx;
height: 30rpx;
font-size: $font-size-activity-tag;
color: #ffffff;
text-align: center;
margin-right: -6rpx;
background: $base-color;
}
text:last-child {
padding: 0 10rpx;
}
}
}
.goods-name {
line-height: 1.3;
}
.bottom-wrap {
display: flex;
align-items: center;
justify-content: space-between;
}
.price-wrap {
overflow: hidden;
width: 260rpx;
display: flex;
align-items: flex-end;
flex-wrap: wrap;
>view:last-of-type {
flex: 1;
}
.discount-price {
white-space: nowrap;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
color: var(--price-color);
}
.price {
font-size: $font-size-toolbar;
color: var(--price-color);
}
}
.original-price {
font-size: $font-size-tag;
color: $color-tip;
line-height: 1;
text-decoration: line-through;
margin: 0 10rpx;
}
}
button {
margin-right: 20rpx;
min-width: 112rpx;
height: 52rpx;
line-height: 52rpx;
padding: 0 20rpx;
margin: 0;
color: var(--btn-text-color);
background-color: $base-color;
color: #fff;
font-size: 24rpx;
}
}
}
}
&.horizontal-slide {
display: flex;
flex-direction: column;
.flex-between {
justify-content: space-between;
}
.scroll {
width: calc(100% - 40rpx);
padding: 20rpx;
line-height: 1;
white-space: nowrap;
.item.shadow {
margin-bottom: 4rpx;
}
}
.item {
display: inline-block;
width: 200rpx;
overflow: hidden;
box-sizing: border-box;
flex-shrink: 0;
&:nth-child(3n + 3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
position: relative;
overflow: hidden;
margin: 0 auto;
>image {
width: 200rpx;
}
.num {
width: 80rpx;
position: absolute;
bottom: 0;
font-size: $font-size-tag;
line-height: 1;
color: #ffffff;
text-align: center;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
padding: 10rpx;
transform: translate(50%);
background: $base-color;
}
}
.content {
padding: 10rpx 10rpx 16rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
&.multi-content {
height: 142rpx;
box-sizing: border-box;
}
.goods-name {
line-height: 1.3;
font-size: $font-size-base;
&.multi-hidden {
white-space: break-spaces;
}
}
.price-wrap {
line-height: 1;
white-space: nowrap;
margin-top: 10rpx;
font-weight: bold;
.unit {
font-size: $font-size-tag;
height: 32rpx;
color: var(--price-color);
}
.price {
font-size: $font-size-toolbar;
color: var(--price-color);
}
}
}
}
.swiper {
padding: 20rpx;
width: 100%;
white-space: nowrap;
box-sizing: border-box;
.swiper-item {
display: flex;
align-items: center;
}
.item {
width: 200rpx;
box-sizing: border-box;
}
}
&.style-2 {
.item {
width: 212rpx;
&:nth-child(3n + 3) {
width: 210rpx;
}
.img-wrap {
width: 212rpx;
height: 212rpx;
>image {
width: 212rpx !important;
}
}
.price-wrap {
text-align: center;
margin-top: 0 !important;
margin-bottom: 10rpx;
}
.sale-num {
text-align: center;
color: #666666;
line-height: 1;
}
}
.scroll {
padding: 0;
width: auto;
}
.swiper {
padding: 0;
}
}
&.style-3 {
.other-info-wrap {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.sale-action {
font-size: $font-size-tag;
width: 94rpx;
height: 44rpx;
background: linear-gradient(131deg, #3edb73 0%, #1db576 100%);
border-radius: 8rpx;
color: #fff;
text-align: center;
line-height: 44rpx;
transform: scale(0.9);
}
}
}
}
</style>

View File

@@ -1,469 +0,0 @@
<template>
<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" @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)" />
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.btnStyle.control">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ showPrice(item).split('.')[0] }}
</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ '.' + showPrice(item).split('.')[1] }}
</text>
</view>
<button v-if="value.btnStyle.control" :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'
}">
{{ value.btnStyle.text }}
</button>
</view>
</view>
</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" @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)" />
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ showPrice(item).split('.')[0] }}
</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ '.' + showPrice(item).split('.')[1] }}
</text>
</view>
</view>
</view>
</scroll-view>
<swiper v-if="value.slideMode == 'slide'" :autoplay="false" class="swiper"
:style="{ height: swiperHeight }">
<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"
@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)" />
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ showPrice(item).split('.')[0] }}
</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">
{{ '.' + showPrice(item).split('.')[1] }}
</text>
</view>
</view>
</view>
</swiper-item>
</swiper>
</template>
</view>
</x-skeleton>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-presale',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
skeletonType: '',
skeletonConfig: {},
list: [],
page: 1
};
},
created() {
this.initSkeleton();
this.getData();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getData();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color + ';';
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color + ';';
}
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(this
.value.goodsMarginNum * 2);
else width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this.rpxUpPx(this.value
.margin.both * 2) * 2] / 6;
obj += 'margin-right:' + width + 'px;';
obj += 'margin-left:' + width + 'px;';
}
return obj;
},
swiperHeight() {
if (this.value.nameLineMode == 'multiple') {
return this.value.ornament.type == 'shadow' ? '390rpx' : '382rpx';
}
return this.value.ornament.type == 'shadow' ? '364rpx' : '348rpx';
}
},
methods: {
initSkeleton() {
if (this.value.template == 'row1-of1') {
// 单列 风格
this.skeletonType = 'list';
this.skeletonConfig = {
textRows: 2
};
} else if (this.value.template == 'horizontal-slide') {
// 横向滑动 风格
this.skeletonType = 'waterfall';
this.skeletonConfig = {
gridRows: 1,
gridColumns: 3,
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '80%']
};
}
},
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
getData() {
var data = {
num: this.value.count
};
if (this.value.sources == 'diy') {
data.num = 0;
data.goods_id_arr = this.value.goodsId.toString();
}
this.$api.sendRequest({
url: '/presale/api/goods/lists',
data: data,
success: res => {
if (res.code == 0 && res.data) {
this.list = res.data;
// 切屏滚动,每页显示固定数量
if (this.value.template == 'horizontal-slide' && this.value.slideMode == 'slide') {
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
}
this.loading = false;
}
});
},
toDetail(e) {
this.$util.redirectTo('/pages_promotion/presale/detail', {
id: e.presale_id
});
},
imageError(index) {
this.list[index].goods_image = this.$util.getDefaultImage().goods;
this.$forceUpdate();
},
showPrice(data) {
let price = data.price;
if (data.member_price && parseFloat(data.member_price) < parseFloat(price)) price = data.member_price;
return price;
},
async handlerClick(item) {
await this.__$emitEvent({
eventName: 'presale-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.toDetail(item);
}
})
}
}
};
</script>
<style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
touch-action: none;
}
.diy-presale {
&.row1-of1 {
.item {
display: flex;
margin-bottom: 20rpx;
padding: 16rpx;
&.shadow {
margin: 8rpx 8rpx 20rpx 8rpx;
}
&:last-child {
margin-bottom: 0;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
>image {
width: 200rpx;
}
}
.content {
flex: 1;
margin-left: 20rpx;
position: relative;
padding: 6rpx 0;
.goods-name {
line-height: 1.5;
}
.discount-price {
white-space: nowrap;
font-weight: bold;
position: absolute;
bottom: 10rpx;
left: 0;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
color: $base-color;
}
}
button {
position: absolute;
bottom: 10rpx;
right: 20rpx;
margin: 0;
padding: 0 20rpx;
background-color: $base-color;
color: #fff;
min-width: 112rpx;
height: 52rpx;
line-height: 52rpx;
font-size: $font-size-tag;
}
}
}
}
&.horizontal-slide {
.scroll {
width: calc(100% - 40rpx);
padding: 20rpx;
line-height: 1;
white-space: nowrap;
.item.shadow {
margin-bottom: 8rpx;
}
}
.flex-between {
justify-content: space-between;
}
.item {
display: inline-block;
width: 200rpx;
overflow: hidden;
box-sizing: border-box;
&:nth-child(3n + 3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
margin: 0 auto;
>image {
width: 200rpx;
}
}
.content {
padding: 10rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
&.multi-content {
height: 134rpx;
box-sizing: border-box;
}
.goods-name {
line-height: 1.3;
&.multi-hidden {
white-space: break-spaces;
}
}
.discount-price {
white-space: nowrap;
margin-top: auto;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
color: $base-color;
}
}
}
}
.swiper {
padding: 20rpx;
width: 100%;
white-space: nowrap;
box-sizing: border-box;
.swiper-item {
display: flex;
align-items: center;
}
.item {
width: 200rpx;
}
}
}
}
</style>

View File

@@ -1,128 +0,0 @@
<template>
<view data-component-name="diy-quick-nav" :style="componentStyle">
<scroll-view class="quick-nav" scroll-x="true">
<!-- #ifdef MP -->
<view class="uni-scroll-view-content">
<!-- #endif -->
<view class="quick-nav-item" v-for="(item, index) in value.list" :key="index"
@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="true"></image>
<diy-icon v-if="item.iconType == 'icon'" :icon="item.icon"
:value="item.style ? item.style : null" :style="{ fontSize: '60rpx' }"></diy-icon>
</view>
<text class="quick-text" :style="{ color: item.textColor }">{{ item.title }}</text>
</view>
<!-- #ifdef MP -->
</view>
<!-- #endif -->
</scroll-view>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-quick-nav',
props: {
value: {
type: Object
}
},
data() {
return {};
},
created() { },
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
componentStyle() {
var css = '';
css += 'background-color:' + this.value.componentBgColor + ';';
if (this.value.componentAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
}
css += 'box-shadow:' + (this.value.ornament.type == 'shadow' ? '0 0 10rpx ' + this.value.ornament.color : '') + ';';
css += 'border:' + (this.value.ornament.type == 'stroke' ? '2rpx solid ' + this.value.ornament.color : '') + ';';
return css;
}
},
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);
return;
}
}
this.$util.diyRedirectTo(link);
},
async handlerClick(item) {
await this.__$emitEvent({
eventName: 'quick-nav-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.redirectTo(item.link);
}
})
}
}
};
</script>
<style>
.quick-nav>>>.uni-scroll-view-content {
display: flex;
}
</style>
<style lang="scss">
.quick-nav {
.quick-nav-item {
display: flex;
align-items: center;
padding: 0 18rpx;
box-sizing: border-box;
flex-shrink: 0;
border-radius: 40rpx;
margin-right: 20rpx;
height: 48rpx;
&:first-of-type {
padding-left: 12rpx;
}
&:last-child {
margin-right: 0;
}
.quick-img {
margin-right: 6rpx;
height: 30rpx;
line-height: 1;
image {
width: 30rpx;
height: 30rpx;
}
}
.quick-text {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
font-size: 24rpx;
line-height: 1;
}
}
}
</style>

View File

@@ -1,539 +0,0 @@
<template>
<view data-component-name="diy-rubik-cube">
<!-- 自定义 -->
<view v-if="value.mode == 'custom-rubik-cube'">
<view style="position: relative;"><rich-text :nodes="customHtml"></rich-text></view>
</view>
<view v-else :class="['rubik-cube', value.mode]" :style="rubikCubeWrapCss">
<!-- 1左2右 -->
<template v-if="value.mode == 'row1-lt-of2-rt'">
<view class="template-left">
<view :class="['item', value.mode]" @click="handlerClick(value.list[0].link)"
@tap="handlerClick(value.list[0].link)"
:style="{ marginRight: value.imageGap * 2 + 'rpx', width: list[0].imgWidth, height: list[0].imgHeight + 'px' }">
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
</view>
</view>
<view class="template-right">
<template v-for="(item, index) in list">
<template v-if="index > 0">
<view :key="index" :class="['item', value.mode]" @click="handlerClick(item.link)"
@tap="handlerClick(item.link)"
:style="{ marginBottom: value.imageGap * 2 + 'rpx', width: item.imgWidth, height: item.imgHeight + 'px' }">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
</view>
</template>
</template>
</view>
</template>
<!-- 1左3右 -->
<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' }"
@click="handlerClick(value.list[0].link)" @tap="handlerClick(value.list[0].link)">
<image :src="$util.img(value.list[0].imageUrl)" :mode="list[0].imageMode || 'scaleToFill'"
:style="list[0].pageItemStyle" :show-menu-by-longpress="true" />
</view>
</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' }"
@click="handlerClick(value.list[1].link)" @tap="handlerClick(value.list[1].link)">
<image :src="$util.img(value.list[1].imageUrl)" :mode="list[1].imageMode || 'scaleToFill'"
:style="list[1].pageItemStyle" :show-menu-by-longpress="true" />
</view>
<view class="template-bottom">
<template v-for="(item, index) in list">
<template v-if="index > 1">
<view :key="index" :class="['item', value.mode]" @click="handlerClick(item.link)"
@tap="handlerClick(item.link)" :style="{
marginRight: value.imageGap * 2 + 'rpx',
width: item.imgWidth,
height: item.imgHeight + 'px'
}">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
</view>
</template>
</template>
</view>
</view>
</template>
<template v-else>
<view :class="['item', value.mode]" v-for="(item, index) in list" :key="index"
@click="handlerClick(item.link)" @tap="handlerClick(item.link)"
:style="{ marginRight: value.imageGap * 2 + 'rpx', marginBottom: value.imageGap * 2 + 'rpx', width: item.widthStyle, height: item.imgHeight + 'px' }">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'"
:style="item.pageItemStyle" :show-menu-by-longpress="true" />
</view>
</template>
</view>
</view>
</template>
<script>
// 魔方、橱窗
import htmlParser from '@/common/js/html-parser';
import DiyMinx from './minx.js'
export default {
name: 'diy-rubik-cube',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
customHtml: ''
};
},
created() {
if (this.value.mode == 'custom-rubik-cube') {
this.value.diyHtml = this.value.diyHtml.replace(/&quot;/g, '"');
this.customHtml = htmlParser(this.value.diyHtml);
} else {
var singleRow = {
'row1-of2': {
ratio: 2,
width: 'calc((100% - ' + uni.upx2px(this.value.imageGap * 2) + 'px) / 2)'
},
'row1-of3': {
ratio: 3,
width: 'calc((100% - ' + uni.upx2px(this.value.imageGap * 4) + 'px) / 3)'
},
'row1-of4': {
ratio: 4,
width: 'calc((100% - ' + uni.upx2px(this.value.imageGap * 6) + 'px) / 4)'
}
};
if (singleRow[this.value.mode]) {
this.calcSingleRow(singleRow[this.value.mode]);
} else if (this.value.mode == 'row2-lt-of2-rt') {
this.calcFourSquare();
} else if (this.value.mode == 'row1-lt-of2-rt') {
this.calcRowOneLeftOfTwoRight();
} else if (this.value.mode == 'row1-tp-of2-bm') {
this.calcRowOneTopOfTwoBottom();
} else if (this.value.mode == 'row1-lt-of1-tp-of2-bm') {
this.calcRowOneLeftOfOneTopOfTwoBottom();
}
}
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
list() {
var arr = JSON.parse(JSON.stringify(this.value.list));
arr.forEach((item, index) => {
item.pageItemStyle = this.countBorderRadius(this.value.mode, index);
});
return arr;
},
rubikCubeWrapCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
}
},
methods: {
/**
* 魔方:单行多个,平分宽度
* 公式:
* 宽度:屏幕宽度/2示例375/2=187.5
* 比例:原图高/原图宽示例322/690=0.46
* 高度:宽度*比例示例187.5*0.46=86.25
*/
calcSingleRow(params) {
uni.getSystemInfo({
success: res => {
let maxHeight = 0;
this.list.forEach((item, index) => {
var ratio = item.imgHeight / item.imgWidth;
let width = res.windowWidth - uni.upx2px(this.value.margin.both *
2); // 减去左右间距
if (this.value.imageGap > 0) {
width -= uni.upx2px(params.ratio * this.value.imageGap * 2); // 减去间隙
}
item.imgWidth = width / params.ratio;
item.imgHeight = item.imgWidth * ratio;
if (maxHeight == 0 || maxHeight < item.imgHeight) maxHeight = item
.imgHeight;
})
this.list.forEach((item, index) => {
item.widthStyle = params.width;
item.imgHeight = maxHeight;
});
}
})
},
/**
* 魔方四方型各占50%
*/
calcFourSquare() {
uni.getSystemInfo({
success: res => {
let maxHeightFirst = 0;
let maxHeightTwo = 0;
this.list.forEach((item, index) => {
var ratio = item.imgHeight / item.imgWidth;
item.imgWidth = res.windowWidth;
item.imgWidth -= uni.upx2px(this.value.margin.both * 4);
if (this.value.imageGap > 0) {
item.imgWidth -= uni.upx2px(this.value.imageGap * 2);
}
item.imgWidth = item.imgWidth / 2;
item.imgHeight = item.imgWidth * ratio;
// 获取每行最大高度
if (index <= 1) {
if (maxHeightFirst == 0 || maxHeightFirst < item.imgHeight) {
maxHeightFirst = item.imgHeight;
}
} else if (index > 1) {
if (maxHeightTwo == 0 || maxHeightTwo < item.imgHeight) {
maxHeightTwo = item.imgHeight;
}
}
});
this.list.forEach((item, index) => {
item.imgWidth = 'calc((100% - ' + uni.upx2px(this.value.imageGap * 2) +
'px) / 2)';
item.widthStyle = item.imgWidth;
if (index <= 1) {
item.imgHeight = maxHeightFirst;
} else if (index > 1) {
item.imgHeight = maxHeightTwo;
}
});
}
});
},
/**
* 魔方1左2右
*/
calcRowOneLeftOfTwoRight() {
let rightHeight = 0; // 右侧两图平分高度
let divide = 'left'; // 划分规则leftright
if (this.list[1].imgWidth === this.list[2].imgWidth) divide = 'right';
uni.getSystemInfo({
success: res => {
this.list.forEach((item, index) => {
if (index == 0) {
var ratio = item.imgHeight / item.imgWidth; // 获取左图的尺寸比例
item.imgWidth = res.windowWidth - uni.upx2px(this.value.margin.both * 4) - uni.upx2px(this.value.imageGap * 2);
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;
}
});
}
});
},
/**
* 魔方1上2下
*/
calcRowOneTopOfTwoBottom() {
var maxHeight = 0;
uni.getSystemInfo({
success: res => {
this.list.forEach((item, index) => {
var ratio = item.imgHeight / item.imgWidth; // 获取左图的尺寸比例
if (index == 0) {
item.imgWidth = res.windowWidth - uni.upx2px(this.value.margin.both * 4);
} else if (index > 0) {
item.imgWidth = res.windowWidth - uni.upx2px(this.value.margin.both * 4) - uni.upx2px(this.value.imageGap * 2);
item.imgWidth = item.imgWidth / 2;
}
item.imgHeight = item.imgWidth * ratio;
// 获取最大高度
if (index > 0 && (maxHeight == 0 || maxHeight < item.imgHeight))
maxHeight = item.imgHeight;
});
this.list.forEach((item, index) => {
item.imgWidth += 'px';
item.widthStyle = item.imgWidth;
if (index > 0) item.imgHeight = maxHeight;
});
}
});
},
/**
* 魔方1左3右
*/
calcRowOneLeftOfOneTopOfTwoBottom() {
uni.getSystemInfo({
success: res => {
this.list.forEach((item, index) => {
// 左图
if (index == 0) {
var ratio = item.imgHeight / item.imgWidth; // 获取左图的尺寸比例
item.imgWidth = res.windowWidth - uni.upx2px(this.value.margin.both * 4) - uni.upx2px(this.value.imageGap * 2);
item.imgWidth = item.imgWidth / 2;
item.imgHeight = item.imgWidth * ratio;
} else if (index == 1) {
item.imgWidth = this.list[0].imgWidth;
item.imgHeight = (this.list[0].imgHeight - uni.upx2px(this.value.imageGap * 2)) / 2;
} else if (index > 1) {
item.imgWidth = (this.list[0].imgWidth - uni.upx2px(this.value.imageGap * 2)) / 2;
item.imgHeight = this.list[1].imgHeight;
}
});
this.list.forEach((item, index) => {
item.imgWidth += 'px';
item.imgHeight;
});
}
});
},
countBorderRadius(type, index) {
var obj = '';
if (this.value.elementAngle == 'right') {
return obj;
}
var defaultData = {
'row1-lt-of2-rt': [
['border-top-right-radius', 'border-bottom-right-radius'],
['border-top-left-radius', 'border-bottom-left-radius', 'border-bottom-right-radius'],
['border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius']
],
'row1-lt-of1-tp-of2-bm': [
['border-top-right-radius', 'border-bottom-right-radius'],
['border-top-left-radius', 'border-bottom-left-radius', 'border-bottom-right-radius'],
['border-radius'],
['border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius']
],
'row1-tp-of2-bm': [
['border-bottom-left-radius', 'border-bottom-right-radius'],
['border-top-left-radius', 'border-bottom-right-radius', 'border-top-right-radius'],
['border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius']
],
'row2-lt-of2-rt': [
['border-top-right-radius', 'border-bottom-left-radius', 'border-bottom-right-radius'],
['border-top-left-radius', 'border-bottom-right-radius', 'border-bottom-left-radius'],
['border-top-left-radius', 'border-bottom-right-radius', 'border-top-right-radius'],
['border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius']
],
'row1-of4': [
['border-top-right-radius', 'border-bottom-right-radius'],
['border-radius'],
['border-radius'],
['border-top-left-radius', 'border-bottom-left-radius']
],
'row1-of3': [
['border-top-right-radius', 'border-bottom-right-radius'],
['border-radius'],
['border-top-left-radius', 'border-bottom-left-radius']
],
'row1-of2': [
['border-top-right-radius', 'border-bottom-right-radius'],
['border-top-left-radius', 'border-bottom-left-radius']
]
};
defaultData[type][index].forEach((item, index) => {
// obj += item + ':' + this.value.aroundRadius * 2 + 'rpx;';
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
});
return obj;
},
async handlerClick(link) {
await this.__$emitEvent({
eventName: 'rubik-cube-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.$util.diyRedirectTo(link);
}
})
}
}
};
</script>
<style lang="scss">
.rubik-cube {
overflow: hidden;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.rubik-cube .item {
text-align: center;
line-height: 0;
overflow: hidden;
}
.rubik-cube .item image {
width: 100%;
max-width: 100%;
height: 100%;
}
// 一行两个
.rubik-cube .item.row1-of2 {
box-sizing: border-box;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
.rubik-cube .item.row1-of2:nth-child(1) {
margin-left: 0 !important;
}
.rubik-cube .item.row1-of2:nth-child(2) {
margin-right: 0 !important;
}
// 一行三个
.rubik-cube .item.row1-of3 {
box-sizing: border-box;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
.rubik-cube .item.row1-of3:nth-child(1) {
margin-left: 0 !important;
}
.rubik-cube .item.row1-of3:nth-child(3) {
margin-right: 0 !important;
}
// 一行四个
.rubik-cube .item.row1-of4 {
box-sizing: border-box;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
.rubik-cube .item.row1-of4:nth-child(1) {
margin-left: 0 !important;
}
.rubik-cube .item.row1-of4:nth-child(4) {
margin-right: 0 !important;
}
// 两左两右
.rubik-cube .item.row2-lt-of2-rt {
// width: 50%;
display: inline-block;
box-sizing: border-box;
}
.rubik-cube .item.row2-lt-of2-rt:nth-child(1) {
margin-left: 0 !important;
margin-top: 0 !important;
}
.rubik-cube .item.row2-lt-of2-rt:nth-child(2) {
margin-right: 0 !important;
margin-top: 0 !important;
}
.rubik-cube .item.row2-lt-of2-rt:nth-child(3) {
margin-left: 0 !important;
margin-bottom: 0 !important;
}
.rubik-cube .item.row2-lt-of2-rt:nth-child(4) {
margin-right: 0 !important;
margin-bottom: 0 !important;
}
// 一左两右
.rubik-cube .template-left,
.rubik-cube .template-right {
// width: 50%;
box-sizing: border-box;
}
.rubik-cube .template-left .item.row1-lt-of2-rt:nth-child(1) {
margin-bottom: 0;
}
.rubik-cube .template-right .item.row1-lt-of2-rt:nth-child(2) {
margin-bottom: 0 !important;
}
.rubik-cube.row1-lt-of2-rt .template-right {
display: flex;
flex-direction: column;
justify-content: space-between;
}
// 一上两下
.rubik-cube .item.row1-tp-of2-bm:nth-child(1) {
width: 100%;
box-sizing: border-box;
margin-top: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
}
.rubik-cube .item.row1-tp-of2-bm:nth-child(2) {
// width: 50%;
box-sizing: border-box;
margin-left: 0 !important;
margin-bottom: 0 !important;
}
.rubik-cube .item.row1-tp-of2-bm:nth-child(3) {
// width: 50%;
box-sizing: border-box;
margin-right: 0 !important;
margin-bottom: 0 !important;
}
// 一左三右
.rubik-cube .template-left .item.row1-lt-of1-tp-of2-bm {
width: 100%;
box-sizing: border-box;
}
.rubik-cube .template-bottom {
display: flex;
align-items: center;
justify-content: space-between;
}
.rubik-cube .template-bottom .item:nth-child(2) {
margin-right: 0 !important;
}
</style>

View File

@@ -1,370 +0,0 @@
<template>
<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"
@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" />
</view>
<diy-icon class="icon" v-if="value.searchStyle == 2 && value.iconType == 'icon'" :icon="value.icon"
:value="value.style ? value.style : 'null'"
:style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx' }"></diy-icon>
<view class="search-content" :style="inputStyle">
<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" @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" @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"
@click.stop="handlerSearchClick" @tap="handlerSearchClick"
:placeholderStyle="placeholderStyle" />
<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'"
@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' }"
@click.stop="handlerRedirectToClick(value.searchLink)"
@tap="handlerRedirectToClick(value.searchLink)"></diy-icon>
</block>
</view>
</view>
<!-- 解决fixed定位后导航栏塌陷的问题 -->
<view v-if="value.positionWay == 'fixed'" class="u-navbar-placeholder"
:style="{ width: '100%', paddingTop: moduleHeight }"></view>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
// 获取系统状态栏的高度
let systemInfo = uni.getSystemInfoSync();
let menuButtonInfo = {};
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API尚未兼容)
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// #endif
import DiyMinx from './minx.js'
// 搜索
export default {
name: 'diy-search',
props: {
value: {
type: Object,
default: () => {
return {};
}
},
topNavColor: String,
global: {
type: Object,
default: () => {
return {};
}
},
haveTopCategory: {
type: Boolean
},
followOfficialAccount: {
type: Object
},
},
data() {
return {
searchText: '',
menuButtonInfo: menuButtonInfo,
height: 0,
placeholderHeight: 0,
moduleHeight: 0
};
},
mixins: [DiyMinx],
computed: {
fixedCss() {
var obj = '';
if (this.value.positionWay == 'fixed') {
let top = this.fixedTop;
// 固定定位
if (this.global.topNavBg)
obj += 'background-color:' + (this.topNavColor == 'transparent' ? this.value.pageBgColor : this
.topNavColor) + ';';
else
obj += 'background-color:' + this.value.pageBgColor + ';';
obj += 'top:' + top + ';';
obj += 'padding-top:' + this.value.margin.top * 2 + 'rpx;';
obj += 'padding-left:' + this.value.margin.both * 2 + 'rpx;';
obj += 'padding-right:' + this.value.margin.both * 2 + 'rpx;';
obj += 'padding-bottom:' + this.value.margin.bottom * 2 + 'rpx;';
}
return obj;
},
searchWrapCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
obj += 'text-align:' + this.value.textAlign + ';';
return obj;
},
inputStyle() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.borderType == 2) {
obj += 'border-radius:' + '40rpx;';
}
return obj;
},
placeholderStyle() {
var obj = '';
if (this.value.textColor) {
obj += 'color:' + this.value.textColor;
} else {
obj += 'color: rgba(0,0,0,0)';
}
return obj;
},
fixedTop() {
let diyPositionObj = this.$store.state.diyGroupPositionObj;
let data = 0
if (diyPositionObj.diySearch && diyPositionObj.diyIndexPage && diyPositionObj.nsNavbar) {
if (diyPositionObj.diySearch.moduleIndex > diyPositionObj.diyIndexPage.moduleIndex) {
data = diyPositionObj.nsNavbar.originalVal + diyPositionObj.diyIndexPage.originalVal;
} else {
data = diyPositionObj.nsNavbar.originalVal;
}
} else if (diyPositionObj.diySearch && diyPositionObj.nsNavbar) {
data = diyPositionObj.nsNavbar.originalVal;
}
data += 'px';
return data;
}
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
}
},
created() {
setTimeout(() => {
// 获取组件的高度默认高度为4545是在375屏幕上的高度
const query = uni.createSelectorQuery();
// #ifdef H5
let cssSelect = '.page-header .u-navbar';
// #endif
// #ifdef MP
let cssSelect = '.page-header >>> .u-navbar';
// #endif
query
.select(cssSelect)
.boundingClientRect(data => {
if (this.global.navBarSwitch) {
this.height = data ? data.height : 45;
} else {
this.height = data ? data.height : 0;
}
// 如果存在分类导航组件,则追加该组件的高度
if (this.haveTopCategory) {
this.height += 49;
}
})
.exec();
});
if (this.value.positionWay == 'fixed') this.navbarPlaceholderHeight();
},
mounted() {
if (this.value.positionWay == 'fixed')
this.setModuleLocationFn();
},
methods: {
search() {
this.$util.redirectTo('/pages_tool/goods/search');
},
redirectTo(link) {
if (link.wap_url) {
if (this.$util.getCurrRoute() == this.$util.MEMBER_PAGE_URL && !this.storeToken) {
this.$refs.login.open(link.wap_url);
return;
}
}
this.$util.diyRedirectTo(link);
},
navbarPlaceholderHeight() {
let height = 0;
setTimeout(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.diy-search-wrap')
.boundingClientRect(data => {
// 获取搜索框自身高度
this.placeholderHeight = data.height;
// 通过搜索框自身高度 - 定位模式下的多出的padding-bottom高度
if (this.placeholderHeight) this.placeholderHeight -= this.value.margin.bottom;
}).exec();
});
},
// 向vuex中的diyIndexPositionObj增加搜索组件定位位置
setModuleLocationFn() {
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.diy-search-wrap')
.boundingClientRect(data => {
let diySearch = {
originalVal: data.height || 0, //自身高度 px
currVal: 0, //定位高度
moduleIndex: this.value.moduleIndex //组件在diy-group的位置
};
this.moduleHeight = (data.height || 0) + 'px';
this.$store.commit('setDiyGroupPositionObj', {
'diySearch': diySearch
});
}).exec();
})
},
async handlerRedirectToClick(link) {
await this.__$emitEvent({
eventName: 'search-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.redirectTo(link);
}
})
},
async handlerSearchClick(item) {
await this.__$emitEvent({
eventName: 'search-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.search();
}
})
}
}
};
</script>
<style lang="scss">
/deep/ .uni-input-placeholder {
overflow: initial;
}
.diy-search-wrap {
overflow: hidden;
}
.fixed {
position: fixed;
left: 0;
right: 0;
top: 0;
z-index: 991;
transition: background 0.3s;
}
.search-box {
position: relative;
display: flex;
align-items: center;
.img {
height: 60rpx;
margin-right: 20rpx;
image {
width: 100%;
height: 100%;
}
}
.icon {
width: 170rpx;
height: 60rpx;
margin-right: 20rpx;
}
}
.search-box-3 {
.search-content {
display: flex;
align-items: center;
height: 68rpx;
.iconfont {
position: initial;
transform: translateY(0);
width: auto;
margin-left: 26rpx;
margin-right: 12rpx;
font-size: $font-size-base;
line-height: 1;
}
.uni-input {
flex: 1;
padding-left: 0;
height: 68rpx;
}
.search-content-btn {
margin-right: 8rpx;
width: 116rpx;
height: 54rpx;
line-height: 54rpx;
text-align: center;
color: #fff;
border-radius: 30rpx;
}
}
.diy-icon {
margin-left: 20rpx;
margin-right: 0;
width: auto;
font-size: 74rpx;
}
.img {
margin-left: 20rpx;
margin-right: 0;
}
}
.search-content {
flex: 1;
}
.search-content input {
box-sizing: border-box;
display: block;
height: 64rpx;
width: 100%;
padding: 0 20rpx 0 40rpx;
color: #333333;
background: none;
}
.search-content .iconfont {
position: absolute;
top: 50%;
right: 4rpx;
transform: translateY(-50%);
font-size: 30rpx;
z-index: 10;
width: 80rpx;
font-weight: bold;
text-align: center;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,180 +0,0 @@
<template>
<x-skeleton data-component-name="diy-store-label" type="banner" :loading="loading" :configs="skeletonConfig">
<view class="diy-store-label">
<block v-if="businessConfig.store_business == 'store'">
<scroll-view scroll-x="true" :class="[value.contentStyle, { between: list.length == 3 }]"
:style="storeLabelWrapCss" :enable-flex="true">
<view v-for="(item, index) in storeLabel" :key="index" :class="['item']">
<diy-icon v-if="value.icon" class="icon-box" :icon="value.icon"
:value="value.style ? value.style : 'null'"></diy-icon>
<text class="label-name"
:style="{ color: value.textColor, fontSize: value.fontSize * 2 + 'rpx', fontWeight: value.fontWeight }">{{
item }}</text>
</view>
</scroll-view>
</block>
<block v-else>
<scroll-view scroll-x="true" :class="[value.contentStyle, { between: list.length == 3 }]"
:style="storeLabelWrapCss" :enable-flex="true">
<view v-for="(item, index) in list" :class="['item']">
<diy-icon v-if="value.icon" class="icon-box" :icon="value.icon"
:value="value.style ? value.style : 'null'"></diy-icon>
<text class="label-name"
:style="{ color: value.textColor, fontSize: value.fontSize * 2 + 'rpx', fontWeight: value.fontWeight }">{{
item.label_name }}</text>
</view>
</scroll-view>
</block>
</view>
</x-skeleton>
</template>
<script>
// 门店标签
import DiyMinx from './minx.js'
export default {
name: 'diy-store-label',
props: {
value: {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
loading: true,
skeletonConfig: {
gridRows: 1,
gridRowsGap: '20rpx',
headHeight: '40rpx',
headBorderRadius: '0'
},
list: [],
notice: '',
storeLabel: [],
businessConfig: ""
};
},
created() {
this.getData();
this.getStoreConfig();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getData();
}
},
computed: {
storeLabelWrapCss: function () {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
}
},
methods: {
getData() {
var data = {
page: 1,
page_size: 0
};
if (this.value.sources == 'initial') {
data.page_size = this.value.count;
} else if (this.value.sources == 'diy') {
data.label_id_arr = this.value.labelIds.toString();
}
this.$api.sendRequest({
url: '/store/api/store/labelPage',
data: data,
success: res => {
if (res.code == 0 && res.data) {
this.list = res.data.list;
}
this.loading = false;
}
});
},
getStoreConfig() {
this.$api.sendRequest({
url: '/store/api/config/config',
success: res => {
if (res.code >= 0) {
this.businessConfig = res.data.business_config;
if (res.data.business_config.store_business == "store") {
this.getStoreInfo();
}
}
}
});
},
getStoreInfo() {
this.$api.sendRequest({
url: '/api/store/info',
success: res => {
if (res.data) {
let label_arr = res.data.label_name.split(",");
let label_count = 3;
if (this.value.sources == 'initial') label_count = this.value.count;
for (let i = 0; i < label_arr.length; i++) {
if (this.storeLabel.length < label_count && label_arr[i] != '') {
this.storeLabel.push(label_arr[i])
}
}
}
}
});
},
}
};
</script>
<style lang="scss">
.diy-store-label {
.style-1 {
display: flex;
align-items: baseline;
/deep/ .uni-scroll-view-content {
display: flex;
align-items: center;
}
&.between {
justify-content: space-between;
/deep/.uni-scroll-view-content {
justify-content: space-between;
}
}
.item {
flex-shrink: 0;
display: flex;
align-items: center;
padding-right: 20rpx;
.icon-box {
font-size: 50rpx;
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
margin-top: 2rpx;
}
.label-name {
line-height: 40rpx;
}
&:last-of-type {
padding-right: 0;
}
}
}
}
</style>

View File

@@ -1,671 +0,0 @@
<template>
<view :style="componentStyle">
<!-- 固定布局模式 -->
<view v-if="value.showStyle == 'fixed'" :class="['goods-list', 'row1-of' + value.rowCount]"
style="padding:20rpx;">
<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)"></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"></image>
</view>
</view>
<view class="info-wrap">
<view class="goods-name" :style="{
'font-size': (value.font.size * 2 + 'rpx') + ';',
'font-weight': value.font.weight + ';',
'color': value.font.color + ';'
}">{{ item.title }}</view>
</view>
</view>
</view>
<!-- 其他布局模式 -->
<scroll-view v-else :class="['video-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle]"
:scroll-x="value.showStyle == 'singleSlide'">
<view class="uni-scroll-view-content">
<view v-for="(item, index) in value.list" :key="index" :class="['video-nav-item', value.mode]"
:style="{ width: (100 / value.rowCount + '%') + ';' }" @tap="showVideo(item)">
<view class="video-img">
<image v-if="item.iconType == 'img'" :style="{
'max-width': '200rpx;',
'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="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">
</image>
</view>
</view>
<view class="video-text" :style="{
'margin-left': '16rpx;',
'font-size': (value.font.size * 2 + 'rpx') + ';',
'font-weight': value.font.weight + ';',
'color': value.font.color + ';'
}">{{ item.title }}</view>
</view>
</view>
</scroll-view>
<!-- 视频播放弹窗 -->
<uni-popup ref="videoPopup" type="center" style="background:transparent;width:100%;height:100%;">
<view class="video-container" style="position:fixed;top:30%;width:100%;left:0;">
<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 DiyMinx from './minx.js'
export default {
name: 'diy-video-list',
props: {
value: {
type: Object,
default: () => ({})
}
},
mixins: [DiyMinx],
data() {
return {
pageWidth: '',
indicatorDots: false,
swiperCurrent: 0,
video_url: ''
}
},
created() {
// 组件创建时的逻辑
},
watch: {
componentRefresh(newValue) {
// 监听组件刷新
}
},
computed: {
componentStyle() {
let style = '';
style += 'background-color:' + this.value.componentBgColor + ';';
if (this.value.componentAngle == 'round') {
style += 'border-top-left-radius:' + (2 * this.value.topAroundRadius) + 'rpx;';
style += 'border-top-right-radius:' + (2 * this.value.topAroundRadius) + 'rpx;';
style += 'border-bottom-left-radius:' + (2 * this.value.bottomAroundRadius) + 'rpx;';
style += 'border-bottom-right-radius:' + (2 * this.value.bottomAroundRadius) + 'rpx;';
}
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;
},
swiperHeight() {
let height = 0;
if (this.value.mode == 'graphic') {
height = (49 + this.value.imageSize) * this.value.pageCount;
} else if (this.value.mode == 'img') {
height = (22 + this.value.imageSize) * this.value.pageCount;
} else if (this.value.mode == 'text') {
height = 43 * this.value.pageCount;
}
return 'height:' + (2 * height) + 'rpx';
},
isIndicatorDots() {
return this.value.carousel.type != 'hide' &&
1 != Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount));
}
},
methods: {
// 显示视频播放弹窗
showVideo(item) {
this.video_url = item.videoUrl;
this.$refs.videoPopup.open();
},
// 图片加载错误处理
imgError(index) {
// 图片加载失败的处理逻辑
console.log('图片加载失败:', index);
}
}
}
</script>
<style lang="scss" scoped>
.goods-name {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.goods-list {
&.row1-of3 {
display: flex;
flex-wrap: wrap;
.goods-item {
position: relative;
display: flex;
flex-direction: column;
margin-top: 20rpx;
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) {
margin-top: 0;
}
&:nth-child(3n) {
width: calc(33.3333333% - 15rpx);
}
&:nth-child(3n-1) {
margin-left: 20rpx;
margin-right: 20rpx;
}
&.shadow {
width: calc(33.3333333% - 18rpx);
&:nth-of-type(1),
&:nth-of-type(2),
&:nth-of-type(3) {
margin-top: 8rpx;
}
&:nth-child(1n) {
margin-left: 8rpx;
}
&:nth-child(3n-1) {
margin-left: 20rpx;
margin-right: 20rpx;
}
&:nth-child(3n) {
margin-right: 0;
margin-left: 0;
}
}
.goods-img-wrap {
position: relative;
overflow: hidden;
height: 220rpx;
}
.goods-img {
width: 100%;
}
.info-wrap {
display: flex;
flex-direction: column;
flex: 1;
.pro-info {
margin-top: auto;
display: flex;
flex-direction: column;
justify-content: space-between;
.discount-price {
display: flex;
justify-content: space-between;
align-items: center;
.price-wrap {
white-space: nowrap;
.unit {
font-size: 24rpx !important;
}
.price {
font-size: 32rpx;
text {
font-weight: 700;
}
}
}
}
.delete-price {
text-decoration: line-through;
flex: 1;
line-height: 28rpx;
color: #909399;
font-size: 20rpx;
}
}
}
}
&.style-1 {
.pro-info {
.price-wrap {
line-height: 1;
}
.discount-price {
justify-content: unset !important;
align-items: baseline !important;
flex-wrap: wrap;
}
.delete-price {
margin-left: 10rpx;
}
}
}
&.style-2 {
.pro-info {
position: relative;
flex-direction: row !important;
align-items: center;
.price-wrap {
line-height: 1;
}
.discount-price {
align-items: flex-end !important;
flex-wrap: wrap;
justify-content: unset !important;
}
.delete-price {
margin: 20rpx 0;
flex-basis: 100% !important;
}
.buy-btn {
min-width: 112rpx;
height: 52rpx;
padding: 0 20rpx;
line-height: 52rpx;
text-align: center;
box-sizing: border-box;
}
}
}
.sell-out {
text {
font-size: 150rpx;
}
}
}
&.row1-of2 {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.goods-item {
position: relative;
margin-top: 20rpx;
width: calc(50% - 10rpx);
display: flex;
flex-direction: column;
box-sizing: border-box;
&:nth-child(2n) {
margin-right: 0 !important;
}
&:nth-of-type(1),
&:nth-of-type(2) {
margin-top: 0;
}
&.shadow {
width: calc(50% - 18rpx);
&:nth-child(2n-1) {
margin-left: 8rpx;
}
&:nth-child(2n) {
margin-right: 8rpx !important;
}
&:nth-of-type(1),
&:nth-of-type(2) {
margin-top: 8rpx;
}
}
.goods-img-wrap {
position: relative;
overflow: hidden;
height: 340rpx;
}
.goods-img {
width: 100%;
}
.info-wrap {
display: flex;
flex-direction: column;
flex: 1;
.sale {
flex-basis: 100%;
}
.pro-info {
margin-top: auto;
display: flex;
flex-direction: row;
justify-content: space-between;
.discount-price {
.price-wrap {
white-space: nowrap;
.unit {
font-weight: 700;
font-size: 24rpx !important;
}
.price {
font-weight: 700;
font-size: 32rpx !important;
}
}
}
.delete-price {
text-decoration: line-through;
flex: 1;
line-height: 28rpx;
color: #909399;
font-size: 20rpx;
}
}
}
}
&.style-1 {
.pro-info {
.discount-price {
display: flex;
flex-wrap: wrap;
align-items: baseline;
.price-wrap {
display: inline-block;
text {
font-weight: 700;
}
line-height: 1;
}
}
.delete-price {
margin-top: 6rpx;
flex-basis: 100% !important;
}
}
}
&.style-2 {
.pro-info {
position: relative;
align-items: center;
.price-wrap {
line-height: 1;
}
.discount-price {
display: flex;
flex-wrap: wrap;
align-items: baseline;
}
.delete-price {
margin-top: 4rpx;
flex-basis: 100% !important;
}
.sale {
line-height: 1;
margin-top: 10rpx;
}
.buy-btn {
min-width: 140rpx;
height: 52rpx;
padding: 0 20rpx;
line-height: 52rpx;
text-align: center;
box-sizing: border-box;
}
}
}
&.style-3 {
.pro-info {
.member-price {
margin-right: auto;
align-self: flex-end;
margin-bottom: 4rpx;
}
.sale {
line-height: 1;
align-self: center;
margin-top: 8rpx;
}
.discount-price {
display: flex;
flex-wrap: wrap;
flex: 1;
align-content: center;
.price-wrap {
display: flex;
align-items: baseline;
line-height: 1;
align-self: center;
}
}
}
.swiper {
padding: 20rpx 0;
}
}
.sell-out {
text {
font-size: 250rpx;
}
}
}
}
.video-container {
width: 100%;
height: 300px;
position: relative;
}
.adaptive-video {
width: 100%;
height: 100%;
object-fit: contain;
position: absolute;
top: 0;
left: 0;
}
.video-nav {
padding: 16rpx;
box-sizing: border-box;
&.fixed-layout {
.uni-scroll-view-content {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
}
&.singleSlide {
.uni-scroll-view-content {
display: flex;
}
.video-nav-item {
flex-shrink: 0;
}
}
&.pageSlide {
position: relative;
.uni-swiper-dots-horizontal {
bottom: 0rpx;
}
&.straightLine {
.uni-swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
}
&.circle {
.uni-swiper-dot {
width: 14rpx;
height: 14rpx;
}
}
}
.video-nav-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
.video-nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 14rpx 0;
box-sizing: border-box;
.video-text {
padding-top: 12rpx;
line-height: 1.5;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
&.alone {
padding-top: 0;
}
}
&.text {
.video-text {
padding-top: 0;
}
}
.video-img {
position: relative;
display: flex;
align-items: center;
justify-content: center;
font-size: 90rpx;
.tag {
position: absolute;
top: -10rpx;
right: -24rpx;
color: #fff;
border-radius: 24rpx;
border-bottom-left-radius: 0;
-webkit-transform: scale(0.8);
transform: scale(0.8);
padding: 8rpx 16rpx;
line-height: 1;
font-size: 24rpx;
}
.icon {
font-size: 50rpx;
color: #606266;
}
}
}
}
.swiper-dot-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: -20rpx;
padding-bottom: 8rpx;
.swiper-dot {
background-color: rgba(0, 0, 0, 0.3);
margin: 8rpx;
&.active {
background-color: #000;
}
}
&.straightLine {
.swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
}
&.circle {
.swiper-dot {
width: 15rpx;
border-radius: 50%;
height: 15rpx;
}
}
}
</style>

View File

@@ -1,58 +0,0 @@
<template>
<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>
// 视频
import DiyMinx from './minx.js'
export default {
name: 'diy-video',
props: {
value: {
type: Object
}
},
data() {
return {};
},
created() { },
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
videoWarpCss: function () {
var obj = '';
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;
}
},
methods: {
async handlerClick(videoUrl) {
await this.__$emitEvent({
eventName: 'video-tap', data: videoUrl, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
}
})
}
}
};
</script>
<style scoped>
video {
width: 100%;
}
.diy-video>>>.uni-video-container {
background-color: transparent;
}
</style>

View File

@@ -1,458 +0,0 @@
<template>
<view :style="componentStyle">
<!-- 固定布局模式 -->
<view v-if="value.showStyle == 'fixed'" :class="['channel-list', 'row1-of' + value.rowCount]"
style="padding:20rpx;">
<view v-for="(item, index) in value.list" :key="index" class="channel-item" @tap="playVideo(item)">
<view class="channel-img-wrap">
<image class="channel-img" style="border-radius:10rpx;" :src="$util.img(item.coverUrl)"
mode="aspectFill" @error="imgError(index)"></image>
<view class="channel-play-btn">
<image class="play-icon" style="width:30rpx;" :src="$util.img('addon/personnel/shop/view/enterprise/play.png')"
mode="widthFix"></image>
</view>
<view class="channel-stats">
<text>{{ item.viewCount }}次观看</text>
</view>
</view>
<view class="channel-info-wrap">
<view class="channel-name" :style="{
'font-size': (value.font.size * 2 + 'rpx') + ';',
'font-weight': value.font.weight + ';',
'color': value.font.color + ';'
}">{{ item.channelName }}</view>
<view class="video-title" :style="{
'font-size': (value.font.size * 1.8 + 'rpx') + ';',
'color': '#666;'
}">{{ item.videoTitle }}</view>
</view>
</view>
</view>
<!-- 其他布局模式 -->
<scroll-view v-else :class="['channel-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle]"
:scroll-x="value.showStyle == 'singleSlide'">
<view class="uni-scroll-view-content">
<view v-for="(item, index) in value.list" :key="index" :class="['channel-nav-item', value.mode]"
:style="{ width: (100 / value.rowCount + '%') + ';' }" @tap="playVideo(item)">
<view class="channel-img">
<image :style="{
'max-width': '100%;',
'border-radius': '8rpx;'
}" :src="$util.img(item.coverUrl)" mode="aspectFill"
:show-menu-by-longpress="true"></image>
<view class="channel-play-btn">
<image class="play-icon" style="width:30rpx;" :src="$util.img('addon/personnel/shop/view/enterprise/play.png')"
mode="widthFix"></image>
</view>
<view class="channel-stats">
<text>{{ item.viewCount }}次观看</text>
</view>
</view>
<view class="channel-text" :style="{
'margin-left': '16rpx;',
'font-size': (value.font.size * 2 + 'rpx') + ';',
'font-weight': value.font.weight + ';',
'color': value.font.color + ';'
}">{{ item.videoTitle }}</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-wechat-channel-list',
props: {
value: {
type: Object,
default: () => ({})
}
},
mixins: [DiyMinx],
data() {
return {
pageWidth: '',
indicatorDots: false,
swiperCurrent: 0
}
},
created() {
// 组件创建时的逻辑
},
watch: {
componentRefresh(newValue) {
// 监听组件刷新
}
},
computed: {
componentStyle() {
let style = '';
style += 'background-color:' + this.value.componentBgColor + ';';
if (this.value.componentAngle == 'round') {
style += 'border-top-left-radius:' + (2 * this.value.topAroundRadius) + 'rpx;';
style += 'border-top-right-radius:' + (2 * this.value.topAroundRadius) + 'rpx;';
style += 'border-bottom-left-radius:' + (2 * this.value.bottomAroundRadius) + 'rpx;';
style += 'border-bottom-right-radius:' + (2 * this.value.bottomAroundRadius) + 'rpx;';
}
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 : '') + ';';
return style;
},
swiperHeight() {
let height = 0;
if (this.value.mode == 'graphic') {
height = (49 + this.value.imageSize) * this.value.pageCount;
} else if (this.value.mode == 'img') {
height = (22 + this.value.imageSize) * this.value.pageCount;
} else if (this.value.mode == 'text') {
height = 43 * this.value.pageCount;
}
return 'height:' + (2 * height) + 'rpx';
},
isIndicatorDots() {
return this.value.carousel.type != 'hide' &&
1 != Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount));
}
},
methods: {
// 播放视频
async playVideo(item) {
await this.__$emitEvent({
eventName: 'video-play', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
// 检查微信环境
if (typeof wx === 'undefined') {
console.error('当前环境不是微信小程序');
return;
}
// 检查基础库版本
const systemInfo = wx.getSystemInfoSync();
const SDKVersion = systemInfo.SDKVersion;
const 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;
};
if (versionCompare(SDKVersion, '2.19.2') < 0) {
console.error('当前微信基础库版本过低,需要 2.19.2 或以上版本');
return;
}
// 调用微信视频号播放API
if (wx.openChannelsActivity) {
wx.openChannelsActivity({
feedId: item.feedId,
finderUserName: item.finderUserName,
success: (res) => {
console.log('打开视频号成功', res);
},
fail: (err) => {
console.error('打开视频号失败', err);
// 错误码处理
switch (err.errCode) {
case 40001:
console.error('错误40001检查主体要求或嵌入式打开的关联关系');
break;
case 40002:
console.error('错误40002参数错误检查 feedId 和 finderUserName');
break;
default:
console.error('错误:' + err.errCode + '' + (err.errMsg || '未知错误'));
break;
}
}
});
} else {
console.error('当前环境不支持微信视频号');
}
}
})
},
// 图片加载错误处理
imgError(index) {
// 图片加载失败的处理逻辑
console.log('图片加载失败:', index);
// 为失败的图片设置默认图片
const item = this.value.list[index];
if (item) {
// 使用默认图片替代加载失败的图片
item.coverUrl = 'addon/personnel/shop/view/enterprise/default-video-cover.png';
}
}
}
}
</script>
<style lang="scss" scoped>
.channel-list {
&.row1-of3 {
display: flex;
flex-wrap: wrap;
.channel-item {
position: relative;
display: flex;
flex-direction: column;
margin-top: 20rpx;
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) {
margin-top: 0;
}
&:nth-child(3n) {
width: calc(33.3333333% - 15rpx);
}
&:nth-child(3n-1) {
margin-left: 20rpx;
margin-right: 20rpx;
}
.channel-img-wrap {
position: relative;
overflow: hidden;
height: 220rpx;
border-radius: 10rpx;
}
.channel-img {
width: 100%;
height: 100%;
}
.channel-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60rpx;
height: 60rpx;
background-color: rgba(0, 0, 0, 0.4);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.channel-stats {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.6));
padding: 10rpx;
color: #fff;
font-size: 20rpx;
}
.channel-info-wrap {
display: flex;
flex-direction: column;
flex: 1;
padding: 10rpx 0;
.channel-name {
margin-bottom: 4rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.video-title {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
}
}
&.row1-of2 {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.channel-item {
position: relative;
margin-top: 20rpx;
width: calc(50% - 10rpx);
display: flex;
flex-direction: column;
box-sizing: border-box;
&:nth-child(2n) {
margin-right: 0 !important;
}
&:nth-of-type(1),
&:nth-of-type(2) {
margin-top: 0;
}
.channel-img-wrap {
position: relative;
overflow: hidden;
height: 340rpx;
border-radius: 10rpx;
}
.channel-img {
width: 100%;
height: 100%;
}
.channel-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80rpx;
height: 80rpx;
background-color: rgba(0, 0, 0, 0.4);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.channel-stats {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.6));
padding: 10rpx;
color: #fff;
font-size: 20rpx;
}
.channel-info-wrap {
display: flex;
flex-direction: column;
flex: 1;
padding: 10rpx 0;
.channel-name {
margin-bottom: 4rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.video-title {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
}
}
}
.channel-nav {
padding: 16rpx;
box-sizing: border-box;
&.fixed-layout {
.uni-scroll-view-content {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
}
&.singleSlide {
.uni-scroll-view-content {
display: flex;
}
.channel-nav-item {
flex-shrink: 0;
}
}
.channel-nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 14rpx 0;
box-sizing: border-box;
.channel-img {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 200rpx;
border-radius: 10rpx;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
.channel-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60rpx;
height: 60rpx;
background-color: rgba(0, 0, 0, 0.4);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.channel-stats {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.6));
padding: 10rpx;
color: #fff;
font-size: 20rpx;
}
}
.channel-text {
padding-top: 12rpx;
line-height: 1.5;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
}
}
}
</style>

View File

@@ -1,232 +0,0 @@
<template>
<!-- #ifdef MP-WEIXIN -->
<view class="diy-wechat-channel" :style="channelWarpCss">
<view class="channel-header" @tap="handlerClick">
<image class="channel-avatar" :src="$util.img(value.avatarUrl)" mode="aspectFill"></image>
<view class="channel-info">
<view class="channel-name">{{ value.channelName }}</view>
<view class="channel-follow" v-if="value.showFollow">关注</view>
</view>
<image class="channel-arrow" :src="$util.img('addon/personnel/shop/view/enterprise/arrow.png')" mode="aspectFill"></image>
</view>
<!-- 嵌入式视频播放 -->
<native-component v-if="value.embedMode && typeof wx !== 'undefined' && wx.canIUse('component.channel-video')">
<channel-video
:feed-id="value.feedId"
:finder-user-name="value.finderUserName"
:feed-token="value.feedToken"
style="width: 100%; height: 320rpx;">
</channel-video>
</native-component>
<!-- 跳转式视频播放 -->
<view v-else class="channel-video" @tap="playVideo">
<image class="video-cover" :src="$util.img(value.coverUrl)" mode="aspectFill"></image>
<view class="video-play-btn">
<image class="play-icon" :src="$util.img('addon/personnel/shop/view/enterprise/play.png')" mode="aspectFill"></image>
</view>
<view class="video-info">
<view class="video-title">{{ value.videoTitle }}</view>
<view class="video-stats">
<text>{{ value.viewCount }}次观看</text>
</view>
</view>
</view>
</view>
<!-- #endif -->
</template>
<script>
// 微信视频号组件
import DiyMinx from './minx.js'
export default {
name: 'diy-wechat-channel',
props: {
value: {
type: Object
}
},
data() {
return {};
},
created() { },
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
channelWarpCss: function () {
var obj = '';
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;
}
},
methods: {
async handlerClick() {
await this.__$emitEvent({
eventName: 'channel-tap', data: this.value, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
}
})
},
async playVideo() {
await this.__$emitEvent({
eventName: 'video-play', data: this.value, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
// 检查微信环境
if (typeof wx === 'undefined') {
console.error('当前环境不是微信小程序');
return;
}
// 检查基础库版本
const systemInfo = wx.getSystemInfoSync();
const SDKVersion = systemInfo.SDKVersion;
const 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;
};
if (versionCompare(SDKVersion, '2.19.2') < 0) {
console.error('当前微信基础库版本过低,需要 2.19.2 或以上版本');
return;
}
// 调用微信视频号播放API
if (wx.openChannelsActivity) {
wx.openChannelsActivity({
feedId: this.value.feedId,
finderUserName: this.value.finderUserName,
success: (res) => {
console.log('打开视频号成功', res);
},
fail: (err) => {
console.error('打开视频号失败', err);
// 错误码处理
switch (err.errCode) {
case 40001:
console.error('错误40001检查主体要求或嵌入式打开的关联关系');
break;
case 40002:
console.error('错误40002参数错误检查 feedId 和 finderUserName');
break;
default:
console.error('错误:' + err.errCode + '' + (err.errMsg || '未知错误'));
break;
}
}
});
} else {
console.error('当前环境不支持微信视频号');
}
}
})
}
}
};
</script>
<style scoped>
.diy-wechat-channel {
width: 100%;
background-color: #fff;
border-radius: 12rpx;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
}
.channel-header {
display: flex;
align-items: center;
padding: 16rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.channel-avatar {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
margin-right: 12rpx;
}
.channel-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.channel-name {
font-size: 28rpx;
font-weight: 500;
color: #333;
margin-bottom: 4rpx;
}
.channel-follow {
font-size: 24rpx;
color: #07c160;
}
.channel-arrow {
width: 24rpx;
height: 24rpx;
margin-left: 8rpx;
}
.channel-video {
position: relative;
}
.video-cover {
width: 100%;
height: 320rpx;
object-fit: cover;
}
.video-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80rpx;
height: 80rpx;
background-color: rgba(0, 0, 0, 0.4);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.play-icon {
width: 40rpx;
height: 40rpx;
}
.video-info {
padding: 16rpx;
}
.video-title {
font-size: 28rpx;
font-weight: 500;
color: #333;
margin-bottom: 8rpx;
line-height: 1.4;
}
.video-stats {
font-size: 24rpx;
color: #999;
}
</style>

View File

@@ -357,10 +357,14 @@
</view>
</template>
<script>
import nsLoading from '@/components/ns-loading/ns-loading.vue'
import aiService from '@/common/js/ai-service.js'
export default {
name: 'ai-chat-message',
components: {
nsLoading
},
props: {
// 初始消息列表
initialMessages: {
@@ -810,121 +814,65 @@ export default {
},
// 发送流式消息
// 发送流式消息(自动适配 H5 / 微信小程序)
async sendStreamMessage(userMessage) {
// 创建流式消息对象
const streamMessage = {
id: ++this.messageId,
role: 'ai',
type: 'text',
content: '',
timestamp: Date.now(),
isStreaming: true
};
// 移除加载状态,添加流式消息
this.messages = this.messages.filter(msg => msg.type !== 'loading');
this.shouldScrollToBottom = true;
this.messages.push(streamMessage);
try {
// #ifdef H5
// ===== H5: 使用 POST + 流式 (fetch readable stream) =====
await aiService.sendHttpStream(
async sendStreamMessage(userMessage) {
// 创建流式消息对象
const streamMessage = {
id: ++this.messageId,
role: 'ai',
type: 'text',
content: '',
timestamp: Date.now(),
isStreaming: true
}
// 移除加载状态,添加流式消息
this.messages = this.messages.filter(msg => msg.type !== 'loading')
this.shouldScrollToBottom = true
this.messages.push(streamMessage)
// 开始流式响应
await aiService.sendStreamMessage(
userMessage,
// 流式数据回调
(chunk) => {
// 实时更新内容
streamMessage.content += chunk;
this.$forceUpdate(); // 强制更新视图
streamMessage.content += chunk
this.$forceUpdate() // 或 this.$nextTick()
},
// 完成回调:处理对象或字符串
(completeResult) => {
// 流结束回调
let finalContent = '';
let convId = '';
// 判断是对象还是字符串
if (typeof completeResult === 'string') {
finalContent = completeResult;
} else {
finalContent = completeResult.content || '';
convId = completeResult.conversation_id || '';
convId = completeResult.conversation_id || ''; // 👈 关键:提取 conversation_id
}
// 更新最终内容
// 更新消息状态
streamMessage.isStreaming = false;
streamMessage.content = finalContent;
// 添加操作按钮
streamMessage.actions = [
{ id: 1, text: '有帮助', type: 'like' },
{ id: 2, text: '没帮助', type: 'dislike' }
];
// 保存会话 ID
// 保存 conversation_id 到本地
if (convId) {
this.currentConversationId = convId;
aiService.setConversationId(convId);
this.saveConversationIdToLocal(convId);
}
// 触发事件
this.$emit('ai-response', streamMessage);
this.saveConversationIdToLocal(convId);
this.currentConversationId = convId;
}
);
// #endif
// #ifdef MP-WEIXIN
// ===== 微信小程序: 使用 WebSocket =====
await aiService.sendStreamMessage(
userMessage,
(chunk) => {
// 实时更新内容
streamMessage.content += chunk;
this.$forceUpdate();
},
(completeResult) => {
// 流结束回调
let finalContent = completeResult?.content || '';
let convId = completeResult?.conversation_id || '';
// 更新最终内容
streamMessage.isStreaming = false;
streamMessage.content = finalContent;
// 添加操作按钮
streamMessage.actions = [
{ id: 1, text: '有帮助', type: 'like' },
{ id: 2, text: '没帮助', type: 'dislike' }
];
// 保存会话 ID
if (convId) {
this.currentConversationId = convId;
aiService.setConversationId(convId);
this.saveConversationIdToLocal(convId);
}
// 触发事件
this.$emit('ai-response', streamMessage);
}
);
// #endif
} catch (error) {
console.error('流式请求失败:', error);
// 移除流式消息
this.messages = this.messages.filter(msg => msg.id !== streamMessage.id);
// 显示错误
const errorMsg = {
id: ++this.messageId,
role: 'ai',
type: 'text',
content: '抱歉,服务暂时不可用,请稍后重试。',
timestamp: Date.now(),
actions: [{ id: 1, text: '重试', type: 'retry' }]
};
this.messages.push(errorMsg);
this.$emit('ai-response', errorMsg);
}
},
},
generateAIResponse(userMessage) {
const responses = {
'你好': '您好我是AI智能客服很高兴为您服务有什么可以帮助您的吗',
@@ -2815,4 +2763,4 @@ $radius-lg: 36rpx;
}
}
}
</style>
</style>

View File

@@ -0,0 +1,638 @@
<template>
<view class="order-container" :class="{ 'safe-area': isIphoneX }">
<!-- #ifdef MP-WEIXIN -->
<view class="payment-navbar" :style="{ 'padding-top': menuButtonBounding.top + 'px', height: menuButtonBounding.height + 'px' }">
<view class="nav-wrap">
<text class="iconfont icon-back_light" @click="back"></text>
<view class="navbar-title">确认订单</view>
</view>
</view>
<view class="payment-navbar-block" :style="{ height: menuButtonBounding.bottom + 'px' }"></view>
<!-- #endif -->
<scroll-view scroll-y="true" class="order-scroll-container">
<view class="payment-navbar-block"></view>
<template v-if="paymentData">
<template v-if="paymentData.is_virtual">
<!-- 虚拟商品联系方式 -->
<view class="mobile-wrap">
<view class="tips color-base-text">
<text class="iconfont icongantanhao"></text>
购买虚拟类商品需填写手机号方便商家与您联系
</view>
<view class="form-group">
<text class="icon">
<image :src="$util.img('public/uniapp/order/icon-mobile.png')" mode="widthFix"></image>
</text>
<text class="text">手机号码</text>
<input type="number" maxlength="11" placeholder="请输入您的手机号码" placeholder-class="color-tip placeholder" class="input" v-model="orderCreateData.member_address.mobile" />
</view>
</view>
</template>
<template v-else>
<!-- 配送方式 -->
<view class="delivery-mode" v-if="goodsData.delivery.express_type.length > 1">
<view class="action">
<view :class="{ active: item.name == orderCreateData.delivery.delivery_type }" v-for="(item, index) in goodsData.delivery.express_type" :key="index" @click="selectDeliveryType(item)">
{{ item.title }}
<!-- 外圆角 -->
<view class="out-radio"></view>
</view>
</view>
</view>
<view class="address-box" :class="{ 'not-delivery-type': goodsData.delivery.express_type.length <= 1 }" v-if="orderCreateData.delivery.delivery_type == 'express'">
<view class="info-wrap" v-if="memberAddress" @click="selectAddress">
<view class="content">
<text class="name">{{ memberAddress.name ? memberAddress.name : '' }}</text>
<text class="mobile">{{ memberAddress.mobile ? memberAddress.mobile : '' }}</text>
<view class="desc-wrap">
{{ memberAddress.full_address ? memberAddress.full_address : '' }}
{{ memberAddress.address ? memberAddress.address : '' }}
</view>
</view>
<text class="cell-more iconfont icon-right"></text>
</view>
<view class="empty-wrap" v-else @click="selectAddress">
<view class="info">请设置收货地址</view>
<view class="cell-more">
<view class="iconfont icon-right"></view>
</view>
</view>
<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'">
<view v-if="localMemberAddress">
<block v-if="storeList && Object.keys(storeList).length > 1">
<view class="local-delivery-store" v-if="storeInfo" @click="openPopup('deliveryPopup')">
<view class="info">
<text class="store-name">{{ storeInfo.store_name }}</text>
提供配送
</view>
<view class="cell-more">
<text>点击切换</text>
<text class="iconfont icon-right"></text>
</view>
</view>
<view v-else class="local-delivery-store">
<view class="info">
<text class="store-name">您的附近没有可配送的门店请选择其他配送方式</text>
</view>
</view>
</block>
<view class="info-wrap local" @click="selectAddress">
<view class="content">
<text class="name">{{ localMemberAddress.name ? localMemberAddress.name : '' }}
</text>
<text class="mobile">{{ localMemberAddress.mobile ? localMemberAddress.mobile : '' }}
</text>
<view class="desc-wrap">
{{ localMemberAddress.full_address ? localMemberAddress.full_address : '' }}
{{ localMemberAddress.address ? localMemberAddress.address : '' }}
</view>
</view>
<text class="cell-more iconfont icon-right"></text>
</view>
<view class="local-box" v-if="calculateGoodsData.config.local && calculateGoodsData.delivery.local.info.time_is_open == 1">
<view class="pick-block" @click="localtime('')">
<view class="title font-size-base">送达时间</view>
<view class="time-picker">
<text :class="{ 'color-tip': !deliveryTime }">{{ deliveryTime ? deliveryTime : '请选择送达时间' }}</text>
<text class="iconfont icon-right cell-more"></text>
</view>
</view>
</view>
</view>
<view class="empty-wrap" v-else @click="selectAddress">
<view class="info">请设置收货地址</view>
<view class="cell-more">
<view class="iconfont icon-right"></view>
</view>
</view>
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')"></image>
</view>
<!-- 门店信息 -->
<view class="store-box" :class="{ 'not-delivery-type': goodsData.delivery.express_type.length <= 1 }" v-if="orderCreateData.delivery.delivery_type == 'store'">
<block v-if="storeInfo">
<view @click="openPopup('deliveryPopup')" class="store-info">
<view class="store-address-info">
<view class="info-wrap">
<view class="title">
<text>{{ storeInfo.store_name }}</text>
</view>
<view class="store-detail">
<view v-if="storeInfo.open_date">营业时间{{ storeInfo.open_date }}</view>
<view class="address">{{ storeInfo.full_address }} {{ storeInfo.address }}
</view>
</view>
</view>
<view class="cell-more iconfont icon-right" v-if="storeList && Object.keys(storeList).length > 1"></view>
</view>
</view>
<view class="mobile-wrap store-mobile" v-if="orderCreateData.member_address">
<view class="form-group">
<text class="text">姓名</text>
<input type="text" placeholder-class="color-tip placeholder" class="input" disabled v-model="orderCreateData.member_address.name" />
</view>
</view>
<view class="mobile-wrap store-mobile" v-if="orderCreateData.member_address">
<view class="form-group">
<text class="text">预留手机</text>
<input type="number" maxlength="11" placeholder="请输入您的手机号码" placeholder-class="color-tip placeholder" class="input" v-model="orderCreateData.member_address.mobile" />
</view>
</view>
<view class="store-time" @click="storetime('')">
<view class="left">提货时间</view>
<view class="right">
{{ deliveryTime }}
<text class="iconfont icon-right"></text>
</view>
</view>
</block>
<view v-else class="empty">当前无自提门店请选择其它配送方式</view>
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')"></image>
</view>
</template>
<!-- 店铺 -->
<view class="site-wrap order-goods" v-if="calculateGoodsData">
<view class="site-header">
<view class="iconfont icon-dianpu"></view>
<text class="site-name">门店</text>
</view>
<view class="site-body">
<!-- 商品 -->
<view class="goods-item" v-for="(goodsItem, goodsIndex) in 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"/>
</view>
<view class="goods-info">
<view class="top-wrap">
<view @click="$util.redirectTo('/pages/goods/detail', { goods_id: goodsItem.goods_id })" class="goods-name">{{ goodsItem.sku_name }}</view>
<view class="sku" v-if="goodsItem.sku_spec_format">
<view class="goods-spec">
<block v-for="(x, i) in goodsItem.sku_spec_format" :key="i">
<view>{{ x.spec_value_name }}</view>
</block>
</view>
</view>
<block v-if="goodsItem.is_virtual == 0">
<view class="error-tips" v-if="orderCreateData.delivery &&
orderCreateData.delivery.delivery_type &&
goodsItem.support_trade_type &&
goodsItem.support_trade_type.indexOf(orderCreateData.delivery.delivery_type) == -1
">
<text class="iconfont icon-gantanhao"></text>
<text>该商品不支持{{ orderCreateData.delivery.delivery_type_name }}</text>
</view>
</block>
<view class="error-tips" v-if="goodsItem.error && goodsItem.error.message">
<text class="iconfont icon-gantanhao"></text>
<text>{{ goodsItem.error.message }}</text>
</view>
</view>
<view class="goods-sub-section">
<view class="color-base-text">
<text class="unit price-style small">{{ $lang('common.currencySymbol') }}</text>
<text class="goods-price price-style large">{{ parseFloat(goodsItem.price).toFixed(2).split('.')[0] }}</text>
<text class="unit price-style small">.{{ parseFloat(goodsItem.price).toFixed(2).split('.')[1] }}</text>
</view>
<view>
<text class="font-size-tag">x</text>
<text class="font-size-base">{{ goodsItem.num }}</text>
</view>
</view>
</view>
</view>
<view class="member-goods-card order-cell" v-if="calculateGoodsData.goods_list[goodsIndex].member_card_list" @click="selectMemberGoodsCard(goodsIndex)">
<text class="tit">次卡抵扣</text>
<view class="box text-overflow">
<block v-if="calculateGoodsData.goods_list[goodsIndex].card_promotion_money">
<text class="text">次卡抵扣{{ calculateGoodsData.goods_list[goodsIndex].card_use_num }}张/{{ calculateGoodsData.goods_list[goodsIndex].card_use_num }}次</text>
<text class="price-font">-¥{{ calculateGoodsData.goods_list[goodsIndex].card_promotion_money | moneyFormat }}</text>
</block>
<text class="color-tip" v-else>请选择次卡</text>
</view>
<text class="iconfont icon-right"></text>
</view>
<view class="goods-form" v-if="goodsData.goods_list[goodsIndex].goods_form" @click="editForm(goodsIndex)">
<ns-form :data="goodsData.goods_list[goodsIndex].goods_form.json_data" ref="goodsForm" :custom-attr="{ sku_id: goodsItem.sku_id, form_id: goodsData.goods_list[goodsIndex].goods_form.id }"/>
<text class="cell-more iconfont icon-right"></text>
<view class="shade"></view>
</view>
</view>
</view>
</view>
<view class="site-wrap buyer-message">
<view class="order-cell">
<text class="tit">买家留言</text>
<view class="box text-overflow " @click="openPopup('buyerMessagePopup')">
<text v-if="orderCreateData.buyer_message">{{ orderCreateData.buyer_message }}</text>
<text class="color-sub" v-else>无留言</text>
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
<view v-if="paymentData.system_form" class="system-form-wrap">
<view class="order-cell">
<text class="tit">{{ paymentData.system_form.form_name }}</text>
</view>
<ns-form :data="paymentData.system_form.json_data" ref="form"/>
</view>
<view class="site-wrap" v-if="calculateGoodsData || promotionInfo || (calculateGoodsData && calculateGoodsData.max_usable_point > 0) || goodsData.invoice">
<view class="site-footer">
<view class="order-cell coupon" v-if="modules.indexOf('coupon') != -1">
<text class="tit">优惠券</text>
<view class="box text-overflow" @click="openPopup('couponPopup')">
<template v-if="orderCreateData.coupon && orderCreateData.coupon.coupon_id">
<text>已使用优惠券,优惠</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ (calculateData && calculateData.coupon_money ? calculateData.coupon_money : 0) | moneyFormat }}</text>
</template>
<text v-else>不使用优惠券</text>
</view>
<text class="iconfont icon-right"></text>
</view>
<view class="order-cell" v-if="promotionInfo">
<text class="tit">活动优惠</text>
<view class="box text-overflow" @click="openPopup('promotionPopup')">
<text>{{ promotionInfo.title }}</text>
</view>
<text class="iconfont icon-right"></text>
</view>
<view class="order-cell point" v-if="calculateGoodsData && calculateGoodsData.max_usable_point > 0">
<text class="tit">
<text>使用{{ parseInt(calculateGoodsData.max_usable_point) }}积分可抵扣</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ calculateData.point_money | moneyFormat }}</text>
</text>
<view class="box"></view>
<ns-switch class="balance-switch" @change="usePoint" :checked="orderCreateData.is_point == 1"/>
</view>
<view class="order-cell order-invoice-cell" v-if="goodsData.invoice.invoice_status == 1">
<text class="tit">发票</text>
<view class="box text-overflow" @click="openPopup('invoicePopup')">
<text v-if="orderCreateData.is_invoice == 1">{{ orderCreateData.invoice_type == 1 ? '纸质' : '电子' }}发票({{ orderCreateData.invoice_content }})</text>
<text v-else>无需发票</text>
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
</view>
<view class="site-wrap box member-card-wrap" v-if="paymentData.recommend_member_card && Object.keys(paymentData.recommend_member_card).length > 0">
<view class="head" @click="selectMemberCard">
<text class="iconfont icon-huiyuan"></text>
<view class="info">
开通{{ paymentData.recommend_member_card.level_name }}
<text>本单预计可省</text>
<text class="price-color">{{ paymentData.recommend_member_card.discount_money | moneyFormat }}</text>
<text>元</text>
</view>
<text class="iconfont" :class="orderCreateData.is_open_card == 1 ? 'icon-yuan_checked color-base-text' : 'icon-yuan_checkbox'"></text>
</view>
<view class="body" v-if="orderCreateData.is_open_card">
<view class="item" :class="{ 'active color-base-border': item.key == orderCreateData.member_card_unit }" v-for="(item, index) in cardChargeType" :key="index" @click="selectMembercardUnit(item.key)">
<view class="title">{{ item.title }}</view>
<view class="price price-font">{{ $lang('common.currencySymbol') }}{{ parseFloat(item.value) }}/{{ item.unit }}</view>
<text class="iconfont icon-icon color-base-text price-font identify" v-if="item.key == orderCreateData.member_card_unit"></text>
</view>
</view>
</view>
<!-- 订单金额 -->
<template v-if="calculateData">
<view class="order-money">
<view class="order-cell">
<text class="tit">商品金额</text>
<view class="box">
<text class="unit color-title price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money color-title price-font">{{ calculateData.goods_money | moneyFormat }}</text>
</view>
</view>
<view class="order-cell" v-if="calculateData.is_virtual == 0 && calculateData.delivery_money > 0">
<text class="tit">运费</text>
<view class="box color-base-text">
<text class="operator">+</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ calculateData.delivery_money | moneyFormat }}</text>
</view>
</view>
<view class="order-cell" v-if="orderCreateData.is_invoice && calculateData.invoice_money > 0">
<text class="tit">
<text>税费</text>
<text class="color-base-text font-bold price-font">({{ goodsData.invoice.invoice_rate }}%)</text>
</text>
<view class="box color-base-text">
<text class="operator">+</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ calculateData.invoice_money | moneyFormat }}</text>
</view>
</view>
<view class="order-cell" v-if="orderCreateData.is_invoice && calculateData.invoice_delivery_money > 0">
<text class="tit">发票邮寄费</text>
<view class="box color-base-text">
<text class="operator">+</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ calculateData.invoice_delivery_money | moneyFormat }}</text>
</view>
</view>
<view class="order-cell" v-if="calculateData.promotion_money > 0">
<text class="tit">优惠</text>
<view class="box color-base-text">
<text class="operator">-</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ calculateData.promotion_money | moneyFormat }}</text>
</view>
</view>
<view class="order-cell" v-if="calculateData.coupon_money">
<text class="tit">优惠券</text>
<view class="box color-base-text">
<text class="operator">-</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ calculateData.coupon_money | moneyFormat }}</text>
</view>
</view>
<view class="order-cell" v-if="calculateData.point_money > 0">
<text class="tit">积分抵扣</text>
<view class="box color-base-text">
<text class="operator">-</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ calculateData.point_money | moneyFormat }}</text>
</view>
</view>
<view class="order-cell" v-if="calculateData.member_card_money > 0">
<text class="tit">会员卡</text>
<view class="box color-base-text">
<text class="operator">+</text>
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class="money price-font">{{ calculateData.member_card_money | moneyFormat }}
</text>
</view>
</view>
</view>
<view v-if="transactionAgreement.title && transactionAgreement.content" class="agreement">购买前请先阅读<text @click="$refs.agreementPopup.open()">《{{ transactionAgreement.title }}》</text>,下单即代表同意该协议</view>
<view class="order-submit bottom-safe-area">
<view class="order-settlement-info">
<text class="font-size-base color-tip margin-right">共{{ calculateData.goods_num }}件</text>
<text class="font-size-base">合计:</text>
<text class=" unit price-font">{{ $lang('common.currencySymbol') }}</text>
<text class=" money price-font">{{ parseFloat(calculateData.pay_money).toFixed(2).split('.')[0] }}</text>
<text class=" unit price-font">.{{ parseFloat(calculateData.pay_money).toFixed(2).split('.')[1] }}</text>
</view>
<view class="submit-btn">
<button type="primary" class="mini" size="mini" @click="create()" v-if="!surplusStartMoney()">提交订单</button>
<button v-else class="no-submit mini" size="mini">差{{ surplusStartMoney() | moneyFormat }}起送</button>
</view>
</view>
<view class="order-submit-block"></view>
<payment ref="choosePaymentPopup" @close="payClose" v-if="calculateData"></payment>
</template>
<!-- 活动优惠弹窗 -->
<uni-popup ref="promotionPopup" type="bottom" v-if="promotionInfo">
<view class="promotion-popup popup">
<view class="popup-header">
<text class="tit">活动优惠</text>
<text class="iconfont icon-close" @click="closePopup('promotionPopup')"></text>
</view>
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
<view class="order-cell" style="align-items: baseline;">
<view class="tit">
<text class="promotion-mark ns-gradient-promotionpages-payment">{{ promotionInfo.title }}
</text>
</view>
<view class="promotion-content">
<view class="tit tit-content" style="white-space: pre-line;" v-html="promotionInfo.content"></view>
</view>
</view>
</scroll-view>
<view class="popup-footer" :class="{ 'bottom-safe-area': isIphoneX }">
<view class="confirm-btn color-base-bg" @click="closePopup('promotionPopup')">确定</view>
</view>
</view>
</uni-popup>
<!-- 门店列表弹窗 -->
<uni-popup ref="deliveryPopup" type="bottom">
<view class="delivery-popup popup">
<view class="popup-header">
<text class="tit">已为您甄选出附近所有相关门店</text>
<text class="iconfont icon-close" @click="closePopup('deliveryPopup')"></text>
</view>
<view class="popup-body store-popup" :class="{ 'safe-area': isIphoneX }">
<mescroll-uni @getData="getStore" ref="mescroll" top="50px">
<block slot="list">
<view class="delivery-content">
<block v-if="storeData">
<view class="item-wrap" v-for="(item, index) in storeData" :key="index" @click="selectPickupPoint(item)">
<view class="detail">
<view class="name" :class="item.store_id == orderCreateData.delivery.store_id ? 'color-base-text' : ''">
<text>{{ item.store_name }}</text>
<text v-if="item.distance">({{ item.distance }}km)</text>
</view>
<view class="info">
<view :class="item.store_id == orderCreateData.delivery.store_id ? 'color-base-text' : ''" class="font-size-goods-tag">营业时间:{{ item.open_date }}</view>
<view :class="item.store_id == orderCreateData.delivery.store_id ? 'color-base-text' : ''" class="font-size-goods-tag">地址:{{ item.full_address }}{{ item.address }}</view>
</view>
</view>
<view class="icon" v-if="item.store_id == orderCreateData.delivery.store_id">
<text class="iconfont icon-yuan_checked color-base-text"></text>
</view>
</view>
</block>
<view v-else class="empty-wrap">
<ns-empty text="所选择收货地址附近没有可以自提的门店" :isIndex="false"></ns-empty>
</view>
</view>
</block>
</mescroll-uni>
</view>
</view>
</uni-popup>
<!-- 留言弹窗 -->
<uni-popup ref="buyerMessagePopup" type="bottom">
<view style="height: auto;" class="buyermessag-popup popup" @touchmove.prevent.stop>
<view class="popup-header">
<text class="tit">买家留言</text>
<text class="iconfont icon-close" @click="closePopup('buyerMessagePopup')"></text>
</view>
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
<view>
<view class="buyermessag-cell">
<view class="buyermessag-form-group">
<textarea type="text" maxlength="100" placeholder="留言前建议先与商家协调一致" placeholder-class="color-tip" v-model="orderCreateData.buyer_message"/>
</view>
</view>
</view>
</scroll-view>
<view class="popup-footer" @click="saveBuyerMessage" :class="{ 'bottom-safe-area': isIphoneX }">
<view class="confirm-btn color-base-bg">确定</view>
</view>
</view>
</uni-popup>
<!-- 优惠券弹窗 -->
<uni-popup ref="couponPopup" type="bottom" v-if="calculateGoodsData" :mask-click="false">
<view class="coupon-popup popup" @touchmove.prevent.stop>
<view class="popup-header">
<text class="tit">优惠券</text>
<text class="iconfont icon-close" @click="closePopup('couponPopup')"></text>
</view>
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
<view v-if="coupon_list.length > 0">
<view class="coupon-item" v-for="(couponItem, couponIndex) in coupon_list" :key="couponIndex" @click="selectCoupon(couponItem)">
<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')"/>
<view class="coupon-money">
<template v-if="couponItem.type == 'divideticket'">
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
<text class="money">{{ parseFloat(couponItem.money) }}</text>
</template>
<template v-else-if="couponItem.type == 'reward'">
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
<text class="money">{{ parseFloat(couponItem.money) }}</text>
</template>
<template v-else-if="couponItem.type == 'discount'">
<text class="money">{{ parseFloat(couponItem.discount) }}</text>
<text class="unit">折</text>
</template>
<view class="at-least">
<template v-if="couponItem.at_least > 0">
满{{ couponItem.at_least }}可用
</template>
<template v-else>
无门槛
</template>
</view>
</view>
</view>
<view class="desc-wrap">
<view class="coupon-name">{{ couponItem.coupon_name }}</view>
<view v-if="couponItem.type == 'discount' && couponItem.discount_limit > 0" class="limit">最多可抵¥{{ couponItem.discount_limit }}</view>
<view class="time font-size-goods-tag">有效期:{{ couponItem.end_time ? $util.timeStampTurnTime(couponItem.end_time) : '长期有效' }}</view>
</view>
<view class="iconfont" :class="orderCreateData.coupon.coupon_id == couponItem.coupon_id ? 'icon-yuan_checked color-base-text' : 'icon-yuan_checkbox'"></view>
</view>
</view>
</view>
<view v-else class="coupon-empty">暂无可用的优惠券</view>
</scroll-view>
<view class="popup-footer" :class="{ 'bottom-safe-area': isIphoneX }">
<view class="confirm-btn color-base-bg" @click="useCpopon">确定</view>
</view>
</view>
</uni-popup>
<!-- 交易协议 -->
<view @touchmove.prevent>
<uni-popup ref="agreementPopup" type="center" :maskClick="false">
<view class="agreement-conten-box">
<view class="close">
<text class="iconfont icon-close" @click="$refs.agreementPopup.close()"></text>
</view>
<view class="title">{{ transactionAgreement.title }}</view>
<view class="con">
<scroll-view scroll-y="true" class="con">
<rich-text :nodes="transactionAgreement.content"></rich-text>
</scroll-view>
</view>
</view>
</uni-popup>
</view>
<!-- 表单修改弹窗 -->
<uni-popup ref="editFormPopup" type="bottom">
<view style="height: auto;" class="form-popup popup" @touchmove.prevent.stop>
<view class="popup-header">
<text class="tit">买家信息</text>
<text class="iconfont icon-close" @click="$refs.editFormPopup.close()"></text>
</view>
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
<ns-form v-if="tempFormData" :data="tempFormData.json_data" ref="tempForm"></ns-form>
</scroll-view>
<view class="popup-footer" @click="saveForm" :class="{ 'bottom-safe-area': isIphoneX }">
<view class="confirm-btn color-base-bg">确定</view>
</view>
</view>
</uni-popup>
<uni-popup ref="memberGoodsCardPopup" type="bottom">
<view class="member-card-popup popup" @touchmove.prevent.stop>
<view class="popup-header">
<text class="tit">选择次卡</text>
<text class="iconfont icon-close" @click="$refs.memberGoodsCardPopup.close()"></text>
</view>
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
<view v-for="(item, index) in selectGoodsCard.cardList" class="card-item" @click="selectGoodsCard.click(item.item_id)">
<view class="content">
<view class="title">{{ item.goods_name }}</view>
<view class="info">
<text v-if="item.card_type == 'timecard'">不限次数</text>
<text v-if="item.card_type == 'oncecard'">剩余{{ item.num - item.use_num }}次</text>
<text v-if="item.card_type == 'commoncard'">剩余{{ item.total_num - item.total_use_num }}次</text>
<text>|</text>
<text>{{ item.end_time ? $util.timeStampTurnTime(item.end_time) : '长期有效' }}</text>
</view>
</view>
<view class="iconfont" :class="selectGoodsCard.itemId == item.item_id ? 'icon-yuan_checked color-base-text' : 'icon-yuan_checkbox'"></view>
</view>
</scroll-view>
<view class="popup-footer" @click="saveMemberGoodsCard" :class="{ 'bottom-safe-area': isIphoneX }">
<view class="confirm-btn color-base-bg">确定</view>
</view>
</view>
</uni-popup>
</template>
</scroll-view>
<!-- 门店自提时间 -->
<ns-select-time @selectTime="selectPickupTime" ref="timePopup"></ns-select-time>
<ns-login ref="login"></ns-login>
<loading-cover ref="loadingCover"></loading-cover>
</view>
</template>
<script>
import payment from './payment.js';
export default {
name: 'common-payment',
data() {
return {};
},
props: {
api: Object,
createDataKey: String
},
mixins: [payment]
};
</script>
<style lang="scss">
@import '@/common/css/order_parment.scss';
.order-cell .promotion-content {
flex: 1;
}
</style>

View File

@@ -169,12 +169,12 @@
<!-- 商品 -->
<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 })">
<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"/>
</view>
<view class="goods-info">
<view class="top-wrap">
<view @click="$util.redirectTo('/pages_goods/detail', { goods_id: goodsItem.goods_id })" class="goods-name">{{ goodsItem.sku_name }}</view>
<view @click="$util.redirectTo('/pages/goods/detail', { goods_id: goodsItem.goods_id })" class="goods-name">{{ goodsItem.sku_name }}</view>
<view class="sku" v-if="goodsItem.sku_spec_format">
<view class="goods-spec">
<block v-for="(x, i) in goodsItem.sku_spec_format" :key="i">
@@ -603,9 +603,9 @@
<text class="iconfont icon-close" @click="$refs.memberGoodsCardPopup.close()"></text>
</view>
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
<view v-for="(item, index) in selectGoodsCard.cardList" :key="index" class="card-item" @click="selectGoodsCard.click(item.item_id)">
<view v-for="(item, index) in selectGoodsCard.cardList" class="card-item" @click="selectGoodsCard.click(item.item_id)">
<view class="content">
<view class="title">{{ isEnEnv ? item.en_goods_name : item.goods_name }}</view>
<view class="title">{{ item.goods_name }}</view>
<view class="info">
<text v-if="item.card_type == 'timecard'">不限次数</text>
<text v-if="item.card_type == 'oncecard'">剩余{{ item.num - item.use_num }}次</text>
@@ -636,8 +636,6 @@
<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)
}
}
@@ -922,7 +922,7 @@ export default {
payClose() {
// 更新购物车数量
this.$store.dispatch('getCartNumber');
this.$util.redirectTo('/pages_order/detail', {
this.$util.redirectTo('/pages/order/detail', {
order_id: this.$refs.choosePaymentPopup.payInfo.order_id
}, 'redirectTo');
},

View File

@@ -0,0 +1,211 @@
<template>
<x-skeleton data-component-name="diy-article" type="list" :loading="loading" :configs="skeletonConfig">
<view class="article-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" @click="toDetail(item)" :style="itemCss">
<view class="article-img">
<image class="cover-img" :src="$util.img(item.cover_img)" mode="widthFix" @error="imgError(index)" />
</view>
<view class="info-wrap">
<text class="title">{{ item.article_title }}</text>
<text class="desc" style="color:#888;font-size: 24rpx; display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;text-overflow: ellipsis;">{{ item.article_abstract }}</text>
<view class="read-wrap">
<block v-if="item.category_name">
<text class="category-icon"></text>
<text>{{ item.category_name }}</text>
</block>
<text class="date">{{ $util.timeStampTurnTime(item.create_time, 'date') }}</text>
</view>
</view>
</view>
</view>
</view>
</x-skeleton>
</template>
<script>
// 文章
export default {
name: 'diy-article',
props: {
value: {
type: Object
}
},
data() {
return {
list: [],
loading: true,
skeletonConfig: {
gridRows: 1,
gridRowsGap: '40rpx',
headWidth: '160rpx',
headHeight: '160rpx',
textRows: 2
}
};
},
created() {
this.getList();
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getList();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
},
// 子项样式
itemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color;
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color;
}
return obj;
}
},
methods: {
getList() {
var data = {
num: this.value.count
};
if (this.value.sources == 'diy') {
data.num = 0;
data.article_id_arr = this.value.articleIds.toString();
}
this.$api.sendRequest({
url: '/api/article/lists',
data: data,
success: res => {
if (res.code == 0 && res.data) {
let data = res.data;
this.list = data;
}
this.loading = false;
}
});
},
toDetail(item) {
this.$util.redirectTo('/pages_tool/article/detail', {
article_id: item.article_id
});
},
imgError(index) {
if (this.list[index]) this.list[index].cover_img = this.$util.getDefaultImage().article;
}
}
};
</script>
<style lang="scss">
.article-wrap {
.list-wrap {
&.style-1 {
.item {
display: flex;
padding: 20rpx;
margin-top: 24rpx;
&:first-of-type {
margin-top: 0;
}
.article-img {
margin-right: 20rpx;
width: 160rpx;
height: 160rpx;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
image {
width: 100%;
}
}
.info-wrap {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
font-weight: bold;
margin-bottom: 10rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: 30rpx;
line-height: 1.5;
}
.abstract {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: $font-size-tag;
}
.read-wrap {
display: flex;
color: #999ca7;
justify-content: flex-start;
align-items: center;
margin-top: 10rpx;
line-height: 1;
text {
font-size: $font-size-tag;
}
.iconfont {
font-size: 36rpx;
vertical-align: bottom;
margin-right: 10rpx;
}
.category-icon {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: $base-color;
margin-right: 10rpx;
}
.date {
margin-left: 20rpx;
}
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,444 @@
<template>
<view data-component-name="diy-audio">
<view class="fui-audio style1" :style="{background:value.background}" v-if="value.type == 'style-2'">
<view class="content" style="padding-top: 20rpx;">
<view class="name" :style="{color:value.textcolor}">{{value.text}}</view>
<view class="author" :style="{color:value.subtitlecolor}">{{value.desc}}----{{value.id}}</view>
</view>
<view class="progress">
<view class="progressBar" :style="{width:audiowidth}"></view>
</view>
<view class="time" :style="{color:value.timecolor}">
{{audiotime}}
</view>
<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)"></image>
</view>
<view class="content">
<view class="name" :style="{color:value.textcolor}">{{value.text}}</view>
<view class="author" :style="{color:value.subtitlecolor}">{{value.desc}}</view>
</view>
<view class="progress">
<view class="progressBar" :style="{width:audiowidth}"></view>
</view>
<view class="time" :style="{color:value.timecolor}">
<!-- {{audios[value.id].audiotime}} -->
{{audiotime}}
</view>
<view @click="play()" class="start" :class="status?'iconj icon-07zanting':'iconj icon-bofang'"></view>
</view>
</view>
</template>
<script>
// 视频
export default {
name: 'diy-audio',
props: {
value: {
type: Object
}
},
data() {
return {
audiosObj:[],
audios: {},
audioContext:null,
audiotime:'00:01',
audiowidth:0,
status:0,//1播放0停止
};
},
created() {
// console.log(this.value)
this.audios[this.value.id] = {
audiotime:'00:01',
audiowidth:0
}
},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {}
},
computed: {
videoWarpCss: function() {
var obj = '';
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;
}
},
methods: {
play(){
var t = this.value.id, a = this.audiosObj[t] || !1;
var e = {
audio:this.$util.img(this.value.audioUrl),
}
if (!a) {
a = uni.createInnerAudioContext("audio_" + t);
var i = this.audiosObj;
i[t] = a, this.audiosObj = i
// uni.setStorageSync('audio_list',audio_list)
var audio_list = uni.getStorageSync('audio_list')?uni.getStorageSync('audio_list'):[]
if(audio_list.includes(t) == false){
audio_list.push(t)
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);
s < 10 && (s = "0" + s);
var u = s + ":" + o, c = n.audios;
// console.log(i)
c[t].audiowidth = i, c[t].Time = e, c[t].audiotime = u, c[t].seconds = r, n.audios = c;
}, 1e3);
});
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,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;
// console.log(this.audiosObj[this.value.id]);
var i = this.audiosObj[this.value.id],a = this.value.id
// console.log(i)
// console.log(a)
// if (a != e) {
// i.pause();
// var n = t.audios;
// n[a] && (n[a].status = !1, this.audios=n);
// }
var audios = document.getElementsByTagName("audio");
// 暂停函数
function pauseAll() {
var self = this;
[].forEach.call(audios, function (i) {
// 将audios中其他的audio全部暂停
i !== self && i.pause();
})
}
// 给play事件绑定暂停函数
[].forEach.call(audios, function (i) {
i.addEventListener("play", pauseAll.bind(i));
})
// var audio_list = uni.getStorageSync('audio_list')
// audio_list.forEach(function(value, index) {
// if (value != e) {
// console.log(e)
// uni.createInnerAudioContext("audio_" + value).pause();
// }
// });
// this.audiosObj.forEach(function(value, index) {
// console.log(value);
// });
// this.each(this.audiosObj, function(a, i) {
// if (a != e) {
// i.pause();
// var n = t.data.audios;
// n[a] && (n[a].status = !1, t.setData({
// audios: n
// }));
// }
// });
},
play_bak(){
var t = this.value.id
this.audioContext = uni.createInnerAudioContext("audio_" + this.value.id);
this.audioContext.src = this.$util.img(this.value.audioUrl);
var that = this
if(this.status == 1){
this.audioContext.pause();
this.status = 0
return false
}
this.audioContext.play();
this.status = 1
this.audioContext.onCanplay(function(s){
var e = setInterval(function() {
var i = parseFloat(that.audioContext.currentTime) / parseFloat(that.audioContext.duration) * 100 + "%", s = Math.floor(Math.ceil(that.audioContext.currentTime) / 60), o = (Math.ceil(that.audioContext.currentTime) % 60 / 100).toFixed(2).slice(-2), r = Math.ceil(that.audioContext.currentTime);
s < 10 && (s = "0" + s);
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
});
}
}
};
</script>
<style scoped>
.fui-audio {
width: 100%;
border: 1rpx solid #eeeeee;
padding: 0 30rpx 0 20rpx;
box-sizing: border-box;
position: relative;
overflow: hidden;
background: #fff;
}
.fui-audio .img {
width: 100rpx;
height: 100rpx;
background: #000;
}
.fui-audio .img image {
width: 100%;
height: 100%;
}
.fui-audio .name {
font-size: 26rpx;
color: #333;
}
.fui-audio .author {
font-size: 26rpx;
color: #666;
}
.fui-audio .time {
font-size: 24rpx;
color: #999;
}
.fui-audio .start {
border: 0;
padding: 0;
margin: 0;
font-size: 28rpx;
}
.progressBar {
height: 2rpx;
width: 0;
background: #333;
}
.fui-audio.style1 {
height: 86rpx;
line-height: 82rpx;
}
.fui-audio.style1 .img,.fui-audio.style2 .img {
display: none;
}
.fui-audio.style1 .name,.fui-audio.style2 .name {
float: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 300rpx;
}
.fui-audio.style1 .author,.fui-audio.style2 .author {
float: left;
margin-left: 12rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200rpx;
}
.fui-audio.style1 .time,.fui-audio.style4 .time {
display: none;
}
.fui-audio.style1 .start {
position: absolute;
top: 0rpx;
right: 40rpx;
width: 40rpx;
height: 40rpx;
color: #000;
}
.fui-audio.style1 .progress {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
.fui-audio.style2 {
height: 86rpx;
line-height: 82rpx;
}
.fui-audio.style2 .img {
display: none;
}
.fui-audio.style2 .time {
position: absolute;
top: 0;
right: 30rpx;
}
.fui-audio.style2 .name {
margin-left: 70rpx;
}
.fui-audio.style2 .start {
position: absolute;
top: 0rpx;
left: 30rpx;
width: 30rpx;
height: 30rpx;
color: #000;
}
.fui-audio.style2 .progress,.fui-audio.style3 .progress {
display: none;
}
.fui-audio.style3 {
padding: 8rpx;
}
.fui-audio.style3 .start {
position: absolute;
top: 30rpx;
left: 28rpx;
width: 56rpx;
height: 56rpx;
color: #fff;
/* border: 2rpx solid #fff; */
border-radius: 50%;
text-indent: 18rpx;
line-height: 56rpx;
}
.fui-audio.style3 .img,.fui-audio.style4 .img {
float: left;
margin-right: 20rpx;
}
.fui-audio.style3 .content {
width: 468rpx;
}
.fui-audio.style3 .content,.fui-audio.style4 .content {
float: left;
height: 100rpx;
display: flex;
flex-direction: column;
justify-content: center;
}
.fui-audio.style3 .content .name {
height: 40rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fui-audio.style3 .content .author {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fui-audio.style3 .time {
position: absolute;
top: 40rpx;
right: 30rpx;
}
.fui-audio.style4 {
padding: 10rpx;
}
.fui-audio.style4 .content {
padding-bottom: 18rpx;
height: 82rpx;
width: 500rpx;
}
.fui-audio.style4 .start {
position: absolute;
top: 32rpx;
right: 30rpx;
width: 30rpx;
height: 30rpx;
color: #000;
}
.fui-audio.style4 .name {
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fui-audio.style4 .author {
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fui-audio.style4 .progress {
background: #f5f5f5;
height: 4rpx;
position: absolute;
bottom: 24rpx;
left: 130rpx;
right: 30rpx;
border-radius: 2rpx;
overflow: hidden;
}
.fui-audio.style4 .progressBar {
height: 4rpx;
}
.diy-audio>>>.uni-video-container {
background-color: transparent;
}
</style>

View File

@@ -0,0 +1,723 @@
<template>
<x-skeleton data-component-name="diy-bargain" :type="skeletonType" :loading="loading" :configs="skeletonConfig">
<view class="diy-bargain" :class="[value.template, value.style]" :style="warpCss">
<!-- 商品头部 -->
<view v-if="value.titleStyle.isShow && list && list.length" :class="[value.titleStyle.style, 'bargain-head']" :style="{ backgroundImage: 'url(' + $util.img(value.titleStyle.backgroundImage) + '), linear-gradient(to right,' + value.titleStyle.bgColorStart + ',' + value.titleStyle.bgColorEnd + ')' }">
<view v-if="value.titleStyle.leftStyle == 'text'" class="left-text" :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"></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 }" @click="$util.redirectTo('/pages_promotion/bargain/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" @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)"/>
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.btnStyle.control">
<view v-if="value.goodsNameStyle.control" class="goods-name" :style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }" :class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ item.goods_name }}
</view>
<view class="progress" v-if="value.style == 'style-2'">
<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')"/>
</view>
</view>
<view class="num" v-if="item.is_bargaining">
已砍
<text>{{ (item.price - item.curr_price).toFixed(2) }}</text>
仅差
<text>{{ item.curr_price }}</text>
</view>
<view class="num" v-else>
最低可砍至
<text>{{ item.floor_price }}</text>
</view>
</view>
<view class="progress" v-if="value.style == 'style-3'">
最低可砍至
<text class="num">{{ item.floor_price }}</text>
</view>
<view class="price-wrap">
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ item.price.split('.')[0] }}</text>
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">.{{ item.price.split('.')[1] }}</text>
</view>
<button v-if="value.btnStyle.control" :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'
}">
{{ item.is_bargaining ? '继续砍价' : value.btnStyle.text }}
</button>
</view>
</view>
</view>
</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" @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"/>
<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"/>
<view class="num" v-if="value.saleStyle.control && value.template == 'horizontal-slide' && value.style != 'style-2'" :style="{ color: value.theme == 'diy' ? value.saleStyle.color : '' }">
已砍{{ item.sale_num }}
</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl">
<view v-if="value.goodsNameStyle.control" class="goods-name" :style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }" :class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ item.goods_name }}
</view>
<view class="discount-price"
v-if="value.priceStyle.mainControl && value.template == 'horizontal-slide' && value.style != 'style-2'">
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ item.floor_price.split('.')[0] }}</text>
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ '.' + item.floor_price.split('.')[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl" :style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">
¥{{ item.price }}
</view>
</view>
</view>
</scroll-view>
<swiper v-if="value.slideMode == 'slide'" :autoplay="false" class="swiper" :style="{ height: swiperHeight }">
<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" @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"/>
<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"/>
<view class="num" v-if="value.saleStyle.control && value.template == 'horizontal-slide' && value.style != 'style-2'" :style="{ color: value.theme == 'diy' ? value.saleStyle.color : '' }">
已砍{{ item.sale_num }}
</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]" v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl">
<view v-if="value.goodsNameStyle.control" class="goods-name" :style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }" :class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl && value.template == 'horizontal-slide' && value.style != 'style-2'">
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ item.floor_price.split('.')[0] }}</text>
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ '.' + item.floor_price.split('.')[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl" :style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">
¥{{ item.price }}
</view>
</view>
</view>
</swiper-item>
</swiper>
</template>
</view>
</x-skeleton>
</template>
<script>
export default {
name: 'diy-bargain',
props: {
value: {
type: Object
}
},
data() {
return {
list: [],
page: 1,
loading: true,
skeletonType: '',
skeletonConfig: {}
};
},
components: {},
async created() {
this.initSkeleton();
if (this.value.template == 'row1-of1' && this.value.style == 'style-2') await this.getDataing();
this.getData();
},
watch: {
// 组件刷新监听
componentRefresh: async function(nval) {
if (this.value.template == 'row1-of1' && this.value.style == 'style-2') await this.getDataing();
this.getData();
}
},
computed: {
warpCss() {
var obj = '';
if (this.value.componentBgColor) obj += 'background:' + this.value.componentBgColor + ';';
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;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color + ';';
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color + ';';
}
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(this
.value.goodsMarginNum * 2);
else width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this.rpxUpPx(this.value
.margin.both * 2) * 2] / 6;
obj += 'margin-left:' + width + 'px;';
obj += 'margin-right:' + width + 'px;';
}
return obj;
},
swiperHeight() {
if (this.value.nameLineMode == 'multiple') {
if (this.value.ornament.type == 'shadow') return '420rpx';
else return '400rpx';
}
if (this.value.ornament.type == 'shadow') return '386rpx';
else return '378rpx';
}
},
methods: {
initSkeleton() {
if (this.value.template == 'row1-of1') {
// 单列 风格
this.skeletonType = 'list';
this.skeletonConfig = {
textRows: 2
};
} else if (this.value.template == 'horizontal-slide') {
// 横向滑动 风格
this.skeletonType = 'waterfall';
this.skeletonConfig = {
gridRows: 1,
gridColumns: 3,
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '80%']
};
}
},
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
// 查找自己参与的砍价
async getDataing() {
var res = await this.$api.sendRequest({
url: '/bargain/api/goods/bargainingList',
data: {},
async: false
});
res.data &&
res.data.forEach((item, index) => {
item.is_bargaining = 1;
});
this.list = res.data || [];
this.loading = false;
},
// 查找可砍价的商品
getData() {
var data = {
num: this.value.count,
is_exclude_bargaining: 1
};
if (this.value.sources == 'diy') {
data.num = 0;
data.id_arr = this.value.goodsId.toString();
}
this.$api.sendRequest({
url: '/bargain/api/goods/lists',
data: data,
success: res => {
if (res.code == 0) {
if (this.value.template == 'row1-of1' && this.value.style == 'style-2') this.list =
this.list.concat(res.data).splice(0, this.value.count);
else this.list = res.data;
// 切屏滚动,每页显示固定数量
if (this.value.template == 'horizontal-slide' && this.value.slideMode == 'slide') {
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
}
this.loading = false;
}
});
},
progress(data) {
// 214 表示当前进度条的宽度
let progress = (((parseFloat(data.price) - parseFloat(data.curr_price)) / parseFloat(data.price)) * 214)
.toFixed();
if (progress == 'NaN') {
progress = 0;
}
return progress;
},
toDetail(e) {
this.$util.redirectTo('/pages_promotion/bargain/detail', {
b_id: e.bargain_id
});
},
imageError(index) {
this.list[index].goods_image = this.$util.getDefaultImage().goods;
this.$forceUpdate();
}
}
};
</script>
<style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
touch-action: none;
}
.diy-bargain {
overflow: hidden;
// 头部
.bargain-head {
&.style-1 {
display: flex;
justify-content: space-between;
align-items: center;
height: 88rpx;
box-sizing: border-box;
padding: 0 20rpx;
background-repeat: no-repeat;
background-size: cover;
margin-bottom: 20rpx;
border-radius: 18rpx 18rpx 0 0;
.left-img {
height: 40rpx;
width: 156rpx;
}
.head-content {
position: relative;
color: #fff;
font-size: $font-size-tag;
margin-right: auto;
margin-left: 20rpx;
line-height: 1;
&::after {
content: '';
position: absolute;
width: 2rpx;
height: 24rpx;
background-color: #fff;
top: 50%;
transform: translateY(-50%);
left: -12rpx;
}
}
.head-right {
display: flex;
align-items: center;
font-size: $font-size-sub;
color: #fff;
}
}
&.style-2 {
display: flex;
justify-content: space-between;
align-items: center;
height: 88rpx;
box-sizing: border-box;
padding: 0 20rpx;
background-repeat: no-repeat;
background-size: cover;
margin-bottom: 20rpx;
border-radius: 18rpx 18rpx 0 0;
.left-img {
height: 40rpx;
width: 156rpx;
}
.head-right {
display: flex;
align-items: center;
justify-content: center;
height: 36rpx;
background: linear-gradient(270deg, #ffbd5b 0%, #fd882e 100%);
border-radius: 24rpx;
padding: 2rpx;
text:nth-child(1) {
position: relative;
left: 6rpx;
transform: scale(0.9);
}
text:nth-child(2) {
padding: 6rpx 4rpx 4rpx;
background-color: #fff;
color: #ffbd5b;
border-radius: 50%;
transform: scale(0.6);
font-weight: bold;
line-height: 1;
}
}
}
}
// 商品列表
&.row1-of1 {
.item {
display: flex;
margin-bottom: 20rpx;
padding: 16rpx;
&.shadow {
margin: 8rpx 8rpx 20rpx 8rpx;
}
&:last-child {
margin-bottom: 0;
padding-bottom: 20rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
>image {
width: 200rpx;
}
}
.content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 6rpx 0 6rpx 20rpx;
.goods-name {
&.multi-hidden {
line-height: 1.3;
}
}
.price-wrap {
display: flex;
justify-content: space-between;
align-items: center;
}
.discount-price {
white-space: nowrap;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: var(--price-color);
}
.price {
font-size: $font-size-toolbar;
color: var(--price-color);
}
}
button {
margin: 0;
padding: 0 20rpx;
color: var(--btn-text-color);
background-color: $base-color;
color: #fff;
min-width: 112rpx;
height: 52rpx;
line-height: 52rpx;
font-size: $font-size-tag;
font-weight: bold;
}
}
}
&.style-2 {
.discount-price {
position: relative;
}
.progress {
display: flex;
flex-direction: column;
margin-top: 10rpx;
margin-right: 16rpx;
.bg {
margin-left: 6rpx;
width: auto;
height: 20rpx;
border-radius: 20rpx;
background-color: #ffeadb;
position: relative;
&::after {
content: '';
width: 26rpx;
height: 26rpx;
border-radius: 50%;
background-color: #fa1a1a;
position: absolute;
top: 50%;
transform: translateY(-50%);
right: -18rpx;
}
.curr {
width: 0;
height: 20rpx;
border-radius: 20rpx;
background-color: #fa1a1a;
position: relative;
.progress-bar {
position: absolute;
right: -20rpx;
width: 30rpx;
height: 30rpx;
max-width: inherit !important;
max-height: inherit !important;
top: 50%;
transform: translateY(-50%);
z-index: 1;
}
}
}
.num {
font-size: $font-size-tag;
margin-top: 12rpx;
line-height: 1;
text {
color: #fa1a1a;
}
}
}
}
&.style-3 {
.progress {
display: flex;
color: $color-tip;
font-size: $font-size-sub;
.num {
color: var(--price-color);
}
}
.item {
.content {
justify-content: space-around;
}
.img-wrap {
overflow: hidden;
}
}
}
}
&.horizontal-slide {
.scroll {
width: calc(100% - 40rpx);
padding: 20rpx;
line-height: 1;
white-space: nowrap;
.item.shadow {
margin-bottom: 8rpx;
}
}
.flex-between {
justify-content: space-between;
}
.item {
display: inline-block;
width: 200rpx;
overflow: hidden;
box-sizing: border-box;
&:nth-child(3n + 3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
position: relative;
overflow: hidden;
margin: 0 auto;
>image {
width: 100%;
}
.bg {
position: absolute;
width: 100%;
height: 60rpx;
bottom: 0;
left: 0;
z-index: 2;
}
.num {
width: 180rpx;
position: absolute;
bottom: 10rpx;
padding-left: 20rpx;
font-size: 20rpx;
line-height: 1;
color: #ffffff;
z-index: 3;
}
}
.content {
padding: 10rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
&.multi-content {
height: 160rpx;
box-sizing: border-box;
}
.goods-name {
line-height: 1.3;
&.multi-hidden {
white-space: break-spaces;
}
}
.discount-price {
white-space: nowrap;
margin-top: auto;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: var(--price-color);
}
.price {
font-size: $font-size-toolbar;
color: var(--price-color);
}
}
.original-price {
margin-top: 4rpx;
font-size: $font-size-tag;
color: $color-tip;
line-height: 1;
text-decoration: line-through;
}
}
}
.swiper {
padding: 20rpx;
width: 100%;
white-space: nowrap;
box-sizing: border-box;
.swiper-item {
display: flex;
align-items: center;
}
.item {
width: 200rpx;
box-sizing: border-box;
}
}
}
}
</style>

View File

@@ -0,0 +1,293 @@
<template>
<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" @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" :animation="cartAnimation" id="tabbarCart">
<block v-if="verify(item.link)">
<image v-if="item.selected_icon_type == 'img'" :src="$util.img(item.selectedIconPath)" />
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath" :value="item.selected_style ? item.selected_style : null"></diy-icon>
</block>
<block v-else>
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath" :value="item.style ? item.style : null"></diy-icon>
</block>
<view class="cart-count-mark font-size-activity-tag"
:class="{ max: item.link.wap_url == '/pages/goods/cart' && cartNumber > 99 }"
:style="{ background: 'var(--price-color)' }" v-if="cartNumber > 0">
{{ cartNumber > 99 ? '99+' : cartNumber }}
</view>
</view>
</block>
<block v-else>
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2">
<block v-if="verify(item.link)">
<image v-if="item.selected_icon_type == 'img'" :src="$util.img(item.selectedIconPath)" />
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath"
:value="item.selected_style ? item.selected_style : null"></diy-icon>
</block>
<block v-else>
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath" :value="item.style ? item.style : null"></diy-icon>
</block>
</view>
</block>
<view class="label" v-if="(tabBarList.type == 1 || tabBarList.type == 3) && tabBarList.theme == 'diy'" :style="{ color: verify(item.link) ? tabBarList.textHoverColor : tabBarList.textColor }">
{{ lang =='en-us'?item.en_text:item.text }}
</view>
<view class="label" v-if="(tabBarList.type == 1 || tabBarList.type == 3) && tabBarList.theme == 'default'" :style="{ color: verify(item.link) ? 'var(--base-color)' : '#333333' }">
{{ lang =='en-us'?item.en_text:item.text }}
</view>
</view>
</view>
</view>
<!-- 解决fixed定位后底部导航栏塌陷问题 -->
<view class="tab-bar-placeholder"></view>
</view>
</template>
<script>
export default {
name: 'diy-bottom-nav',
props: {
value: {
type: Object
},
name: {
type: String,
default: ''
}
},
data() {
return {
lang:uni.getStorageSync("lang"),
currentRoute: '', //当前页面路径
jumpFlag: true, //是否可以跳转,防止重复点击
cartAnimation: {}
};
},
mounted() {
let currentPage = getCurrentPages()[getCurrentPages().length - 1];
if (currentPage && currentPage.route) {
this.currentRoute = currentPage.route;
}
this.$nextTick(() => {
if (!this.$store.state.cartPosition) {
let query = uni.createSelectorQuery().in(this);
query.select('#tabbarCart')
.boundingClientRect(data => {
if (data) this.$store.commit('setCartPosition', data);
}).exec();
query.select('.tab-bar')
.boundingClientRect(data => {
if (data) this.$store.commit('setTabBarHeight', data.height +
'px');
}).exec();
}
});
},
computed: {
cartChange() {
return this.$store.state.cartChange;
}
},
watch: {
cartChange: function (nval, oval) {
if (nval > oval) {
let animation = uni.createAnimation({
duration: 200,
timingFunction: 'ease'
});
animation.scale(1.2).step();
this.cartAnimation = animation.export();
setTimeout(() => {
animation.scale(1).step();
this.cartAnimation = animation.export();
}, 300);
}
}
},
methods: {
redirectTo(link) {
this.$emit('callback');
this.$util.diyRedirectTo(link);
},
verify(link) {
if (link == null || link == '' || !link.wap_url) return false;
if (this.name) {
var url = this.currentRoute + '?name=' + this.name;
} else {
var url = this.currentRoute;
}
// 首页特殊处理
if (link.wap_url == '/pages/index/index' && this.name == 'DIY_VIEW_INDEX') {
return true;
} else if (url && link.wap_url.indexOf(url) != -1) {
return true;
}
return false;
}
}
};
</script>
<style lang="scss">
.placeholder {
height: 112rpx;
&.bluge {
height: 180rpx;
}
}
.safe-area {
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.tab-bar {
background-color: #fff;
box-sizing: border-box;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
z-index: 998;
display: flex;
border-top: 2rpx solid #f5f5f5;
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.tabbar-border {
background-color: rgba(255, 255, 255, 0.329412);
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 2rpx;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
.item {
display: flex;
align-items: center;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex: 1;
flex-direction: column;
padding-bottom: 10rpx;
box-sizing: border-box;
.bd {
position: relative;
height: 100rpx;
flex-direction: column;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
.icon {
position: relative;
display: inline-block;
margin-top: 10rpx;
width: 40rpx;
height: 40rpx;
font-size: 40rpx;
line-height: 40rpx;
image {
width: 100%;
height: 100%;
}
>view {
height: inherit;
display: flex;
align-items: center;
}
.bar-icon {
font-size: 42rpx;
}
}
.label {
position: relative;
text-align: center;
font-size: 24rpx;
line-height: 1;
margin-top: 12rpx;
}
}
&.bulge {
.bd {
position: relative;
height: 100rpx;
flex-direction: column;
text-align: center;
.icon {
margin-top: -60rpx;
margin-bottom: 4rpx;
border-radius: 50%;
width: 100rpx;
height: 102rpx;
padding: 10rpx;
border-top: 2rpx solid #f5f5f5;
background-color: #fff;
box-sizing: border-box;
image {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.label {
position: relative;
text-align: center;
font-size: 24rpx;
height: 40rpx;
line-height: 40rpx;
}
}
}
.cart-count-mark {
position: absolute;
top: -8rpx;
right: -18rpx;
width: 24rpx;
height: 24rpx !important;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
padding: 6rpx;
border-radius: 50%;
z-index: 99;
&.max {
width: 40rpx;
border-radius: 24rpx;
right: -28rpx;
}
}
}
}
.tab-bar-placeholder {
padding-bottom: calc(constant(safe-area-inset-bottom) + 112rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 112rpx);
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@
<script>
//
import DiyMinx from './minx.js'
export default {
name: 'diy-comp-extend',
props: {
@@ -12,12 +11,11 @@ export default {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {};
},
computed: {},
created() { },
created() {},
methods: {}
};
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -1,50 +1,47 @@
<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" @click="toDetail(item)"
:class="[value.ornament.type]" :style="goodsItemCss">
<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" @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)" />
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }" :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">
<view class="info-wrap" v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl || value.btnStyle.control">
<view class="name-wrap">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ isEnEnv ? item.en_goods_name : item.goods_name }}
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]"
>
{{ item.goods_name }}
</view>
</view>
<view class="pro-info">
<view class="discount-price">
<view class="price-wrap" v-if="value.priceStyle.mainControl">
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor : '' }"> </text>
<text class="price price-style large"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor : '' }">{{
item.commission_money.split('.')[0] }}</text>
<text class="unit price-style small"
:style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor : '' }">{{ '.' +
item.commission_money.split('.')[1] }}</text>
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor : '' }"> </text>
<text class="price price-style large" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor : '' }">{{ item.commission_money.split('.')[0] }}</text>
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor : '' }">{{ '.' + item.commission_money.split('.')[1] }}</text>
</view>
<view class="sale-btn" v-if="value.btnStyle.control && item.is_collect == 0" :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'
}" @click.stop="followGoods(item, index)">
<view class="sale-btn" v-if="value.btnStyle.control && item.is_collect == 0"
: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'
}"
@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'
}" @click.stop="delFollowTip(item, index)">
<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'
}"
@click.stop="delFollowTip(item, index)"
>
取消关注
</view>
</view>
<view class="delete-price" v-if="value.priceStyle.lineControl"
:style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">
<view class="delete-price" v-if="value.priceStyle.lineControl" :style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">
{{ item.discount_price }}
</view>
</view>
@@ -54,8 +51,6 @@
</template>
<script>
//
import DiyMinx from './minx.js'
export default {
name: 'diy-fenxiao-goods-list',
props: {
@@ -63,7 +58,6 @@ export default {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {
list: [],
@@ -75,7 +69,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
},
@@ -86,7 +80,7 @@ export default {
},
watch: {
//
componentRefresh: function (nval) {
componentRefresh: function(nval) {
this.getData();
}
},
@@ -124,7 +118,7 @@ export default {
methods: {
//
toDetail(e) {
this.$util.redirectTo('/pages_goods/detail', { goods_id: e.goods_id });
this.$util.redirectTo('/pages/goods/detail', { goods_id: e.goods_id });
},
//
followGoods(e, index) {
@@ -215,7 +209,8 @@ export default {
</script>
<style lang="scss">
.diy-fenxiao {}
.diy-fenxiao {
}
//
.goods-list.row1-of1 {
@@ -223,11 +218,9 @@ export default {
background-color: #fff;
display: flex;
margin-bottom: 20rpx;
&:last-of-type {
margin-bottom: 0;
}
&.shadow {
margin: 8rpx 8rpx 20rpx 8rpx;
}
@@ -236,7 +229,6 @@ export default {
width: 180rpx;
overflow: hidden;
margin-right: 20rpx;
image {
width: 100%;
}
@@ -252,11 +244,9 @@ export default {
.name-wrap {
flex: 1;
margin-bottom: 10rpx;
.goods-name {
font-size: $font-size-base;
line-height: 1.3;
&.multi-hidden {
height: 72rpx;
}
@@ -267,31 +257,25 @@ export default {
display: flex;
flex-direction: column;
justify-content: space-between;
.sale {
font-size: 20rpx;
line-height: 1;
color: #999;
}
.discount-price {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
.price-wrap {
white-space: nowrap;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
}
text {
font-weight: bold;
color: $base-color;
@@ -307,7 +291,6 @@ export default {
font-size: $font-size-activity-tag;
}
}
.sale-btn {
position: absolute;
right: 20rpx;
@@ -327,7 +310,6 @@ export default {
.goods-list.row1-of2 {
display: flex;
flex-wrap: wrap;
.goods-item {
position: relative;
background: #fff;
@@ -335,30 +317,24 @@ export default {
margin-right: 20rpx;
margin-top: 20rpx;
width: calc(50% - 10rpx);
&:nth-child(2n + 2) {
width: calc(50% - 11rpx);
margin-right: 0;
}
&:nth-of-type(1),
&:nth-of-type(2) {
margin-top: 0;
}
&.shadow {
width: calc(50% - 18rpx);
&:nth-child(2n-1) {
margin-left: 8rpx;
}
&:nth-of-type(1),
&:nth-of-type(2) {
margin-top: 8rpx;
}
}
.goods-img {
position: relative;
overflow: hidden;
@@ -379,11 +355,9 @@ export default {
.name-wrap {
margin-bottom: 10rpx;
.goods-name {
font-size: $font-size-base;
line-height: 1.3;
&.multi-hidden {
height: 72rpx;
}
@@ -395,30 +369,24 @@ export default {
display: flex;
flex-direction: column;
justify-content: space-between;
.sale {
font-size: 20rpx;
line-height: 1;
color: #999;
}
.discount-price {
display: flex;
justify-content: space-between;
align-items: center;
.price-wrap {
white-space: nowrap;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
}
text {
font-weight: bold;
color: $base-color;
@@ -434,7 +402,6 @@ export default {
font-size: $font-size-activity-tag;
}
}
.sale-btn {
position: absolute;
right: 20rpx;

View File

@@ -0,0 +1,114 @@
<template>
<view data-component-name="diy-float-btn" class="float-btn" :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" @click="$util.diyRedirectTo(item.link)" :style="{ width: value.imageSize + 'px', height: value.imageSize + 'px', fontSize: value.imageSize + 'px' }">
<image v-if="!item.iconType || item.iconType == 'img'" :src="$util.img(item.imageUrl)" mode="aspectFit" :show-menu-by-longpress="true"/>
<diy-icon v-else-if="item.iconType && item.iconType == 'icon'" :icon="item.icon"
:value="item.style ? item.style : null"></diy-icon>
</view>
</block>
</view>
</template>
<script>
// 获取系统状态栏的高度
let systemInfo = uni.getSystemInfoSync();
export default {
name: 'diy-float-btn',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
navHeight: 0,
statusBarHeight: systemInfo.statusBarHeight
};
},
created() {},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {}
},
components: {},
methods: {},
computed: {
style() {
let style = {},
height = 54;
// #ifdef MP
height = systemInfo.platform == 'ios' ? 54 : 58;
// #endif
switch (parseInt(this.value.bottomPosition)) {
case 1:
style.top = (this.navHeight + this.statusBarHeight + parseInt(this.value.btnBottom)) * 2 + 'rpx';
break;
case 2:
style.top = (this.navHeight + this.statusBarHeight + parseInt(this.value.btnBottom)) * 2 + 'rpx';
break;
case 3:
style.bottom = (100 + parseInt(this.value.btnBottom)) * 2 + 'rpx';
break;
case 4:
style.bottom = (100 + parseInt(this.value.btnBottom)) * 2 + 'rpx';
break;
}
return this.$util.objToStyle(style);
}
}
};
</script>
<style lang="scss">
.float-btn {
position: fixed;
bottom: 20%;
right: 40rpx;
z-index: 990;
&.left_top {
top: 100rpx;
left: 30rpx;
}
&.right_top {
top: 100rpx;
right: 30rpx;
}
&.left_bottom {
bottom: 160rpx;
left: 30rpx;
padding-bottom: constant(safe-area-inset-bottom);
/*兼容 IOS<11.2*/
padding-bottom: env(safe-area-inset-bottom);
/*兼容 IOS>11.2*/
}
&.right_bottom {
bottom: 160rpx;
right: 30rpx;
padding-bottom: constant(safe-area-inset-bottom);
/*兼容 IOS<11.2*/
padding-bottom: env(safe-area-inset-bottom);
/*兼容 IOS>11.2*/
}
.button-box {
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
image {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@@ -0,0 +1,29 @@
<template>
<!-- #ifdef MP -->
<view data-component-name="diy-follow-official-account" v-if="value.isShow">
<official-account></official-account>
</view>
<!--#endif -->
</template>
<script>
// 关注公众号
export default {
name: 'diy-follow-official-account',
props: {
value: {
type: Object
}
},
data() {
return {};
},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {}
},
methods: {}
};
</script>
<style></style>

View File

@@ -0,0 +1,110 @@
<template>
<view data-component-name="diy-form" class="diy-from" :style="style">
<view class="fui-cell-group">
<view class="fui-cell ">
<view class="fui-cell-label ">您的姓名</view>
<view class="fui-cell-info">
<input v-model="Form.realname" class="fui-input" placeholder="请输入您的姓名" value=""></input>
</view>
</view>
<view class="fui-cell ">
<view class="fui-cell-label">手机号码</view>
<view class="fui-cell-info">
<input v-model="Form.mobile" class="fui-input" maxlength="11" placeholder="请输入您的手机号" type="number" ></input>
</view>
</view>
<view class="fui-cell ">
<view class="fui-cell-label">您的邮箱</view>
<view class="fui-cell-info">
<input v-model="Form.mailbox" class="fui-input" placeholder="请输入您的邮箱" type="text" ></input>
</view>
</view>
<view class="fui-cell">
<view class="fui-cell-label">所在城市</view>
<view class="fui-cell-info">
<input v-model="Form.citys" class="fui-input" placeholder="请输入您的所在地" value=""></input>
</view>
</view>
<view class="fui-cell">
<view class="fui-cell-label">备注</view>
<view class="fui-cell-info">
<input v-model="Form.remark" class="fui-input" placeholder="请输入备注" value=""></input>
</view>
</view>
</view>
<view @click="submitform" class="fui-btn btn-danger block mtop">提交信息</view>
</view>
</template>
<script>
export default {
name: 'diy-from',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
markers:[],
Form:{
realname:'',
mobile:'',
mailbox:'',
citys:'',
remark:'',
}
};
},
created() {
},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {
// this.getDataList();
}
},
computed: {
markerst(){
return [{
id:1,
latitude:this.value.list[0].lat,
longitude:this.value.list[0].lng
}]
},
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return css;
}
},
methods: {
submitform(){
this.$api.sendRequest({
url: '/api/member/information',
data: this.Form,
success: res => {
this.$util.showToast({
title: res.message
});
}
});
}
}
};
</script>
<style lang="scss">
.diy-from{
background: #fff;
padding-bottom: 20rpx;
border-radius: 10rpx;
}
</style>

View File

@@ -0,0 +1,167 @@
<template>
<x-skeleton data-component-name="diy-goods-brand" type="waterfall" :loading="loading" :configs="skeletonConfig">
<view :class="['brand-wrap', value.ornament.type]" :style="warpCss">
<view :class="[value.style]">
<view class="title-wrap" v-show="value.title" :style="{ color: value.textColor, fontWeight: value.fontWeight ? 'bold' : '' }">{{ value.title }}
</view>
<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" @click="handlerClick(item)" @tap="handlerClick(item)" @error="imgError(index)" :style="itemCss"/>
</view>
</view>
</view>
</view>
</x-skeleton>
</template>
<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'
export default {
name: 'diy-goods-brand',
props: {
value: {
type: Object
}
},
components: {
uniGrid,
uniGridItem
},
data() {
return {
list: [],
loading: true,
skeletonConfig: {
gridRows: 2,
gridColumns: 4,
gridRowsGap: '20rpx',
headWidth: '120rpx',
headHeight: '120rpx',
textShow: false
}
};
},
created() {
this.getBrandList();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function(nval) {
this.getBrandList();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color;
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color;
}
return obj;
},
// 子项样式
itemCss() {
var obj = '';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return obj;
}
},
methods: {
getBrandList() {
var data = {
page: 1,
page_size: this.value.count
};
if (this.value.sources == 'diy') {
data.page_size = 0;
data.brand_id_arr = this.value.brandIds.toString();
}
this.$api.sendRequest({
url: '/api/goodsbrand/page',
data: data,
success: res => {
if (res.code == 0 && res.data) {
let data = res.data;
this.list = data.list;
}
this.loading = false;
}
});
},
toDetail(item) {
this.$util.redirectTo('/pages/goods/list', {
brand_id: item.brand_id
});
},
imgError(index) {
if (this.list[index]) this.list[index].image_url = this.$util.getDefaultImage().goods;
},
async handlerClick(item) {
await this.__$emitEvent({eventName: 'goods-brand-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.toDetail(item);
}})
},
}
};
</script>
<style lang="scss">
.brand-wrap {
&.shadow {
margin-left: 8rpx;
margin-right: 8rpx;
margin-top: 8rpx;
margin-bottom: 8rpx;
}
.style-1 {
.title-wrap {
text-align: center;
padding: 20rpx 0 10rpx;
}
.ul-wrap {
display: flex;
flex-wrap: wrap;
padding: 20rpx;
.li-item {
display: flex;
align-items: center;
justify-content: center;
width: calc(100% / 4 - 20rpx) !important;
height: 124rpx;
margin: 10rpx;
background-color: #fff;
.brand-pic {
width: 100%;
height: 100%;
}
}
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,599 @@
<template>
<x-skeleton data-component-name="diy-goods-recommend" type="waterfall" :loading="loading" :configs="skeletonConfig">
<view v-if="list.length" :class="['goods-list', goodsValue.style]" :style="goodsListWarpCss">
<view class="top-wrap" v-if="goodsValue.topStyle.support">
<text :class="['js-icon', goodsValue.topStyle.icon.value]" :style="{ backgroundColor: goodsValue.topStyle.icon.bgColor, color: goodsValue.topStyle.icon.color }"></text>
<text class="title" :style="{ color: goodsValue.topStyle.color }">{{ goodsValue.topStyle.title }}</text>
<text class="line" :style="{ color: goodsValue.topStyle.subColor }"></text>
<text class="sub" :style="{ color: goodsValue.topStyle.subColor }">{{ goodsValue.topStyle.subTitle }}</text>
</view>
<swiper :autoplay="false" class="swiper" :style="{ height: swiperHeight }">
<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" @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"/>
<view class="sell-out" v-if="dataItem.stock <= 0">
<text class="iconfont icon-shuqing"></text>
</view>
</div>
<view :class="['info-wrap', { 'multi-content': value.nameLineMode == 'multiple' }]" v-if="goodsValue.goodsNameStyle.control || goodsValue.priceStyle.mainControl || goodsValue.priceStyle.lineControl || goodsValue.labelStyle.support">
<view v-if="goodsValue.goodsNameStyle.control" class="goods-name"
:style="{ color: goodsValue.theme == 'diy' ? goodsValue.goodsNameStyle.color : '', fontWeight: goodsValue.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': goodsValue.nameLineMode == 'single' }, { 'multi-hidden': goodsValue.nameLineMode == 'multiple' }]">
{{ dataItem.goods_name }}
</view>
<view class="pro-info">
<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"/>
<text>{{ goodsValue.labelStyle.title }}</text>
</view>
<view class="discount-price">
<view class="price-wrap" v-if="goodsValue.priceStyle.mainControl">
<text class="unit price-style small" :style="{ color: goodsValue.theme == 'diy' ? goodsValue.priceStyle.mainColor + '!important' : '' }"></text>
<text class="price price-style large" :style="{ color: goodsValue.theme == 'diy' ? goodsValue.priceStyle.mainColor + '!important' : '' }">{{ showPrice(dataItem).split('.')[0] }}</text>
<text class="unit price-style small" :style="{ color: goodsValue.theme == 'diy' ? goodsValue.priceStyle.mainColor + '!important' : '' }">{{ '.' + showPrice(dataItem).split('.')[1] }}</text>
</view>
<view v-if="goodsValue.priceStyle.lineControl && showMarketPrice(dataItem)" class="delete-price price-font" :style="{ color: goodsValue.theme == 'diy' ? goodsValue.priceStyle.lineColor : '' }">{{ showMarketPrice(dataItem) }}</view>
<view class="sale" v-if="goodsValue.saleStyle.control" :style="{ color: goodsValue.theme == 'diy' ? goodsValue.saleStyle.color : '' }">
{{ dataItem.sale_num }}{{ dataItem.unit ? dataItem.unit : '' }}
</view>
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</x-skeleton>
</template>
<script>
export default {
name: 'diy-goods-recommend',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
loading: true,
skeletonConfig: {
gridRows: 1,
gridColumns: 3,
headWidth: '200rpx',
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '60%'],
},
list: [],
goodsValue: {},
page: 1
};
},
created() {
this.goodsValue = this.value;
this.getGoodsList();
},
watch: {
'globalStoreInfo.store_id': {
handler(nval, oval) {
if (nval != oval) {
this.getGoodsList();
}
},
deep: true
},
// 组件刷新监听
componentRefresh: function(nval) {
this.getGoodsList();
}
},
computed: {
goodsListWarpCss() {
var obj = '';
obj += 'background-color:' + this.goodsValue.componentBgColor + ';';
if (this.goodsValue.componentAngle == 'round') {
obj += 'border-top-left-radius:' + this.goodsValue.topAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.goodsValue.topAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.goodsValue.bottomAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.goodsValue.bottomAroundRadius * 2 + 'rpx;';
}
if (this.goodsValue.bgUrl) {
obj += `background-image: url('${this.$util.img(this.goodsValue.bgUrl)}');`;
}
return obj;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.goodsValue.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.goodsValue.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.goodsValue.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.goodsValue.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.goodsValue.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.goodsValue.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.goodsValue.ornament.color + ';';
}
if (this.goodsValue.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.goodsValue.ornament.color + ';';
}
const screenWidth = uni.getSystemInfoSync().windowWidth;
var width = '';
if (this.goodsValue.style != 'style-2') {
width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this.rpxUpPx(this.value.margin
.both * 2) * 2] / 6;
} else {
width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this
.rpxUpPx(this.value.margin.both * 2) * 2
] / 6;
}
obj += 'margin-left:' + width + 'px;';
obj += 'margin-right:' + width + 'px;';
return obj;
},
swiperHeight() {
if (this.goodsValue.style == 'style-3') {
return '330rpx';
} else if (this.goodsValue.style != 'style-2') {
if (this.value.nameLineMode == 'multiple') {
return '348rpx';
}
return '312rpx';
} else {
if (this.value.nameLineMode == 'multiple') {
return '360rpx';
}
return '320rpx';
}
}
},
methods: {
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
getGoodsList() {
var data = {
num: this.goodsValue.count
};
if (this.goodsValue.sources == 'category') {
data.category_id = this.goodsValue.categoryId;
data.category_level = 1;
} else if (this.goodsValue.sources == 'diy') {
data.num = 0;
data.goods_id_arr = this.goodsValue.goodsId.toString();
}
data.order = this.goodsValue.sortWay;
this.$api.sendRequest({
url: '/api/goodssku/components',
data: data,
success: res => {
if (res.code == 0 && res.data) {
let data = res.data;
this.list = data;
// 切屏滚动,每页显示固定数量
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
this.loading = false;
}
});
},
toDetail(item) {
this.$util.redirectTo('/pages/goods/detail', {
goods_id: item.goods_id
});
},
imgError(pageIndex, index) {
this.list[pageIndex][index].goods_image = this.$util.getDefaultImage().goods;
},
showPrice(data) {
let price = data.discount_price;
if (data.member_price && parseFloat(data.member_price) < parseFloat(price)) price = data.member_price;
return price;
},
showMarketPrice(item) {
let price = this.showPrice(item);
if (item.market_price > 0) {
return item.market_price;
} else if (item.price > price) {
return item.price;
}
return '';
},
}
};
</script>
<style lang="scss" scoped>
.goods-list {
.goods-item {
line-height: 1;
.sale {
line-height: 1;
color: $color-tip;
font-size: $font-size-activity-tag;
}
.info-wrap {
.goods-name {
margin-bottom: 10rpx;
line-height: 1.3;
}
}
.sell-out{
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
text{
color: #fff;
font-size: 180rpx;
}
}
}
}
// 商品列表横向滚动样式
.goods-list.style-1 {
width: 100%;
white-space: nowrap;
background-repeat: round;
.top-wrap {
display: flex;
align-items: center;
padding: 20rpx 0;
.js-icon {
border-radius: 50%;
font-size: 40rpx;
margin-right: 10rpx;
width: 70rpx;
height: 70rpx;
text-align: center;
line-height: 70rpx;
}
.line {
height: 28rpx;
margin: 0 10rpx;
border: 2rpx solid;
}
.title {
font-weight: bold;
font-size: $font-size-toolbar;
}
.sub {
font-size: $font-size-tag;
}
}
.flex-between {
justify-content: space-between;
}
.swiper {
display: flex;
flex-wrap: wrap;
margin: 0 20rpx;
.swiper-item {
display: flex;
align-items: center;
}
}
.goods-item {
overflow: hidden;
width: 200rpx;
display: inline-block;
box-sizing: border-box;
&:nth-child(3n + 3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.goods-img, .goods-img-wrap {
position: relative;
width: 100%;
height: 196rpx;
}
.info-wrap {
display: flex;
flex-direction: column;
padding: 10rpx;
&.multi-content {
height: 130rpx;
box-sizing: border-box;
}
.goods-name {
font-size: $font-size-sub;
&.multi-hidden {
white-space: break-spaces;
}
}
.pro-info {
margin-top: auto;
display: flex;
flex-direction: column;
justify-content: space-between;
.discount-price {
display: flex;
justify-content: space-between;
align-items: center;
.price-wrap {
line-height: 1;
white-space: nowrap;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
}
text {
font-weight: bold;
color: $base-color;
}
}
}
.delete-price {
margin-left: 10rpx;
text-decoration: line-through;
flex: 1;
line-height: 28rpx;
color: $color-tip;
font-size: $font-size-activity-tag;
}
}
}
}
}
// 商品列表横向滚动样式
.goods-list.style-2 {
width: 100%;
white-space: nowrap;
background-repeat: round;
padding-bottom: 20rpx;
.top-wrap {
display: flex;
align-items: center;
padding: 20rpx;
.js-icon {
border-radius: 50%;
font-size: 40rpx;
margin-right: 20rpx;
width: 70rpx;
height: 70rpx;
text-align: center;
line-height: 70rpx;
}
.line {
height: 28rpx;
margin: 0 10rpx;
border: 2rpx solid;
}
.title {
font-weight: bold;
font-size: $font-size-toolbar;
}
.sub {
font-size: $font-size-tag;
}
}
.swiper {
display: flex;
flex-wrap: wrap;
margin: 0 20rpx;
padding: 20rpx;
border-radius: 20rpx;
background-color: #fff;
}
.goods-item {
overflow: hidden;
width: 200rpx;
display: inline-block;
box-sizing: border-box;
&.shadow {
margin-top: 8rpx;
width: 200rpx;
}
.goods-img, .goods-img-wrap {
position: relative;
width: 100%;
height: 200rpx;
}
.info-wrap {
padding: 10rpx;
.goods-name {
line-height: 1;
&.multi-hidden {
line-height: 1.3;
height: 68rpx;
white-space: break-spaces;
}
}
.pro-info {
display: flex;
flex-direction: column;
justify-content: space-between;
.discount-price {
display: flex;
justify-content: space-between;
align-items: center;
.price-wrap {
line-height: 1.3;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
text {
font-weight: bold;
color: $base-color;
&:last-of-type {
font-size: 32rpx;
}
}
}
}
.delete-price {
margin-left: 10rpx;
text-decoration: line-through;
flex: 1;
line-height: 28rpx;
color: $color-tip;
font-size: $font-size-activity-tag;
}
}
}
}
}
.goods-list.style-3 {
background-position: bottom;
.swiper {
display: flex;
flex-wrap: wrap;
margin: 0 20rpx;
padding: 10rpx 0;
.swiper-item {
display: flex;
align-items: center;
}
}
.goods-item {
overflow: hidden;
width: 200rpx;
display: inline-block;
box-sizing: border-box;
&.shadow {
// margin-top: 20rpx;
}
.goods-img, .goods-img-wrap {
position: relative;
width: 100%;
height: 200rpx;
}
.info-wrap {
display: flex;
flex-direction: column;
padding: 10rpx;
.pro-info {
text-align: center;
.label-wrap {
border-radius: 40rpx;
display: inline-block;
margin: 10rpx 0;
position: relative;
padding-left: 52rpx;
padding-right: 16rpx;
line-height: 1.7;
image {
position: absolute;
top: -2rpx;
left: -2rpx;
width: 46rpx;
height: 46rpx;
}
text {
font-size: $font-size-tag;
}
}
.discount-price {
.price-wrap {
line-height: 1;
white-space: nowrap;
.unit {
font-size: $font-size-tag;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
}
text {
font-weight: bold;
color: $base-color;
}
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,304 @@
<template>
<view data-component-name="diy-graphic-nav" :style="componentStyle">
<block v-if="value.showStyle == 'pageSlide'">
<swiper :class="['graphic-nav', 'pageSlide', value.carousel.type]" circular :indicator-dots="false" :style="swiperHeight" @change="swiperChange">
<swiper-item class="graphic-nav-wrap"
v-for="(numItem, numIndex) in Math.ceil(value.list.length / (value.pageCount * value.rowCount))">
<!-- #ifdef MP -->
<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 + '%' }" @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 + '%' }" @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' }">
<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="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>
<text class="tag" v-if="item.label.control"
:style="{ color: item.label.textColor, backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')' }">
{{ item.label.text }}
</text>
</view>
<text v-if="value.mode != 'img'" class="graphic-text"
:style="{ fontSize: value.font.size * 2 + 'rpx', fontWeight: value.font.weight, color: value.font.color }">
{{ item.title }}
</text>
</view>
</swiper-item>
</swiper>
<view class="swiper-dot-box" v-if="isIndicatorDots" :class="value.carousel.type">
<view v-for="(numItem, numIndex) in Math.ceil(value.list.length / (value.pageCount * value.rowCount))" :key="numIndex">
<view class="swiper-dot" :class="{'active':numIndex==swiperCurrent}"></view>
</view>
</view>
</block>
<scroll-view v-else :scroll-x="value.showStyle == 'singleSlide'" :class="['graphic-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle ]">
<!-- #ifdef MP -->
<view class="uni-scroll-view-content">
<!-- #endif -->
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list" :key="index" :style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
<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="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>
<text :class="['tag', { alone: value.mode == 'text' }]" v-if="item.label.control"
:style="{ color: item.label.textColor, backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')' }">
{{ item.label.text }}
</text>
</view>
<text v-if="value.mode != 'img'" class="graphic-text" :style="{ fontSize: value.font.size * 2 + 'rpx', fontWeight: value.font.weight, color: value.font.color }">
{{ item.title }}
</text>
</view>
<!-- #ifdef MP -->
</view>
<!-- #endif -->
</scroll-view>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
export default {
name: 'diy-graphic-nav',
props: {
value: {
type: Object
}
},
data() {
return {
pageWidth: '',
indicatorDots: false,
swiperCurrent: 0
};
},
created() {},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {}
},
computed: {
componentStyle() {
var css = '';
css += 'background-color:' + this.value.componentBgColor + ';';
if (this.value.componentAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
}
css += 'box-shadow:' + (this.value.ornament.type == 'shadow' ? '0 0 10rpx ' + this.value.ornament
.color :
'') + ';';
css += 'border:' + (this.value.ornament.type == 'stroke' ? '2rpx solid ' + this.value.ornament.color :
'') + ';';
return css;
},
// 滑块容器的高度
swiperHeight() {
var css = '';
var height = 0;
if (this.value.mode == 'graphic') {
height = (21 + 6 + 14 + 8 + this.value.imageSize) * this.value
.pageCount; // 21 = 文字高度8 = 文字上边距14 = 上下内边距8 = 外边距
} else if (this.value.mode == 'img') {
height = (14 + 8 + this.value.imageSize) * this.value.pageCount; // 14 = 上下内边距8 = 外边距
} else if (this.value.mode == 'text') {
height = (21 + 14 + 8) * this.value.pageCount; // 21 = 文字高度14 = 上下内边距8 = 外边距
}
css += 'height:' + height * 2 + 'rpx';
return css;
},
// 是否显示轮播点
isIndicatorDots() {
var bool = true;
bool = this.value.carousel.type == 'hide' || Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount)) == 1 ? false : true;
return bool;
}
},
methods: {
redirectTo(link) {
if (link.wap_url) {
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) {
this.swiperCurrent = e.detail.current
}
}
};
</script>
<style>
/* 固定显示 */
.graphic-nav.fixed-layout>>>.uni-scroll-view-content {
display: flex;
flex-wrap: wrap;
}
/* 单行滑动 */
.graphic-nav.singleSlide>>>.uni-scroll-view-content {
display: flex;
}
.graphic-nav.pageSlide>>>.uni-swiper-dots-horizontal {
bottom: 0rpx;
}
.graphic-nav.pageSlide.straightLine>>>.uni-swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
.graphic-nav.pageSlide.circle>>>.uni-swiper-dot {
width: 14rpx;
height: 14rpx;
}
</style>
<style lang="scss">
.graphic-nav {
padding: 16rpx;
box-sizing: border-box;
&.singleSlide {
.graphic-nav-item {
flex-shrink: 0;
}
}
&.pageSlide {
position: relative;
.graphic-nav-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
}
.graphic-nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 14rpx 0;
box-sizing: border-box;
.graphic-text {
padding-top: 12rpx;
line-height: 1.5;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
&.alone {
padding-top: 0;
}
}
&.text {
.graphic-text {
padding-top: 0;
}
}
.graphic-img {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
font-size: 90rpx;
.tag {
position: absolute;
top: -10rpx;
right: -24rpx;
color: #fff;
border-radius: 24rpx;
border-bottom-left-radius: 0;
transform: scale(0.8);
padding: 8rpx 16rpx;
line-height: 1;
font-size: 24rpx;
}
.icon {
font-size: 50rpx;
color: $color-sub;
}
}
}
}
.swiper-dot-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: -20rpx;
padding-bottom: 8rpx;
.swiper-dot {
background-color: rgba(0, 0, 0, .3);
margin: 8rpx;
&.active {
background-color: rgba(0, 0, 0, 1);
}
}
&.straightLine {
.swiper-dot {
width: 30rpx;
border-radius: 0;
height: 8rpx;
}
}
&.circle {
.swiper-dot {
width: 15rpx;
border-radius: 50%;
height: 15rpx;
}
}
}
</style>

View File

@@ -5,34 +5,34 @@
<!-- 门店展示 -->
<diy-store :value="item"></diy-store>
</view>
<template v-if="item.componentName == 'Kefu'">
<!-- 客服按钮 -->
<diy-kefu :value="item"></diy-kefu>
</template>
<template v-if="item.componentName == 'Form'">
<!-- 表单组件 -->
<diy-form :value="item"></diy-form>
</template>
<template v-if="addonIsExist.store && item.componentName == 'StoreLabel'">
<!-- 门店标签 -->
<diy-store-label :value="item"></diy-store-label>
</template>
<template v-if="item.componentName == 'Picture'">
<!-- 单图组组件 -->
<diy-picture :value="item"></diy-picture>
</template>
<template v-if="item.componentName == 'Listmenu'">
<!-- 列表按钮组件 -->
<diy-listmenu :value="item"></diy-listmenu>
</template>
<template v-if="item.componentName == 'Text'">
<!-- 文本 -->
<diy-text :value="item"></diy-text>
@@ -55,8 +55,7 @@
<template v-if="item.componentName == 'Search'">
<!-- 搜索 -->
<diy-search :value="item" :topNavColor="topNavColor" :global="diyGlobalData.global"
:haveTopCategory="haveTopCategory" :followOfficialAccount="followOfficialAccount"></diy-search>
<diy-search :value="item" :topNavColor="topNavColor" :global="diyGlobalData.global" :haveTopCategory="haveTopCategory" :followOfficialAccount="followOfficialAccount"></diy-search>
</template>
<template v-if="item.componentName == 'RichText'">
@@ -86,8 +85,7 @@
<template v-if="item.componentName == 'ManyGoodsList'">
<!-- 多商品组 -->
<diy-many-goods-list :value="item" :global="diyGlobalData.global"
:scrollTop="scrollTop"></diy-many-goods-list>
<diy-many-goods-list :value="item" :global="diyGlobalData.global" :scrollTop="scrollTop"></diy-many-goods-list>
</template>
<template v-if="item.componentName == 'RubikCube'">
@@ -99,8 +97,8 @@
<!-- 视频 -->
<diy-video :value="item"></diy-video>
</template>
<template v-if="item.componentName == 'Seckill' && addonIsExist.seckill">
@@ -169,7 +167,7 @@
<!-- 文章 -->
<diy-article :value="item"></diy-article>
</template>
<template v-if="item.componentName == 'MerchList'">
<!-- 商户列表 -->
<diy-merch-list :value="item"></diy-merch-list>
@@ -204,63 +202,20 @@
<!-- 关注公众号 -->
<diy-follow-official-account :value="item"></diy-follow-official-account>
</template>
<template v-if="item.componentName == 'Map'">
<!-- 地图组件 -->
<diy-map :value="item"></diy-map>
</template>
<template v-if="item.componentName == 'Audio'">
<!-- 音频 -->
<diy-audio :value="item"></diy-audio>
</template>
<template v-if="item.componentName == 'ImageNav'">
<!-- 图片导航 -->
<diy-image-nav :value="item"></diy-image-nav>
</template>
<template v-if="item.componentName == 'Digit'">
<!-- 数字 -->
<diy-digit :value="item"></diy-digit>
</template>
<template v-if="item.componentName == 'VideoList'">
<!-- 视频列表 -->
<diy-video-list :value="item"></diy-video-list>
</template>
<template v-if="item.componentName == 'BottomNav'">
<!-- 底部导航 -->
<diy-bottom-nav :value="item"></diy-bottom-nav>
</template>
<template v-if="item.componentName == 'CategoryItem'">
<!-- 分类项 -->
<diy-category-item :value="item"></diy-category-item>
</template>
<template v-if="item.componentName == 'Category'">
<!-- 分类 -->
<diy-category :value="item"></diy-category>
</template>
<template v-if="item.componentName == 'Icon'">
<!-- 图标 -->
<diy-icon :value="item"></diy-icon>
</template>
<template v-if="item.componentName == 'WechatChannel'">
<!-- 微信视频号 -->
<diy-wechat-channel :value="item"></diy-wechat-channel>
</template>
<template v-if="item.componentName == 'WechatChannelList'">
<!-- 微信视频号列表 -->
<diy-wechat-channel-list :value="item"></diy-wechat-channel-list>
</template>
<!-- 自定义扩展组件 -->
<diy-comp-extend :value="item"></diy-comp-extend>
</view>
@@ -268,98 +223,95 @@
</template>
<script>
//
import DiyMinx from './minx.js'
export default {
props: {
diyData: {
type: Object
export default {
components: {},
props: {
diyData: {
type: Object
},
scrollTop: {
type: [String, Number],
default: '0'
},
haveTopCategory: {
type: Boolean
},
followOfficialAccount: {
type: Object
},
},
scrollTop: {
type: [String, Number],
default: '0'
data() {
return {
diyGlobalData: null
};
},
haveTopCategory: {
type: Boolean
created() {
this.diyGlobalData = JSON.parse(JSON.stringify(this.diyData));
},
followOfficialAccount: {
type: Object
},
},
mixins: [DiyMinx],
data() {
return {
diyGlobalData: null
};
},
created() {
this.diyGlobalData = JSON.parse(JSON.stringify(this.diyData));
},
computed: {
topNavColor() {
var color = '';
if (this.diyData.global.topNavBg) {
color = 'transparent';
if (this.scrollTop > 20) {
color = this.diyData.global.topNavColor;
} else {
computed: {
topNavColor() {
var color = '';
if (this.diyData.global.topNavBg) {
color = 'transparent';
if (this.scrollTop > 20) {
color = this.diyData.global.topNavColor;
} else {
color = 'transparent';
}
} else {
color = this.diyData.global.topNavColor;
}
} else {
color = this.diyData.global.topNavColor;
}
return color;
},
//
setPagestyle() {
this.diyGlobalData.value.forEach((item, index) => {
item.pageStyle = '';
//
item.moduleIndex = index + 1;
return color;
},
//
setPagestyle() {
this.diyGlobalData.value.forEach((item, index) => {
item.pageStyle = '';
//
item.moduleIndex = index + 1;
//
if (item.componentName == 'Search' && item.positionWay == 'fixed') {
// item.pageStyle = 'background-color:' + item.pageBgColor + ';';
return false;
}
//
if (item.componentName == 'Search' && item.positionWay == 'fixed') {
// item.pageStyle = 'background-color:' + item.pageBgColor + ';';
return false;
}
item.pageStyle += 'background-color:' + item.pageBgColor + ';';
if (item.margin) {
item.pageStyle += 'padding-top:' + item.margin.top * 2 + 'rpx' + ';';
item.pageStyle += 'padding-bottom:' + item.margin.bottom * 2 + 'rpx' + ';';
item.pageStyle += 'padding-right:' + item.margin.both * 2 + 'rpx' + ';';
item.pageStyle += 'padding-left:' + item.margin.both * 2 + 'rpx' + ';';
}
});
return this.diyGlobalData.value;
},
//
diyDataArray() {
let data = [],
showModuleData = this.$store.state.diyGroupShowModule ? JSON.parse(this.$store.state
.diyGroupShowModule) : '';
if (showModuleData.length) {
if (showModuleData.includes('null')) return [];
let diyDataArr = this.setPagestyle;
diyDataArr.forEach((item, index) => {
if (showModuleData.includes(item.componentName)) {
data.push(item);
item.pageStyle += 'background-color:' + item.pageBgColor + ';';
if (item.margin) {
item.pageStyle += 'padding-top:' + item.margin.top * 2 + 'rpx' + ';';
item.pageStyle += 'padding-bottom:' + item.margin.bottom * 2 + 'rpx' + ';';
item.pageStyle += 'padding-right:' + item.margin.both * 2 + 'rpx' + ';';
item.pageStyle += 'padding-left:' + item.margin.both * 2 + 'rpx' + ';';
}
});
} else data = this.setPagestyle;
return data;
}
},
methods: {}
};
return this.diyGlobalData.value;
},
//
diyDataArray() {
let data = [],
showModuleData = this.$store.state.diyGroupShowModule ? JSON.parse(this.$store.state
.diyGroupShowModule) : '';
if (showModuleData.length) {
if (showModuleData.includes('null')) return [];
let diyDataArr = this.setPagestyle;
diyDataArr.forEach((item, index) => {
if (showModuleData.includes(item.componentName)) {
data.push(item);
}
});
} else data = this.setPagestyle;
return data;
}
},
methods: {}
};
</script>
<style lang="scss">
.diy-group {
width: 100%;
}
.diy-group {
width: 100%;
}
</style>

View File

@@ -0,0 +1,462 @@
<template>
<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" @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)">
</image>
</view>
<view class="content"
v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl || value.btnStyle.control">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ item.groupbuy_price.split('.')[0] }}</text>
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ '.' + item.groupbuy_price.split('.')[1] }}</text>
</view>
<button v-if="value.btnStyle.control" :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'
}">
{{ value.btnStyle.text }}
</button>
</view>
</view>
</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" @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)"/>
<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" :style="{ color: value.theme == 'diy' ? value.saleStyle.color : '' }">
已团{{ item.sell_num }}
</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]" v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ item.groupbuy_price.split('.')[0] }}</text>
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ '.' + item.groupbuy_price.split('.')[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl" :style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">¥{{ item.price }}</view>
</view>
</view>
</scroll-view>
<swiper v-if="value.slideMode == 'slide'" :autoplay="false" class="swiper" :style="{ height: swiperHeight }">
<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"
@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)"/>
<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" :style="{ color: value.theme == 'diy' ? value.saleStyle.color : '' }">已团{{ item.sell_num }}</view>
</view>
<view :class="['content', { 'multi-content': value.nameLineMode == 'multiple' }]" v-if="value.goodsNameStyle.control || value.priceStyle.mainControl || value.priceStyle.lineControl">
<view v-if="value.goodsNameStyle.control" class="goods-name"
:style="{ color: value.theme == 'diy' ? value.goodsNameStyle.color : '', fontWeight: value.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{ 'using-hidden': value.nameLineMode == 'single' }, { 'multi-hidden': value.nameLineMode == 'multiple' }]">
{{ item.goods_name }}
</view>
<view class="discount-price" v-if="value.priceStyle.mainControl">
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">¥</text>
<text class="price price-style large" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ item.groupbuy_price.split('.')[0] }}</text>
<text class="unit price-style small" :style="{ color: value.theme == 'diy' ? value.priceStyle.mainColor + '!important' : '' }">{{ '.' + item.groupbuy_price.split('.')[1] }}</text>
</view>
<view class="original-price price-font" v-if="value.priceStyle.lineControl" :style="{ color: value.theme == 'diy' ? value.priceStyle.lineColor : '' }">¥{{ item.price }}</view>
</view>
</view>
</swiper-item>
</swiper>
</template>
</view>
</x-skeleton>
</template>
<script>
export default {
name: 'diy-groupbuy',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
skeletonType: '',
skeletonConfig: {},
list: [],
page: 1
};
},
created() {
this.initSkeleton();
this.getData();
},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {
this.getData();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
},
// 商品项样式
goodsItemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color + ';';
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color + ';';
}
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(this
.value.goodsMarginNum * 2);
else width = [screenWidth - this.rpxUpPx(20) * 2 - this.rpxUpPx(200) * 3 - this.rpxUpPx(this.value
.margin.both * 2) * 2] / 6;
obj += 'margin-left:' + width + 'px;';
obj += 'margin-right:' + width + 'px;';
}
return obj;
},
swiperHeight() {
if (this.value.nameLineMode == 'multiple') return this.value.ornament.type == 'shadow' ? '404rpx' :
'392rpx';
return this.value.ornament.type == 'shadow' ? '376rpx' : '368rpx';
}
},
methods: {
initSkeleton() {
if (this.value.template == 'row1-of1') {
// 单列 风格
this.skeletonType = 'list';
this.skeletonConfig = {
textRows: 2
};
} else if (this.value.template == 'horizontal-slide') {
// 横向滑动 风格
this.skeletonType = 'waterfall';
this.skeletonConfig = {
gridRows: 1,
gridColumns: 3,
headHeight: '200rpx',
textRows: 2,
textWidth: ['100%', '80%']
};
}
},
rpxUpPx(res) {
const screenWidth = uni.getSystemInfoSync().windowWidth;
var data = (screenWidth * parseInt(res)) / 750;
return Math.floor(data);
},
getData() {
var data = {
num: this.value.count
};
if (this.value.sources == 'diy') {
data.num = 0;
data.goods_id_arr = this.value.goodsId.toString();
}
this.$api.sendRequest({
url: '/groupbuy/api/goods/lists',
data: data,
success: res => {
if (res.code == 0) {
this.list = res.data;
// 切屏滚动,每页显示固定数量
if (this.value.template == 'horizontal-slide' && this.value.slideMode == 'slide') {
let size = 3;
let temp = [];
this.page = Math.ceil(this.list.length / size);
for (var i = 0; i < this.page; i++) {
temp[i] = [];
for (var j = i * size; j < this.list.length; j++) {
if (temp[i].length == size) break;
temp[i].push(this.list[j]);
}
}
this.list = temp;
}
this.loading = false;
}
}
});
},
toDetail(e) {
this.$util.redirectTo('/pages_promotion/groupbuy/detail', {
groupbuy_id: e.groupbuy_id
});
},
imageError(index) {
this.list[index].goods_image = this.$util.getDefaultImage().goods;
this.$forceUpdate();
}
}
};
</script>
<style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
/deep/::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
color: transparent;
background: transparent;
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
touch-action: none;
}
.diy-groupbuy {
&.row1-of1 {
.item {
display: flex;
margin-bottom: 20rpx;
padding: 16rpx;
&.shadow {
margin: 8rpx 8rpx 20rpx 8rpx;
}
&:last-child {
margin-bottom: 0;
padding-bottom: 20rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
>image {
width: 200rpx;
}
}
.goods-name {
margin-top: 6rpx;
line-height: 1.5;
}
.content {
flex: 1;
margin-left: 20rpx;
position: relative;
.discount-price {
white-space: nowrap;
font-weight: bold;
position: absolute;
bottom: 20rpx;
left: 0;
display: flex;
align-items: baseline;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
color: $base-color;
}
}
button {
position: absolute;
bottom: 10rpx;
right: 20rpx;
margin: 0;
padding: 0 20rpx;
background-color: $base-color;
color: #fff;
min-width: 112rpx;
height: 52rpx;
line-height: 52rpx;
font-size: $font-size-tag;
}
}
}
}
&.horizontal-slide {
.scroll {
width: calc(100% - 40rpx);
padding: 20rpx;
line-height: 1;
white-space: nowrap;
.item.shadow {
margin-bottom: 8rpx;
}
}
.flex-between {
justify-content: space-between;
}
.item {
display: inline-block;
width: 200rpx;
overflow: hidden;
box-sizing: border-box;
&:nth-child(3n + 3) {
width: 198rpx;
}
&.shadow {
margin-top: 8rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
position: relative;
overflow: hidden;
margin: 0 auto;
>image {
width: 200rpx;
}
.bg {
position: absolute;
width: 100%;
height: 60rpx;
bottom: 0;
left: 0;
z-index: 2;
}
.num {
width: 180rpx;
position: absolute;
bottom: 10rpx;
padding-left: 20rpx;
font-size: 20rpx;
line-height: 1;
color: #ffffff;
z-index: 3;
}
}
.content {
padding: 10rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
&.multi-content {
height: 158rpx;
box-sizing: border-box;
}
.goods-name {
line-height: 1.3;
&.multi-hidden {
white-space: break-spaces;
}
}
.discount-price {
white-space: nowrap;
margin-top: auto;
font-weight: bold;
line-height: 1;
.unit {
font-size: $font-size-tag;
margin-right: 4rpx;
color: $base-color;
}
.price {
font-size: $font-size-toolbar;
color: $base-color;
}
}
.original-price {
font-size: $font-size-tag;
color: $color-tip;
line-height: 1;
text-decoration: line-through;
}
}
}
.swiper {
width: 100%;
white-space: nowrap;
padding: 20rpx;
box-sizing: border-box;
.swiper-item {
display: flex;
align-items: center;
}
.item {
width: 200rpx;
}
}
}
}
</style>

View File

@@ -4,7 +4,6 @@
<script>
//
import DiyMinx from './minx.js'
export default {
name: 'diy-horz-blank',
props: {
@@ -12,16 +11,15 @@ export default {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {};
},
watch: {
//
componentRefresh: function (nval) { }
componentRefresh: function(nval) {}
},
computed: {
horzBlankGaugeWrap: function () {
horzBlankGaugeWrap: function() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
if (this.value.componentAngle == 'round') {
@@ -34,7 +32,7 @@ export default {
return obj;
}
},
created() { },
created() {},
methods: {}
};
</script>

View File

@@ -1,11 +1,9 @@
<template>
<view data-component-name="diy-horz-line" :style="{ borderTop: '2rpx ' + value.borderStyle + ' ' + value.color }">
</view>
<view data-component-name="diy-horz-line" :style="{ borderTop: '2rpx ' + value.borderStyle + ' ' + value.color }"></view>
</template>
<script>
// 线
import DiyMinx from './minx.js'
export default {
name: 'diy-horz-line',
props: {
@@ -13,13 +11,12 @@ export default {
type: Object
}
},
mixins: [DiyMinx],
data() {
return {};
},
watch: {
//
componentRefresh: function (nval) { }
componentRefresh: function(nval) {}
},
methods: {}
};

View File

@@ -0,0 +1,73 @@
<template>
<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="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 + '%'
}" @click.stop="$util.diyRedirectTo(mapItem.link)"></view>
</view>
</view>
</template>
<script>
export default {
name: 'diy-hot-area',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {};
},
created() {},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {}
},
computed: {
hotAreaWarp: function() {
var obj = '';
obj = 'background-color:' + this.value.componentBgColor + ';';
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;
}
},
methods: {}
};
</script>
<style lang="scss" scoped>
.hot-area-box {
position: relative;
width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.simple-graph-wrap {
line-height: 0;
overflow: hidden;
position: relative;
image {
width: 100%;
}
.heat-map {
position: absolute;
}
}
</style>

View File

@@ -0,0 +1,84 @@
<template>
<view data-component-name="diy-icon" class="diy-icon" :style="iconBgStyle">
<text class="js-icon" :class="iconClass" :style="iconStyle"></text>
</view>
</template>
<script>
export default {
name: 'diy-icon',
props: {
icon: {
type: String,
default: ''
},
value: {
type: Object,
default: function () {
return null;
}
}
},
computed: {
iconClass(){
var _class = ' ' + this.icon;
if (this.value && this.value.iconColor.length > 1) _class += ' gradient';
return _class;
},
iconBgStyle(){
if (!this.value) return {};
var style = {
'border-radius': this.value.bgRadius + '%',
'background': ''
};
if (this.value.iconBgImg) style['background'] += 'url('+ this.$util.img(this.value.iconBgImg) +') no-repeat bottom / contain'
if (this.value.iconBgColor.length) {
if (style.background) style.background += ',';
if (this.value.iconBgColor.length == 1) {
style.background += this.value.iconBgColor[0];
} else {
style['background'] += 'linear-gradient('+ this.value.iconBgColorDeg +'deg, '+ this.value.iconBgColor.join(',') +')';
}
}
return this.$util.objToStyle(style);
},
iconStyle(){
if (!this.value) return {};
var style = {
'font-size': this.value.fontSize + '%'
}
if (this.value.iconColor.length == 1) {
style.color = this.value.iconColor[0];
} else {
style['background'] = 'linear-gradient('+ this.value.iconColorDeg +'deg, '+ this.value.iconColor.join(',') +')';
}
return this.$util.objToStyle(style);
}
}
}
</script>
<style lang="scss">
.diy-icon {
width: 100%;
height: 100%;
font-size: 100%;
color: #000;
display: flex;
align-items: center;
justify-content: center;
.js-icon {
font-size: 50%;
line-height:1;
padding: 1rpx;
&.gradient {
-webkit-background-clip:text!important;
-webkit-text-fill-color:transparent;
}
}
}
</style>

View File

@@ -0,0 +1,310 @@
<template>
<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" @click="handlerClick(imgAdsValue.list[0].link)" @tap="handlerClick(imgAdsValue.list[0].link)">
<image :style="{ height: imgAdsValue.list[0].imgHeight }" :src="$util.img(imgAdsValue.list[0].imageUrl)" mode="widthFix" :show-menu-by-longpress="true"/>
</view>
</block>
<swiper v-else class="swiper" :style="{ height: swiperHeight }" :class="{
'swiper-left': imgAdsValue.indicatorLocation == 'left',
'swiper-right': imgAdsValue.indicatorLocation == 'right',
'ns-indicator-dots': imgAdsValue.carouselStyle == 'line'
}" :autoplay="true" :interval="imgAdsValue.interval" circular="true" :indicator-dots="isDots"
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" @click="handlerClick(item.link)" @tap="handlerClick(item.link)">
<view class="item" :style="imgAdsSwiper + 'height: ' + item.imgHeight">
<image :src="$util.img(item.imageUrl)" :mode="item.imageMode || 'scaleToFill'" :show-menu-by-longpress="true"/>
</view>
</swiper-item>
</swiper>
<!-- #ifdef MP-WEIXIN -->
<view v-if="imgAdsValue.list.length > 1 && value.indicatorIsShow" :class="[
'swiper-dot-box',
{ straightLine: imgAdsValue.carouselStyle == 'line' },
{ 'swiper-left': imgAdsValue.indicatorLocation == 'left' },
{ 'swiper-right': imgAdsValue.indicatorLocation == 'right' }
]">
<view v-for="(numItem, numIndex) in imgAdsValue.list.length" :key="numIndex" :class="['swiper-dot', { active: numIndex == swiperIndex }]" :style="[numIndex == swiperIndex && { backgroundColor: imgAdsValue.indicatorColor }]"></view>
</view>
<!-- #endif -->
</view>
</view>
</template>
<script>
// 图片广告
import DiyMinx from './minx.js'
export default {
name: 'diy-img-ads',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
isDots: true,
swiperHeight: 0,
imgAdsValue: null, // 深拷贝一遍数据,防止动态计算图片展示尺寸的时候,影响到父级的数据,导致二次渲染的时候,数据错误
swiperIndex: 0
};
},
created() {
this.calcSingleRow();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function(nval) {}
},
computed: {
imgAdsMarginWarp: function() {
var obj = '';
obj = 'background-color:' + this.value.componentBgColor + ';';
return obj;
},
imgAdsSwiper: function() {
var obj = '';
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;
},
singleGraphBg: function() {
var imgArr = [];
for (let i = 0; i < this.imgAdsValue.list.length; i++) {
let item = this.imgAdsValue.list[i];
imgArr[i] = parseFloat(item.imgHeight);
}
imgArr.sort(function(a, b) {
return b - a;
});
var obj = '';
obj += 'background-color:' + this.imgAdsValue.backgroundColor + ';';
obj += 'height:' + imgArr[0] * (this.imgAdsValue.backgroundHeight / 100) * 2 + 'rpx;';
return obj;
}
},
methods: {
swiperChange(e) {
this.swiperIndex = e.detail.current;
},
calcSingleRow() {
let minHeight = 0;
let systemInfo = uni.getSystemInfoSync()
// 深拷贝一层数据,防止数据更改越权
this.imgAdsValue = JSON.parse(JSON.stringify(this.value));
this.imgAdsValue.list.forEach((item, index) => {
var ratio = item.imgHeight / item.imgWidth;
item.imgWidth = systemInfo.windowWidth;
item.imgWidth -= this.value.margin.both * 2;
item.imgHeight = item.imgWidth * ratio;
// 获取最大高度 if (maxHeight == 0 || maxHeight < item.imgHeight) maxHeight = item.imgHeight;
if (minHeight == 0 || minHeight > item.imgHeight) minHeight = item.imgHeight;
});
this.imgAdsValue.list.forEach((item, index) => {
item.imgHeight = minHeight + 'px';
this.swiperHeight = minHeight + 'px';
});
this.imgAdsValue.indicatorColor = this.imgAdsValue.indicatorColor || '#fff';
if (this.value.indicatorIsShow === undefined) {
this.value.indicatorIsShow = true; // 控制指示点是否展示
}
// 是否显示指示器
if (this.imgAdsValue.list.length <= 1) {
this.isDots = false;
}
// #ifdef H5
this.isDots = this.value.indicatorIsShow;
// #endif
// #ifdef MP-WEIXIN
this.isDots = false;
// #endif
},
async handlerClick(link) {
await this.__$emitEvent({eventName: 'img-ads-tap', data: link, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.$util.diyRedirectTo(link);
}})
},
}
};
</script>
<style lang="scss" scoped>
.single-graph {
width: 100%;
line-height: 0;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
box-sizing: border-box;
}
.simple-graph-wrap {
line-height: 0;
overflow: hidden;
position: relative;
image {
width: 100%;
}
.heat-map {
position: absolute;
}
}
.item.active text {
background: rgba(0, 0, 0, 0.3);
position: absolute;
bottom: 0;
color: #ffffff;
font-size: $font-size-tag;
width: 100%;
left: 0;
line-height: 40rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding: 0 10rpx;
text-align: center;
}
.swiper-box {
position: relative;
width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.swiper {
margin: 0 auto;
overflow: hidden;
}
.swiper-item {
width: 100%;
height: auto !important;
display: flex;
justify-content: center;
flex-direction: column;
// position: relative;
overflow: hidden;
.item {
width: 100%;
height: auto;
text-align: center;
position: relative;
overflow: hidden;
image {
width: 100%;
max-width: 100%;
height: 100%;
will-change: transform;
}
.heat-map {
position: absolute;
}
}
}
.swiper-dot-box {
position: absolute;
bottom: 20rpx;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 0 40rpx 8rpx;
box-sizing: border-box;
&.swiper-left {
justify-content: flex-start;
}
&.swiper-right {
justify-content: flex-end;
}
.swiper-dot {
background-color: #b2b2b2;
width: 15rpx;
border-radius: 50%;
height: 15rpx;
margin: 8rpx;
&.active {
background-color: rgba(0, 0, 0, 1);
}
}
&.straightLine {
.swiper-dot {
width: 18rpx;
height: 6rpx;
border-radius: 4rpx;
&.active {
width: 36rpx;
background-color: rgba(0, 0, 0, 1);
}
}
}
}
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
/deep/.uni-scroll-view::-webkit-scrollbar {
display: none;
}
.swiper /deep/ .uni-swiper-dots-horizontal {
bottom: 25rpx;
}
.swiper-left /deep/ .uni-swiper-dots-horizontal {
left: 40rpx;
transform: translate(0);
}
.swiper-right /deep/ .uni-swiper-dots-horizontal {
right: 40rpx;
display: flex;
justify-content: flex-end;
transform: translate(0);
}
.carousel-angle /deep/ .uni-swiper-dots-horizontal .uni-swiper-dot {
width: 24rpx;
border-radius: 0;
height: 8rpx;
}
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot {
width: 18rpx;
height: 6rpx;
border-radius: 4rpx;
}
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot-active {
width: 36rpx;
}
</style>

View File

@@ -0,0 +1,830 @@
<template>
<view data-component-name="diy-index-page">
<view class="bg" :style="warpCss">
<view class="index-page-content">
<view class="nav-top-category" :style="categoryCss">
<scroll-view v-if="value" scroll-with-animation class="diyIndex" scroll-x="true"
:scroll-into-view="'a' + pageIndex"
: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"
@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
}" v-if="value.styleType == 'fill'">
{{ item.short_name ? item.short_name : item.category_name }}
</view>
<view class="text-con" :class="index == pageIndex ? 'active' : ''" :style="{ color: index == pageIndex ? value.selectColor : value.noColor }" v-else>
{{ item.short_name ? item.short_name : item.category_name }}
</view>
<view class="color-base-bg line" v-if="index == pageIndex && value.styleType != 'fill'" :style="{ background: value.selectColor ? value.selectColor + '!important' : 'rgba(0,0,0,0)' + '!important' }">
</view>
</view>
</scroll-view>
<text class="iconfont icon-unfold unfold-arrows" :style="{ color: value.moreColor }" @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 }]" @click="changePageIndex(index)">
{{ item.short_name ? item.short_name : item.category_name }}
</text>
</view>
</uni-popup>
<view class="nav_top_category-fill" :style="{ height: moduleHeight }"></view>
<block v-if="pageIndex == 0">
<slot name="components"></slot>
<slot></slot>
</block>
<block v-else>
<slot name="components"></slot>
<view class="index-category-box">
<view class="category-goods" v-show="!isloading">
<mescroll-uni :top="uniPopTop" ref="mescroll" @getData="getGoodsList" :background="'url(' + $util.img(bgUrl) + ') 0px -50px / 100% no-repeat'" :paddingBoth="'30rpx'" @touchmove.prevent.stop>
<block slot="list">
<!-- 二级分类 -->
<view class="twoCategorylist" v-if="twoCategorylist != 'undefined' && twoCategorylist && twoCategorylist.length > 0">
<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" @click="toCateGoodsList(item.category_id_2, 2)">
<view class="item-box">
<image :src="$util.img(item.image)" v-if="item.image" mode="aspectFill"/>
<image :src="$util.getDefaultImage().goods" v-else mode="aspectFill"/>
<view>{{ item.category_name }}</view>
</view>
</view>
</view>
</view>
<view class="twoCategory base" v-if="twoCategorylist.length > 5 && twoCategorylist.length <= 10">
<view class="twoCategory-page">
<view class="swiper-item" v-for="(item, index) in twoCategorylist" :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"/>
<image :src="$util.getDefaultImage().goods" v-else mode="aspectFill"/>
<view>{{ item.category_name }}</view>
</view>
</view>
</view>
</view>
<swiper class="twoCategory big" :duration="500" v-if="twoCategorylist.length > 10" @change="swiperTocategoryChange">
<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" @click="toCateGoodsList(item.category_id_2, 2)">
<view class="item-box">
<image :src="item.image" mode="aspectFill"/>
<view>{{ item.category_name }}</view>
</view>
</view>
</swiper-item>
</swiper>
<view class="dot-box">
<view class="dot-item" v-for="page in maxPage" v-if="maxPage > 1" :key="page" :class="twoCategorylistId == page - 1 ? 'active color-base-bg' : ''"></view>
</view>
</view>
<!-- 分类广告 -->
<image class="category_adv" v-if="cateList[pageIndex].image_adv" :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" @click="toDetail(item)">
<view class="goods-img">
<image :src="goodsImg(item.goods_image)" mode="widthFix" @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)"/>
</view>
</view>
<view class="info-wrap">
<view class="name-wrap">
<view class="goods-name">{{ item.goods_name }}</view>
</view>
<view class="lineheight-clear">
<view class="discount-price">
<text class="unit color-base-text font-size-tag">{{ $lang('common.currencySymbol') }}</text>
<text class="price color-base-text font-size-toolbar">{{ showPrice(item) }}</text>
</view>
<view class="member-price-tag" v-if="item.member_price && item.member_price == showPrice(item)"><image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix"/>
</view>
<view class="member-price-tag" v-else-if="item.promotion_type == 1">
<image :src="$util.img('public/uniapp/index/discount.png')" mode="widthFix"/>
</view>
</view>
<view class="pro-info">
<view class="delete-price font-size-activity-tag color-tip" v-if="showMarketPrice(item)">
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
<text>{{ showMarketPrice(item) }}</text>
</view>
<view class="sale font-size-activity-tag color-tip">已售{{ item.sale_num }}{{ item.unit ? item.unit : '件' }}</view>
</view>
</view>
</view>
</view>
<view v-if="!isloading && goodsList[pageIndex].list.length == 0">
<ns-empty text="该分类下暂无商品" :isIndex="false"></ns-empty>
</view>
</block>
</mescroll-uni>
<!-- <ns-empty v-else-if="!isloading" :isIndex="false" text="该分类下暂无商品"></ns-empty> -->
</view>
<view class="loading" v-show="isloading"><ns-loading ref="loading"></ns-loading></view>
</view>
</block>
</view>
</view>
</view>
</template>
<script>
import nsLoading from '@/components/ns-loading/ns-loading.vue';
export default {
props: {
value: {
type: Object
},
bgUrl: {
type: String
},
scrollTop: {
type: [String, Number],
default: '0'
},
diyGlobal: {
type: Object
}
},
components: {
nsLoading
},
data() {
return {
pageIndex: 0, //当前选中分类id
cateList: [{
//header分类
category_name: '首页'
}],
twoCategorylist: [], //二级分类
twoCategorylistId: 0, //二级分类所在的swiper
goodsList: {},
isloading: true,
top: 0,
isUnfold: true, //是否展开菜单
moduleHeight: '' //组件高度
};
},
computed: {
warpCss() {
var obj = '';
obj += (this.bgUrl ? 'background:' + 'url(' + this.$util.img(this.bgUrl) + ') no-repeat 0 0/100%' : '') + ';';
return obj;
},
categoryCss() {
var obj = '';
obj += 'top:' + this.fixedTop + ';';
// obj += 'background-color:' + (this.value.componentBgColor || this.value.pageBgColor) + ';';
obj += 'background-color:' + this.topNavColor + ';';
return obj;
},
maxPage() {
let num = 0;
if (this.twoCategorylist && this.twoCategorylist.length) {
num = Math.ceil(this.twoCategorylist.length / 10);
}
return num;
},
type() {
if (this.value) {
return true;
} else {
return false;
}
},
topNavColor() {
var color = this.value.componentBgColor || this.value.pageBgColor;
if (this.diyGlobal.topNavBg && this.scrollTop > 20) color = this.diyGlobal.topNavColor;
return color;
},
fixedTop() {
let diyPositionObj = this.$store.state.diyGroupPositionObj;
let data = 0;
if (diyPositionObj.diySearch && diyPositionObj.diyIndexPage && diyPositionObj.nsNavbar) {
if (diyPositionObj.diySearch.moduleIndex > diyPositionObj.diyIndexPage.moduleIndex) data =
diyPositionObj.nsNavbar.originalVal + 'px';
else data = diyPositionObj.nsNavbar.originalVal + diyPositionObj.diySearch.originalVal + 'px';
} else if (diyPositionObj.diyIndexPage && diyPositionObj.nsNavbar) {
data = diyPositionObj.nsNavbar.originalVal + 'px';
}
return data;
},
// 分类导航展开菜单的位置
uniPopTop() {
let diyPositionObj = this.$store.state.diyGroupPositionObj;
let data = '0';
if (this.fixedTop && diyPositionObj.diyIndexPage)
data = Number.parseFloat(this.fixedTop) + diyPositionObj.diyIndexPage.originalVal + 'px';
return data;
}
},
watch: {
type(newVal, oldVal) {
if (newVal) {
this.getCategoryList();
}
}
},
mounted() {
this.getCategoryList();
setTimeout(() => {
// 获取组件的高度默认高度为4545是在375屏幕上的高度
const query = uni.createSelectorQuery();
// #ifdef H5
let cssSelect = '.page-header .u-navbar';
this.top = 100;
// #endif
// #ifdef MP
let cssSelect = '.page-header >>> .u-navbar';
this.top = 20;
// #endif
query
.select(cssSelect)
.boundingClientRect(data => {
let height;
if (this.diyGlobal.navBarSwitch) {
height = data ? data.height : 45;
} else {
height = data ? data.height : 0;
}
// #ifdef H5
this.top += height * 2;
// #endif
// #ifdef MP
this.top += height;
// #endif
})
.exec();
});
this.setModuleLocatinoFn();
},
methods: {
initPageIndex() {
this.pageIndex = 0;
this.showModuleFn();
},
//请求分类列表
getCategoryList() {
let url = '/api/goodscategory/tree';
let data = {
level: 3
};
this.$api.sendRequest({
url: url,
data: data,
success: res => {
if (res.code >= 0) {
let arr = [];
let obj = {
list: []
};
obj.category_name = this.value.title ? this.value.title : '首页';
arr.push(obj);
this.cateList = arr.concat(res.data);
Object.keys(this.cateList).forEach((key, index) => {
this.goodsList[key] = {
page: 1,
list: []
};
});
this.twoCategorylist = this.cateList[this.pageIndex].child_list;
}
}
});
},
//修改当前页面id
changePageIndex(e) {
this.isloading = true;
this.pageIndex = e;
this.showModuleFn();
if (e == 0) return;
this.twoCategorylist = this.cateList[this.pageIndex].child_list;
if (this.cateList[this.pageIndex].child_list) {
this.twoCategorylist = this.cateList[this.pageIndex].child_list;
this.twoCategorylist.forEach(v => {
if (v.image) {
v.image = this.$util.img(v.image);
} else {
v.image = this.$util.getDefaultImage().goods;
}
});
} else {
this.twoCategorylist = false;
}
if (this.$refs.mescroll) {
this.$refs.mescroll.refresh();
this.$refs.mescroll.myScrollTo(0);
}
},
//监听二级分类 页面切换
swiperTocategoryChange(e) {
this.twoCategorylistId = e.detail.current;
},
toDetail(item) {
this.$util.redirectTo('/pages/goods/detail', {
goods_id: item.goods_id
});
},
getGoodsList(mescroll) {
let id = this.pageIndex;
var data = {
page: mescroll.num,
page_size: mescroll.size
};
data.category_id = this.cateList[this.pageIndex].category_id_1;
data.category_level = 1;
this.$api.sendRequest({
url: '/api/goodssku/page',
data: data,
success: res => {
this.isloading = false;
let newArr = [];
let msg = res.message;
if (res.code == 0 && res.data) {
this.count = res.data.count;
newArr = res.data.list;
} else {
this.$util.showToast({
title: msg
});
}
mescroll.endSuccess(newArr.length);
//设置列表数据
if (mescroll.num == 1) this.goodsList[id].list = []; //如果是第一页需手动制空列表
this.goodsList[id].list = this.goodsList[id].list.concat(newArr); //追加新数据
if (this.$refs.loadingCover) this.$refs.loadingCover.hide();
this.$forceUpdate();
}
});
},
toCateGoodsList(e, f) {
this.$util.redirectTo('/pages/goods/list', {
category_id: e,
category_level: f
});
},
goodsImg(imgStr) {
let imgs = imgStr.split(',');
return imgs[0] ? this.$util.img(imgs[0], {
size: 'mid'
}) : this.$util.getDefaultImage().goods;
},
imgError(index) {
this.goodsList[index].goods_image = this.$util.getDefaultImage().goods;
},
showPrice(data) {
let price = data.discount_price;
if (data.member_price && parseFloat(data.member_price) < parseFloat(price)) price = data.member_price;
return price;
},
showMarketPrice(item) {
if (item.market_price_show) {
let price = this.showPrice(item);
if (item.market_price > 0) {
return item.market_price;
} else if (parseFloat(item.price) > parseFloat(price)) {
return item.price;
}
}
return '';
},
goodsTag(data) {
return data.label_name || '';
},
// 控制菜单展开关闭
unfoldMenu() {
if (this.isUnfold) this.$refs.navTopCategoryPop.open();
else this.$refs.navTopCategoryPop.close();
this.isUnfold = !this.isUnfold;
},
// 向vuex中的diyIndexPositionObj增加分类导航组件定位位置
setModuleLocatinoFn() {
const query = uni.createSelectorQuery().in(this);
query.select('.nav-top-category')
.boundingClientRect(data => {
let diyIndexPage = {
originalVal: data.height || 0, //自身高度 px
moduleIndex: this.value.moduleIndex //组件在diy-group的位置
};
this.moduleHeight = (data.height || 0) + 'px';
this.$store.commit('setDiyGroupPositionObj', {
diyIndexPage: diyIndexPage
});
}).exec();
},
showModuleFn() {
let searchModule = this.$root.diyData.value.filter((item, index) => {
return item.componentName == 'Search';
});
// setDiyGroupShowModule值为【】表示显示所有组件,为【null】则什么组件也不显示
if (this.pageIndex == 0) this.$store.commit('setDiyGroupShowModule', JSON.stringify([]));
else {
if (searchModule[0].positionWay == 'fixed') this.$store.commit('setDiyGroupShowModule', JSON.stringify(
['Search']));
else this.$store.commit('setDiyGroupShowModule', JSON.stringify(['null']));
}
// 特殊处理,切换分类导航导致页面无法上下滚动
// #ifdef H5
if (this.pageIndex == 0) {
// 标记当前页使用了mescroll (需延时,确保page已切换)
setTimeout(function() {
let uniPageDom = document.getElementsByTagName('uni-page')[0];
uniPageDom && uniPageDom.removeAttribute('use_mescroll');
}, 30);
}
// #endif
}
}
};
</script>
<style lang="scss">
.bg {
width: 100%;
height: 100%;
}
.nav-top-category {
display: flex;
align-items: center;
position: fixed;
z-index: 999;
transition: background 0.3s;
width: 100%;
padding: 0 24rpx;
box-sizing: border-box;
.text-fiexd {
.text-con {
line-height: 60rpx;
}
}
.unfold-arrows {
position: relative;
margin-left: 4rpx;
padding-left: 16rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
color: #fff;
}
}
.nav-topcategory-pop {
padding: 0 10rpx 20rpx;
display: flex;
flex-wrap: wrap;
background-color: #fff;
.category-item {
padding: 0 30rpx;
height: 60rpx;
text-align: center;
line-height: 56rpx;
border-radius: 40rpx;
background-color: #f0f0f0;
margin: 20rpx 10rpx 0;
font-size: 24rpx;
border: 2rpx solid transparent;
box-sizing: border-box;
&.active {
background-color: transparent;
}
}
}
.diyIndex {
width: 100%;
height: 100rpx;
white-space: nowrap;
padding: 20rpx 0 0;
box-sizing: border-box;
&.widthAuto {
width: auto;
}
.item {
position: relative;
margin-right: 40rpx;
display: inline-block;
line-height: 80rpx;
font-size: $font-size-base;
text-align: center;
.text-con {
height: 30px;
line-height: 30px;
&.active {
font-size: $font-size-base;
font-weight: bold;
}
}
.text-con.active {
font-size: $font-size-base;
font-weight: bold;
}
.line {
position: absolute;
left: calc(50% - 14rpx);
width: 28rpx;
height: 5rpx;
border-radius: 5rpx;
}
&.fill {
border-radius: 50rpx;
padding: 0 10rpx;
.text-con.active {
font-size: $font-size-base;
font-weight: 600;
color: #fff;
}
}
}
}
.index-page-box {
width: 100%;
height: calc(100vh - 288rpx);
}
.index-page-content {
width: 100%;
// height: calc(100vh - 144px);
}
.index-category-box.active {
padding-bottom: 160rpx;
padding-bottom: calc(160rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(160rpx + env(safe-area-inset-bottom));
}
.index-category-box {
width: 100%;
padding-bottom: 110rpx;
padding-bottom: calc(110rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(110rpx + env(safe-area-inset-bottom));
.twoCategorylist {
position: relative;
}
.twoCategory.min {
height: 160rpx;
}
.twoCategory.big {
height: 340rpx;
}
.twoCategory {
width: 100%;
background: #ffffff;
border-radius: 15rpx;
overflow: hidden;
margin-top: 20rpx;
.twoCategory-page {
width: 100%;
height: 100%;
padding: 20rpx;
box-sizing: border-box;
}
.swiper-item {
width: 120rpx;
height: 120rpx;
display: inline-block;
margin-right: calc((100% - 120rpx * 5) / 4);
overflow: hidden;
.item-box {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
image {
width: 88rpx;
height: 88rpx;
}
view {
width: 100%;
font-size: 22rpx;
line-height: 1;
margin-top: 10rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
text-align: center;
}
}
}
.swiper-item:nth-child(5n) {
margin-right: 0;
}
.swiper-item:nth-child(10n + 6) {
margin-top: 15rpx;
}
}
.dot-box {
width: calc(100% - 40rpx);
height: 50rpx;
position: absolute;
bottom: 0rpx;
left: 20rpx;
background: rgba($color: #000000, $alpha: 0);
display: flex;
justify-content: center;
align-items: center;
.dot-item {
width: 12rpx;
height: 12rpx;
background: #cccccc;
border-radius: 6rpx;
margin-right: 10rpx;
}
.dot-item.active {
width: 24rpx;
}
}
.category_adv {
width: 100%;
margin: 20rpx 0;
border-radius: 15rpx;
}
.category-goods {
width: 100%;
}
}
.loading {
width: 100%;
height: 50rpx;
margin-top: 100rpx;
}
/deep/.uni-scroll-view::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none;
}
.goods-list.double-column {
display: flex;
flex-wrap: wrap;
margin-top: $margin-updown;
.goods-item {
flex: 1;
position: relative;
background-color: #fff;
flex-basis: 48%;
max-width: calc((100% - 30rpx) / 2);
margin-right: $margin-both;
margin-bottom: $margin-updown;
border-radius: $border-radius;
&:nth-child(2n) {
margin-right: 0;
}
.goods-img {
position: relative;
overflow: hidden;
padding-top: 100%;
border-top-left-radius: $border-radius;
border-top-right-radius: $border-radius;
image {
width: 100%;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
}
.goods-tag {
color: #fff;
line-height: 1;
padding: 8rpx 16rpx;
position: absolute;
border-bottom-right-radius: $border-radius;
top: 0;
left: 0;
font-size: $font-size-goods-tag;
}
.goods-tag-img {
position: absolute;
border-top-left-radius: $border-radius;
width: 80rpx;
height: 80rpx;
top: 0;
left: 0;
z-index: 5;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.info-wrap {
padding: 0 26rpx 26rpx 26rpx;
}
.goods-name {
font-size: $font-size-base;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin-top: 20rpx;
height: 68rpx;
}
.discount-price {
display: inline-block;
font-weight: bold;
line-height: 1;
margin-top: 16rpx;
.unit {
margin-right: 6rpx;
}
}
.pro-info {
display: flex;
margin-top: 16rpx;
.delete-price {
text-decoration: line-through;
flex: 1;
.unit {
margin-right: 6rpx;
}
}
&>view {
line-height: 1;
&:nth-child(2) {
text-align: right;
}
}
}
.member-price-tag {
display: inline-block;
width: 60rpx;
line-height: 1;
margin-left: 6rpx;
image {
width: 100%;
}
}
}
}
</style>

View File

@@ -0,0 +1,71 @@
<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">
<view class="fui-list jump" v-if="index == 0">
<view class="fui-list-media">
<image class="round" :src="$util.img(item.imageUrl)" style="border-radius:6rpx"></image>
</view>
<view class="fui-list-inner" >
<view class="title" style="color: ;height: 75rpx;">
<text style="font-weight:600" :style="{color:item.textColor}">{{item.title}}</text>
<view class="subtitle" style="font-size:24rpx" :style="{color:item.textColor}">{{item.desc}}</view>
</view>
</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}" @click="previewSqs()">立即添加</span>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'diy-picture',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
};
},
created() {
// this.getDataList();
},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {
// this.getDataList();
}
},
computed: {
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return css;
}
},
methods: {
previewSqs(){
var img = this.$util.img(this.value.list[1].imageUrl)
uni.previewImage({
current: img,
urls: [img]
})
}
}
};
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,77 @@
<template>
<view data-component-name="diy-picture" class="diy-picture" :style="style">
<view class="fui-cell-group">
<!-- <image mode="widthFix" style="width: 100%;" :src="$util.img(item.imageUrl)"></image> -->
<view v-for="(item,index) in value.list" @click="redirectTo(item.link)" class="fui-cell" :class="item.iconType == 'img'?'img-cell':''">
<view class="fui-cell-icon" style="color:diyitem.style.iconcolo">
<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>
<image v-if="item.iconType == 'img'" mode="widthFix" :src="$util.img(item.imageUrl)" style="border-radius:6rpx;width: 60rpx;"></image>
</view>
<view class="fui-cell-text" style="color:#333;">{{item.title}}</view>
<view class="fui-cell-remark" style="font-size: 24rpx;">{{lang=='en-us'?'view':'查看'}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'diy-listmenu',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
lang:uni.getStorageSync("lang")//en-us 英文
};
},
created() {
// this.getDataList();
},
watch: {
// 组件刷新监听
componentRefresh: function(nval) {
// this.getDataList();
}
},
computed: {
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if(this.value.margin.top > 0)css += 'margin-top:' + this.value.margin.top * 2 + 'rpx;';
return css;
}
},
methods: {
redirectTo(link) {
if (link.wap_url) {
if (this.$util.getCurrRoute() == 'pages/member/index' && !this.storeToken) {
this.$refs.login.open(link.wap_url);
return;
}
}
this.$util.diyRedirectTo(link);
},
}
};
</script>
<style lang="scss">
.img-cell{
padding:0 16rpx !important;
}
</style>

View File

@@ -0,0 +1,249 @@
<template>
<x-skeleton data-component-name="diy-live" type="banner" :loading="loading" :configs="skeletonConfig">
<view class="live-wrap" @click="handlerClick(liveInfo.roomid)" @tap="handlerClick(liveInfo.roomid)" v-if="liveInfo">
<view class="banner-wrap">
<image :src="liveInfo.banner != '' ? $util.img(liveInfo.banner) : $util.img('public/uniapp/live/live_default_banner.png')"
mode="widthFix" @error="liveInfo.banner = $util.img('public/uniapp/live/live_default_banner.png')"/>
<view class="shade"></view>
<view class="wrap">
<view class="room-name">
<text class="status-name font-size-base" :class="{ 'color-base-bg': liveInfo.live_status == '101' }">
<text class="iconfont icon-zhibozhong font-size-sub" v-if="liveInfo.live_status == '101'"></text>
<text class="iconfont icon-zhibojieshu font-size-sub" v-else></text>
{{ liveInfo.status_name }}
</text>
{{ liveInfo.name }}
</view>
</view>
</view>
<view class="room-info" v-if="value.isShowAnchorInfo || value.isShowLiveGood">
<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"/>
<text class="anchor-name">主播{{ liveInfo.anchor_name }}</text>
</block>
<text class="separate" v-if="value.isShowAnchorInfo && value.isShowLiveGood">|</text>
<block v-if="value.isShowLiveGood">
<text class="goods-text">直播商品{{ liveInfo.goods.length }}</text>
</block>
</view>
</view>
</x-skeleton>
</template>
<script>
// 直播
import DiyMinx from './minx.js'
export default {
components: {},
name: 'diy-live',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
loading: true,
skeletonConfig: {
headHeight: '200rpx'
},
liveInfo: {
banner: '',
anchor_img: ''
}
};
},
created() {
this.getLiveInfo();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function(nval) {
this.getLiveInfo();
}
},
methods: {
getLiveInfo() {
this.$api.sendRequest({
url: '/live/api/live/info',
success: res => {
if (res.code == 0 && res.data) {
this.liveInfo = res.data;
this.getLiveStatus();
} else {
this.liveInfo = null;
}
this.loading = false;
}
});
},
entryRoom(roomId) {
// #ifdef MP-WEIXIN
wx.navigateTo({
url: `plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=${roomId}`
});
// #endif
},
getLiveStatus() {
// #ifdef MP-WEIXIN
let livePlayer = requirePlugin('live-player-plugin');
livePlayer.getLiveStatus({
room_id: this.liveInfo.roomid
}).then(res => {
const liveStatus = res.liveStatus;
if (liveStatus && liveStatus != this.liveInfo.live_status) {
this.changeLiveStatus(liveStatus);
}
})
.catch(err => {console.log('get live status', err);
});
// 往后间隔1分钟或更慢的频率去轮询获取直播状态
var timer = setInterval(() => {
livePlayer
.getLiveStatus({
room_id: this.liveInfo.roomid
})
.then(res => {
const liveStatus = res.liveStatus;
if (liveStatus && liveStatus != this.liveInfo.live_status) {
this.changeLiveStatus(liveStatus);
}
if (this.$util.inArray(liveStatus, [103, 104, 106, 107])) {
clearInterval(timer);
}
})
.catch(err => {
console.log('get live status', err);
});
}, 60000);
// #endif
},
changeLiveStatus(status) {
this.$api.sendRequest({
url: '/live/api/live/modifyLiveStatus',
data: {
room_id: this.liveInfo.roomid,
status: status
},
success: res => {
if (res.code == 0) {
this.getLiveInfo();
}
}
});
},
async handlerClick(roomid) {
await this.__$emitEvent({eventName: 'live-tap', data: roomid, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.entryRoom(roomid);
}})
},
}
};
</script>
<style lang="scss">
.live-wrap {
background: #fff;
border-radius: 16rpx;
overflow: hidden;
}
.banner-wrap {
width: 100%;
position: relative;
line-height: 1;
display: flex;
image {
width: 100%;
}
.shade {
width: 100%;
height: 100%;
position: absolute;
background: rgba($color: #888, $alpha: 0.3);
left: 0;
top: 0;
z-index: 5;
}
.wrap {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 10;
padding: 26rpx 20rpx;
box-sizing: border-box;
.room-name {
font-size: $font-size-toolbar;
color: #fff;
line-height: 1;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: flex;
align-items: center;
.status-name {
display: inline-block;
font-size: $font-size-activity-tag;
color: #fff;
padding: 8rpx 12rpx;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 36rpx;
margin-right: 20rpx;
.icon-zhibozhong {
font-size: $font-size-activity-tag;
color: #fff;
margin-right: 9rpx;
}
}
}
}
}
.room-info {
padding: 20rpx 30rpx;
background: #fff;
display: flex;
.anchor-img {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 20rpx;
}
.anchor-name,
.goods-text {
font-size: $font-size-base;
line-height: 60rpx;
}
.separate {
color: #808080;
margin: 0 10rpx;
line-height: 56rpx;
}
}
</style>
<style scoped>
.coupon-all>>>.uni-scroll-view::-webkit-scrollbar {
display: none;
}
</style>

View File

@@ -0,0 +1,255 @@
<template>
<view data-component-name="diy-many-goods-list" class="many-goods-list">
<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" @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 class="desc" :class="{ 'color-base-bg': index == cateIndex && item.desc }">{{ item.desc }}
</view>
</view>
</view>
</scroll-view>
<view class="many-goods-list-fill" :style="{'height': manyInfo.height}" v-if="fixedTop"></view>
<diy-goods-list class="many-goods-list-body" v-if="goodsValue" :value="goodsValue" ref="diyGoodsList"></diy-goods-list>
</view>
</template>
<script>
import DiyMinx from './minx.js'
export default {
name: 'diy-many-goods-list',
props: {
value: {
type: Object,
default: () => {
return {};
}
},
scrollTop: {
type: [Number, String]
},
global: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
cateIndex: 0, // 当前选中的分类id
goodsValue: null, // 商品列表数据
manyInfo: {
bodyHeight: 0,
bodyTop: 0,
height: 0,
top: 0
}
};
},
created() {
this.changeCateIndex(this.value.list[0], 0, true);
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function(nval) {
this.changeCateIndex(this.value.list[0], 0, true);
},
scrollTop: function(nval) {
const query = uni.createSelectorQuery().in(this);
query
.select('.many-goods-list')
.boundingClientRect(data => {
if (data) {
this.manyInfo.top = data.top;
}
})
.exec();
query
.select('.many-goods-list .many-goods-list-body')
.boundingClientRect(data => {
if (data) {
this.manyInfo.bodyHeight = (data.height || 0);
this.manyInfo.bodyTop = (data.top || 0);
}
})
.exec();
}
},
computed: {
fixedTop() {
let diyPositionObj = JSON.parse(JSON.stringify(this.$store.state.diyGroupPositionObj));
let positionHeight = 0;
let height = 0;
delete diyPositionObj.diyManyGoodsList;
if (diyPositionObj) {
let arr = Object.values(diyPositionObj);
arr.forEach((item, index) => {
positionHeight += item.originalVal; //定位的高度【搜索框+导航分类+自定义头部】
});
}
if (this.manyInfo.top < positionHeight && (this.manyInfo.bodyTop + this.manyInfo.bodyHeight >
positionHeight + Number.parseFloat(this.manyInfo.height))) {
height = positionHeight;
}
return height;
},
manyWrapCss() {
let html = '';
html += `position: ${this.fixedTop ? 'fixed' : 'initial'};`
html += `top: ${this.fixedTop}px;`
if (!this.global.topNavBg)
html += `background-color: #fff;`
else
html += `background-color: ${this.fixedTop ? this.global.topNavColor : 'transparent'};`
return html;
}
},
mounted() {
const query = uni.createSelectorQuery().in(this);
query
.select('.many-goods-list .many-goods-list-head')
.boundingClientRect(data => {
if (data) {
this.manyInfo.height = (data.height || 0) + 'px';
// 向vuex中的diyIndexPositionObj增加多商品组件定位位置
let diyManyGoodsList = {
originalVal: data.height || 0 //自身高度 px
}
this.$store.commit('setDiyGroupPositionObj', {
diyManyGoodsList: diyManyGoodsList
});
}
})
.exec();
},
methods: {
changeCateIndex(item, index, isFirst) {
this.cateIndex = index;
this.goodsValue = {
sources: item.sources,
categoryId: item.categoryId,
categoryName: item.categoryName,
goodsId: item.goodsId,
componentBgColor: this.value.componentBgColor,
componentAngle: this.value.componentAngle,
topAroundRadius: this.value.topAroundRadius,
bottomAroundRadius: this.value.bottomAroundRadius,
elementBgColor: this.value.elementBgColor,
elementAngle: this.value.elementAngle,
topElementAroundRadius: this.value.topElementAroundRadius,
bottomElementAroundRadius: this.value.bottomElementAroundRadius,
count: this.value.count,
nameLineMode: this.value.nameLineMode,
template: this.value.template,
style: this.value.style,
ornament: this.value.ornament,
sortWay: this.value.sortWay,
saleStyle: this.value.saleStyle,
tag: this.value.tag,
btnStyle: this.value.btnStyle,
goodsNameStyle: this.value.goodsNameStyle,
theme: this.value.theme,
priceStyle: this.value.priceStyle,
slideMode: this.value.slideMode,
imgAroundRadius: this.value.imgAroundRadius,
margin: this.value.margin,
goodsMarginType: this.value.goodsMarginType,
goodsMarginNum: this.value.goodsMarginNum
};
// 如果是第一次加载,不需要执行下面代码
if (isFirst) return;
this.$refs.diyGoodsList.goodsValue = this.goodsValue;
this.$refs.diyGoodsList.getGoodsList();
},
async handlerClick({item,index}) {
await this.__$emitEvent({eventName: 'many-goods-list-tap', data: {item,index}, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.changeCateIndex(item, index, false);
}})
},
}
};
</script>
<style lang="scss" scoped>
.many-goods-list-head {
left: 0;
right: 0;
z-index: 5;
background-color: #fff;
}
scroll-view {
width: 100%;
white-space: nowrap;
box-sizing: border-box;
padding: 20rpx 0;
.scroll-item {
display: inline-block;
text-align: center;
vertical-align: top;
width: calc(25% - 40rpx);
position: relative;
padding: 0 20rpx;
&:first-child {
width: calc(25% - 20rpx);
padding-left: 0;
}
.split-line {
display: inline-block;
width: 1rpx;
height: 30rpx;
background-color: #e5e5e5;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
&.active {
.name {
font-weight: bold;
}
.desc {
color: #ffffff;
border-radius: 20rpx;
}
}
.name {
font-size: 32rpx;
color: $color-title;
line-height: 1;
}
.cate {
display: inline-block;
}
.desc {
font-size: $font-size-tag;
color: $color-tip;
height: 36rpx;
line-height: 36rpx;
margin-top: 10rpx;
min-width: 120rpx;
max-width: 220rpx;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 10rpx;
}
}
}
</style>

View File

@@ -0,0 +1,87 @@
<template>
<view data-component-name="diy-map" class="diy-map" :style="style">
<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 style="position:absolute;right:10px;bottom:30rpx;z-index:99999;background:#4390FF;padding:5px 10px;wxcs_style_padding:10rpx 20rpx;border-radius:8rpx;color: #fff;" @click="handlerClick(item)" @tap="handlerClick(item)">
<cover-view style="font-size:24rpx">一键导航</cover-view>
</cover-view>
</map>
</view>
</view>
</template>
<script>
// 地图
import DiyMinx from './minx.js'
export default {
name: 'diy-map',
props: {
value: {
type: Object
}
},
data() {
return {
loading: true,
markers:[]
};
},
created() {
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function(nval) {
// this.getDataList();
}
},
computed: {
markerst(){
return [{
id:1,
latitude:this.value.list[0].lat,
longitude:this.value.list[0].lng
}]
},
style() {
var css = '';
css += 'background-color:' + this.value.contentBgColor + ';';
if (this.value.elementAngle == 'round') {
css += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
css += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
return css;
}
},
methods: {
tomap(item){
uni.openLocation({
latitude: parseFloat(item.lat),
longitude: parseFloat(item.lng),
name:"一键导航",
})
},
async handlerClick(item) {
await this.__$emitEvent({eventName: 'map-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.tomap(item);
}})
}
}
};
</script>
<style lang="scss">
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,249 @@
<template>
<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" @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"/>
<view class="icon-shade" :style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_pay_shade.png') + ')'"></view>
</template>
<template v-else>
<diy-icon :icon="value.icon.waitPay.icon" v-if="value.icon.waitPay" :value="value.icon.waitPay.style ? value.icon.waitPay.style : null"></diy-icon>
</template>
<text v-if="orderNum.waitpay > 0" class="order-num color-base-bg price-font">{{ orderNum.waitpay > 99 ? '99+' : orderNum.waitpay }}</text>
</view>
<view class="title">{{ $lang('waitpay') }}</view>
</view>
<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"></image>
<view class="icon-shade" :style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_send_shade.png') + ')'"></view>
</template>
<template v-else>
<diy-icon :icon="value.icon.waitSend.icon" v-if="value.icon.waitSend" :value="value.icon.waitSend.style ? value.icon.waitSend.style : null"></diy-icon>
</template>
<text v-if="orderNum.waitsend > 0" class="order-num color-base-bg price-font">{{ orderNum.waitsend > 99 ? '99+' : orderNum.waitsend }}</text>
</view>
<view class="title">{{ $lang('waitsend') }}</view>
</view>
<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"/>
<view class="icon-shade" :style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_confirm_shade.png') + ')'"></view>
</template>
<template v-else>
<diy-icon :icon="value.icon.waitConfirm.icon" v-if="value.icon.waitConfirm" :value="value.icon.waitConfirm.style ? value.icon.waitConfirm.style : null"></diy-icon>
</template>
<text v-if="orderNum.waitconfirm > 0" class="order-num color-base-bg price-font">{{ orderNum.waitconfirm > 99 ? '99+' : orderNum.waitconfirm }}</text>
</view>
<view class="title">{{ $lang('waitconfirm') }}</view>
</view>
<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"/>
<view class="icon-shade" :style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/wait_rate_shade.png') + ')'"></view>
</template>
<template v-else>
<diy-icon :icon="value.icon.waitUse.icon" v-if="value.icon.waitUse" :value="value.icon.waitUse.style ? value.icon.waitUse.style : null"></diy-icon>
</template>
<!-- <text v-if="orderNum.wait_use > 0" class="order-num color-base-bg price-font">{{ orderNum.wait_use > 99 ? '99+' : orderNum.wait_use }}</text> -->
</view>
<view class="title">{{ $lang('completed') }}</view>
</view>
<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"/>
<view class="icon-shade" :style="'-webkit-mask-image: url(' + $util.img('public/uniapp/member/order/refunding_shade.png') + ')'"></view>
</template>
<template v-else>
<diy-icon :icon="value.icon.refunding.icon" v-if="value.icon.refunding" :value="value.icon.refunding.style ? value.icon.refunding.style : null"></diy-icon>
</template>
<text v-if="orderNum.refunding > 0" class="order-num color-base-bg price-font">{{ orderNum.refunding > 99 ? '99+' : orderNum.refunding }}</text>
</view>
<view class="title">{{ $lang('activist') }}</view>
</view>
</view>
</view>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
// 自定义会员中心——我的订单
export default {
name: 'diy-member-my-order',
props: {
value: {
type: Object
}
},
data() {
return {
orderNum: {
waitpay: 0,
waitsend: 0,
waitconfirm: 0,
refunding: 0,
wait_use: 0,
waitrate: 0
}
};
},
created() {
this.init();
},
watch: {
storeToken(nVal, oVal) {
this.init();
},
// 组件刷新监听
componentRefresh: function(nval) {
this.init();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;
}
},
methods: {
init() {
if (this.storeToken) {
this.getOrderNum();
} else {
this.orderNum = {
waitpay: 0,
waitsend: 0,
waitconfirm: 0,
refunding: 0,
wait_use: 0,
waitrate: 0
};
}
},
/**
* 获取订单数量
*/
getOrderNum() {
this.$api.sendRequest({
url: '/api/order/num',
data: {
order_status: 'waitpay,waitsend,waitconfirm,refunding,wait_use,waitrate'
},
success: res => {
if (res.code == 0) {
this.orderNum = res.data;
} else {
this.orderNum = {
waitpay: 0,
waitsend: 0,
waitconfirm: 0,
refunding: 0,
wait_use: 0,
waitrate: 0
};
}
}
});
},
/**
* 跳转
* @param {Object} url
*/
redirect(url) {
if (this.storeToken) {
this.$util.redirectTo(url);
} else {
this.$refs.login.open(url);
}
}
}
};
</script>
<style lang="scss">
.common-wrap {
width: 100%;
box-sizing: border-box;
}
.order-wrap {
.status-wrap {
display: flex;
padding: 30rpx 0;
align-items: center;
justify-content: center;
color: #333;
}
.item-wrap {
flex: 1;
text-align: center;
background: #f6f7f9;
padding: 20rpx 0;
.icon-block {
width: 60rpx;
height: 60rpx;
font-size: 60rpx;
margin: 4rpx auto;
position: relative;
&>image {
position: absolute;
top: 5%;
right: 5%;
width: 90%;
height: 90%;
z-index: 5;
}
.icon-shade {
width: 90%;
height: 90%;
position: absolute;
z-index: 4;
top: 5%;
right: 5%;
background: $base-color;
-webkit-mask: no-repeat center / contain;
}
}
.order-num {
position: absolute;
top: 0;
right: 0;
transform: translate(50%, -50%);
box-sizing: border-box;
color: #ffffff;
line-height: 1.2;
text-align: center;
font-size: 24rpx;
padding: 0 6rpx;
min-width: 30rpx;
border-radius: 16rpx;
height: 30rpx;
display: flex;
align-items: center;
justify-content: center;
}
.title {
font-size: 26rpx;
}
}
}
</style>

View File

@@ -0,0 +1,358 @@
<template>
<view class="diy-merch-list">
<x-skeleton type="list" :loading="loading" :configs="skeletonConfig" v-if="value.ornament.type == 'default'">
<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" @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)" />
</view>
<view class="info-wrap">
<text class="title">{{ item.merch_name }}</text>
<text class="desc">{{ item.desc }}</text>
<view class="read-wrap"></view>
</view>
</view>
</view>
</view>
</x-skeleton>
<view v-else :style="warpCss">
<scroll-view :scroll-x="true" :class="['merch-nav', 'singleSlide' ]">
<!-- #ifdef MP -->
<view class="uni-scroll-view-content">
<!-- #endif -->
<view class="merch-nav-item graphic" v-for="(item, index) in list" :key="index" :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="true"
style="max-width: 80rpx; max-height: 80rpx; border-radius: 50rpx;"
/>
</view>
<text class="graphic-text" style="font-size: 28rpx; font-weight: normal; color: rgb(48, 49, 51);">
{{ item.merch_name }}
</text>
</view>
<!-- #ifdef MP -->
</view>
<!-- #endif -->
</scroll-view>
</view>
</view>
</template>
<script>
// 文章
import DiyMinx from './minx.js'
export default {
name: 'diy-article',
props: {
value: {
type: Object
}
},
data() {
return {
list: [
/*{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
},
{
merch_name:'品牌',
merch_image:'http://saas.cn//upload/4/common/images/20240824/20240824040223172448654356147.jpg'
}*/
],
loading: true,
skeletonConfig: {
gridRows: 1,
gridRowsGap: '40rpx',
headWidth: '160rpx',
headHeight: '160rpx',
textRows: 2
}
};
},
created() {
this.getList();
},
mixins: [DiyMinx],
watch: {
// 组件刷新监听
componentRefresh: function (nval) {
this.getList();
}
},
computed: {
warpCss() {
var obj = '';
obj += 'background-color:' + this.value.componentBgColor + ';';
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;';
}
console.log(obj)
return obj;
},
// 子项样式
itemCss() {
var obj = '';
obj += 'background-color:' + this.value.elementBgColor + ';';
if (this.value.elementAngle == 'round') {
obj += 'border-top-left-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-top-right-radius:' + this.value.topElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-left-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
obj += 'border-bottom-right-radius:' + this.value.bottomElementAroundRadius * 2 + 'rpx;';
}
if (this.value.ornament.type == 'shadow') {
obj += 'box-shadow:' + '0 0 10rpx ' + this.value.ornament.color;
}
if (this.value.ornament.type == 'stroke') {
obj += 'border:' + '2rpx solid ' + this.value.ornament.color;
}
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();
}
this.$api.sendRequest({
url: '/merch/api/merch/lists',
data: data,
success: res => {
if (res.code == 0 && res.data) {
let data = res.data;
this.list = data;
}
this.loading = false;
}
});
},
toDetail(item) {
this.$util.redirectTo('/pages_promotion/merch/detail', {
merch_id: item.merch_id
});
},
imgError(index) {
if (this.list[index]) this.list[index].merch_image = this.$util.getDefaultImage().article;
},
async handlerClick(item) {
await this.__$emitEvent({eventName: 'merch-list-tap', data: item, promiseCallback: (event, handler, awaitedResult) => {
if (!awaitedResult) return;
this.toDetail(item);
}})
}
}
};
</script>
<style>
/* 单行滑动 */
.merch-nav.singleSlide>>>.uni-scroll-view-content {
display: flex;
}
</style>
<style lang="scss">
.merch-nav {
padding: 16rpx;
box-sizing: border-box;
&.singleSlide {
.merch-nav-item {
flex-shrink: 0;
}
}
&.pageSlide {
position: relative;
.merch-nav-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
}
.merch-nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 14rpx 0;
box-sizing: border-box;
.graphic-text {
padding-top: 12rpx;
line-height: 1.5;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
&.alone {
padding-top: 0;
}
}
&.text {
.graphic-text {
padding-top: 0;
}
}
.graphic-img {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
font-size: 24rpx;
.tag {
position: absolute;
top: -10rpx;
right: -24rpx;
color: #fff;
border-radius: 24rpx;
border-bottom-left-radius: 0;
transform: scale(0.8);
padding: 8rpx 16rpx;
line-height: 1;
font-size: 24rpx;
}
.icon {
font-size: 50rpx;
color: $color-sub;
}
}
}
}
.merch-wrap {
.list-wrap {
&.style-1 {
.item {
display: flex;
padding: 20rpx;
margin-top: 24rpx;
&:first-of-type {
margin-top: 0;
}
.merch-img {
margin-right: 20rpx;
width: 160rpx;
height: 160rpx;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
image {
width: 100%;
}
}
.info-wrap {
// flex: 1;
// display: flex;
// flex-direction: column;
// justify-content: space-between;
.desc{
color:#888
}
.title {
font-weight: bold;
// margin-bottom: 10rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: 30rpx;
line-height: 1.5;
}
.abstract {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: $font-size-tag;
}
.read-wrap {
display: flex;
color: #999ca7;
justify-content: flex-start;
align-items: center;
margin-top: 10rpx;
line-height: 1;
text {
font-size: $font-size-tag;
}
.iconfont {
font-size: 36rpx;
vertical-align: bottom;
margin-right: 10rpx;
}
.category-icon {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: $base-color;
margin-right: 10rpx;
}
.date {
margin-left: 20rpx;
}
}
}
}
}
}
}
</style>

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