Compare commits
No commits in common. "00ab94b840a37028810e51cd90b0c121510909ce" and "892fccb4d81b0eed7cad9878ae4975a9c33de3df" have entirely different histories.
00ab94b840
...
892fccb4d8
47
App.vue
47
App.vue
@ -5,32 +5,32 @@ import { goLogin } from "@/hooks/useGoLogin";
|
|||||||
import { goHome } from "@/hooks/useGoHome";
|
import { goHome } from "@/hooks/useGoHome";
|
||||||
|
|
||||||
onLaunch(async () => {
|
onLaunch(async () => {
|
||||||
console.log("App Launch");
|
console.log("App Launch");
|
||||||
|
|
||||||
const token = uni.getStorageSync("token");
|
const token = uni.getStorageSync("token");
|
||||||
|
|
||||||
// 检测是否绑定手机号和token
|
// 检测是否绑定手机号和token
|
||||||
if (!token) {
|
if (!token) {
|
||||||
goLogin();
|
goLogin();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
const res = await checkPhone();
|
const res = await checkPhone();
|
||||||
|
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
goHome();
|
goHome();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
console.log("App Show");
|
console.log("App Show");
|
||||||
});
|
});
|
||||||
|
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
console.log("App Hide");
|
console.log("App Hide");
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -41,18 +41,13 @@ onHide(() => {
|
|||||||
page,
|
page,
|
||||||
body,
|
body,
|
||||||
#app {
|
#app {
|
||||||
font-family: PingFang SC, PingFang SC;
|
font-family: PingFang SC, PingFang SC;
|
||||||
background-color: #e9f3f7;
|
background-color: #e9f3f7;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
}
|
|
||||||
|
|
||||||
/*每个页面公共css */
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mb12 {
|
.mb12 {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<view class="chat-ai">
|
<view class="chat-ai">
|
||||||
<view class="loading-container" >
|
<ChatMarkdown :key="textKey" :text="processedText" />
|
||||||
<image v-if="isLoading" class="loading-img" src="/static/msg_loading.svg" />
|
<slot name="content"></slot>
|
||||||
<ChatMarkdown :key="textKey" :text="processedText" />
|
|
||||||
</view>
|
|
||||||
<slot name="content"></slot>
|
|
||||||
</view>
|
|
||||||
<slot name="footer"></slot>
|
|
||||||
</view>
|
</view>
|
||||||
|
<slot name="footer"></slot>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -16,14 +13,10 @@ import { defineProps, computed, ref, watch } from "vue";
|
|||||||
import ChatMarkdown from "./ChatMarkdown.vue";
|
import ChatMarkdown from "./ChatMarkdown.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
text: {
|
text: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
isLoading: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 用于强制重新渲染的key
|
// 用于强制重新渲染的key
|
||||||
@ -31,63 +24,50 @@ const textKey = ref(0);
|
|||||||
|
|
||||||
// 处理文本内容
|
// 处理文本内容
|
||||||
const processedText = computed(() => {
|
const processedText = computed(() => {
|
||||||
if (!props.text) {
|
if (!props.text) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保文本是字符串类型
|
// 确保文本是字符串类型
|
||||||
const textStr = String(props.text);
|
const textStr = String(props.text);
|
||||||
|
|
||||||
// 处理加载状态的文本
|
|
||||||
if (textStr.includes("加载中") || textStr.includes("...")) {
|
|
||||||
return textStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 处理加载状态的文本
|
||||||
|
if (textStr.includes("加载中") || textStr.includes("...")) {
|
||||||
return textStr;
|
return textStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return textStr;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听text变化,强制重新渲染
|
// 监听text变化,强制重新渲染
|
||||||
watch(
|
watch(
|
||||||
() => props.text,
|
() => props.text,
|
||||||
(newText, oldText) => {
|
(newText, oldText) => {
|
||||||
if (newText !== oldText) {
|
if (newText !== oldText) {
|
||||||
textKey.value++;
|
textKey.value++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-width: 100%; // ✅ 限制最大宽度
|
max-width: 100%; // ✅ 限制最大宽度
|
||||||
overflow-x: hidden; // ✅ 防止横向撑开
|
overflow-x: hidden; // ✅ 防止横向撑开
|
||||||
|
|
||||||
.chat-ai {
|
.chat-ai {
|
||||||
margin: 6px 12px;
|
margin: 6px 12px;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
|
|
||||||
min-width: 90px;
|
min-width: 80px;
|
||||||
background: rgba(255, 255, 255, 0.4);
|
background: rgba(255, 255, 255, 0.4);
|
||||||
box-shadow: 2px 2px 6px 0px rgba(0, 0, 0, 0.1);
|
box-shadow: 2px 2px 6px 0px rgba(0, 0, 0, 0.1);
|
||||||
border-radius: 4px 20px 20px 20px;
|
border-radius: 4px 20px 20px 20px;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
border-color: #ffffff;
|
border-color: #ffffff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
.loading-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-img {
|
|
||||||
margin-left: -4px;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@ -1,65 +1,62 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="input-area-wrapper">
|
<view class="input-area-wrapper">
|
||||||
<view v-if="!visibleWaveBtn" class="area-input">
|
<view v-if="!visibleWaveBtn" class="area-input">
|
||||||
<!-- 语音/键盘切换 -->
|
<!-- 语音/键盘切换 -->
|
||||||
<view class="input-container-voice" @click="toggleVoiceMode">
|
<view class="input-container-voice" @click="toggleVoiceMode">
|
||||||
<image
|
<image v-if="!isVoiceMode" src="/static/input_voice_icon.png"></image>
|
||||||
v-if="!isVoiceMode"
|
<image v-else src="/static/input_keyboard_icon.png"></image>
|
||||||
src="/static/input_voice_icon.png"
|
</view>
|
||||||
></image>
|
|
||||||
<image v-else src="/static/input_keyboard_icon.png"></image>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 输入框/语音按钮容器 -->
|
<!-- 输入框/语音按钮容器 -->
|
||||||
<view class="input-button-container">
|
<view class="input-button-container">
|
||||||
<textarea
|
<textarea
|
||||||
ref="textareaRef"
|
ref="textareaRef"
|
||||||
v-if="!isVoiceMode"
|
v-if="!isVoiceMode"
|
||||||
class="textarea"
|
:class="['textarea', ios ? 'ios' : 'android']"
|
||||||
type="text"
|
type="text"
|
||||||
cursor-spacing="20"
|
cursor-spacing="65"
|
||||||
confirm-type="send"
|
confirm-type="send"
|
||||||
v-model="inputMessage"
|
v-model="inputMessage"
|
||||||
auto-height
|
auto-height
|
||||||
:confirm-hold="true"
|
:confirm-hold="true"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:show-confirm-bar="false"
|
:show-confirm-bar="false"
|
||||||
:hold-keyboard="holdKeyboard"
|
:hold-keyboard="holdKeyboard"
|
||||||
:adjust-position="true"
|
:adjust-position="true"
|
||||||
:disable-default-padding="true"
|
:disable-default-padding="true"
|
||||||
maxlength="300"
|
maxlength="300"
|
||||||
@confirm="sendMessage"
|
@confirm="sendMessage"
|
||||||
@focus="handleFocus"
|
@focus="handleFocus"
|
||||||
@blur="handleBlur"
|
@blur="handleBlur"
|
||||||
@touchstart="handleTouchStart"
|
@touchstart="handleTouchStart"
|
||||||
@touchend="handleTouchEnd"
|
@touchend="handleTouchEnd"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<view
|
<view
|
||||||
v-if="isVoiceMode"
|
v-if="isVoiceMode"
|
||||||
class="hold-to-talk-button"
|
class="hold-to-talk-button"
|
||||||
@longpress="handleVoiceTouchStart"
|
@longpress="handleVoiceTouchStart"
|
||||||
@touchend="handleVoiceTouchEnd"
|
@touchend="handleVoiceTouchEnd"
|
||||||
@touchcancel="handleVoiceTouchEnd"
|
@touchcancel="handleVoiceTouchEnd"
|
||||||
>
|
>
|
||||||
按住 说话
|
按住 说话
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="input-container-send">
|
|
||||||
<view class="input-container-send-btn" @click="sendMessage">
|
|
||||||
<image
|
|
||||||
v-if="props.isSessionActive"
|
|
||||||
src="/static/input_stop_icon.png"
|
|
||||||
></image>
|
|
||||||
<image v-else src="/static/input_send_icon.png"></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 录音按钮 -->
|
<view class="input-container-send">
|
||||||
<RecordingWaveBtn v-if="visibleWaveBtn" ref="recordingWaveBtnRef" />
|
<view class="input-container-send-btn" @click="sendMessage">
|
||||||
|
<image
|
||||||
|
v-if="props.isSessionActive"
|
||||||
|
src="/static/input_stop_icon.png"
|
||||||
|
></image>
|
||||||
|
<image v-else src="/static/input_send_icon.png"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 录音按钮 -->
|
||||||
|
<RecordingWaveBtn v-if="visibleWaveBtn" ref="recordingWaveBtnRef" />
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -70,18 +67,18 @@ const plugin = requirePlugin("WechatSI");
|
|||||||
const manager = plugin.getRecordRecognitionManager();
|
const manager = plugin.getRecordRecognitionManager();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: String,
|
modelValue: String,
|
||||||
holdKeyboard: Boolean,
|
holdKeyboard: Boolean,
|
||||||
isSessionActive: Boolean,
|
isSessionActive: Boolean,
|
||||||
stopRequest: Function,
|
stopRequest: Function,
|
||||||
});
|
});
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
"update:modelValue",
|
"update:modelValue",
|
||||||
"send",
|
"send",
|
||||||
"noHideKeyboard",
|
"noHideKeyboard",
|
||||||
"keyboardShow",
|
"keyboardShow",
|
||||||
"keyboardHide",
|
"keyboardHide",
|
||||||
"sendVoice",
|
"sendVoice",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const textareaRef = ref(null);
|
const textareaRef = ref(null);
|
||||||
@ -93,139 +90,144 @@ const keyboardHeight = ref(0);
|
|||||||
const isVoiceMode = ref(false);
|
const isVoiceMode = ref(false);
|
||||||
const visibleWaveBtn = ref(false);
|
const visibleWaveBtn = ref(false);
|
||||||
|
|
||||||
|
// 判断当前平台是否为iOS
|
||||||
|
const ios = computed(() => {
|
||||||
|
return uni.getSystemInfoSync().platform === "ios";
|
||||||
|
});
|
||||||
|
|
||||||
// 保持和父组件同步
|
// 保持和父组件同步
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(val) => {
|
(val) => {
|
||||||
inputMessage.value = val;
|
inputMessage.value = val;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 当子组件的 inputMessage 变化时,通知父组件(但要避免循环更新)
|
// 当子组件的 inputMessage 变化时,通知父组件(但要避免循环更新)
|
||||||
watch(inputMessage, (val) => {
|
watch(inputMessage, (val) => {
|
||||||
// 只有当值真正不同时才emit,避免循环更新
|
// 只有当值真正不同时才emit,避免循环更新
|
||||||
if (val !== props.modelValue) {
|
if (val !== props.modelValue) {
|
||||||
emit("update:modelValue", val);
|
emit("update:modelValue", val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 切换语音/文本模式
|
// 切换语音/文本模式
|
||||||
const toggleVoiceMode = () => {
|
const toggleVoiceMode = () => {
|
||||||
isVoiceMode.value = !isVoiceMode.value;
|
isVoiceMode.value = !isVoiceMode.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理语音按钮长按开始
|
// 处理语音按钮长按开始
|
||||||
const handleVoiceTouchStart = () => {
|
const handleVoiceTouchStart = () => {
|
||||||
manager.start({ lang: "zh_CN" });
|
manager.start({ lang: "zh_CN" });
|
||||||
|
|
||||||
visibleWaveBtn.value = true;
|
visibleWaveBtn.value = true;
|
||||||
|
|
||||||
// 启动音频条动画
|
// 启动音频条动画
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (recordingWaveBtnRef.value) {
|
if (recordingWaveBtnRef.value) {
|
||||||
recordingWaveBtnRef.value.startAnimation();
|
recordingWaveBtnRef.value.startAnimation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理语音按钮长按结束
|
// 处理语音按钮长按结束
|
||||||
const handleVoiceTouchEnd = () => {
|
const handleVoiceTouchEnd = () => {
|
||||||
manager.stop();
|
manager.stop();
|
||||||
|
|
||||||
// 停止音频条动画
|
// 停止音频条动画
|
||||||
if (recordingWaveBtnRef.value) {
|
if (recordingWaveBtnRef.value) {
|
||||||
recordingWaveBtnRef.value.stopAnimation();
|
recordingWaveBtnRef.value.stopAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
visibleWaveBtn.value = false;
|
visibleWaveBtn.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理发送原语音
|
// 处理发送原语音
|
||||||
const initRecord = () => {
|
const initRecord = () => {
|
||||||
manager.onRecognize = (res) => {
|
manager.onRecognize = (res) => {
|
||||||
let text = res.result;
|
let text = res.result;
|
||||||
inputMessage.value = text;
|
inputMessage.value = text;
|
||||||
};
|
};
|
||||||
// 识别结束事件
|
// 识别结束事件
|
||||||
manager.onStop = (res) => {
|
manager.onStop = (res) => {
|
||||||
console.log(res, 37);
|
console.log(res, 37);
|
||||||
let text = res.result;
|
let text = res.result;
|
||||||
|
|
||||||
if (text == "") {
|
if (text == "") {
|
||||||
console.log("没有说话");
|
console.log("没有说话");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
inputMessage.value = text;
|
inputMessage.value = text;
|
||||||
// 在语音识别完成后发送消息
|
// 在语音识别完成后发送消息
|
||||||
emit("send", text);
|
emit("send", text);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// 监听键盘高度变化
|
// 监听键盘高度变化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 监听键盘弹起
|
// 监听键盘弹起
|
||||||
uni.onKeyboardHeightChange((res) => {
|
uni.onKeyboardHeightChange((res) => {
|
||||||
keyboardHeight.value = res.height;
|
keyboardHeight.value = res.height;
|
||||||
if (res.height) {
|
if (res.height) {
|
||||||
emit("keyboardShow", res.height);
|
emit("keyboardShow", res.height);
|
||||||
} else {
|
} else {
|
||||||
emit("keyboardHide");
|
emit("keyboardHide");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
initRecord();
|
initRecord();
|
||||||
});
|
});
|
||||||
|
|
||||||
const sendMessage = () => {
|
const sendMessage = () => {
|
||||||
if (props.isSessionActive) {
|
if (props.isSessionActive) {
|
||||||
// 如果会话进行中,调用停止请求函数
|
// 如果会话进行中,调用停止请求函数
|
||||||
if (props.stopRequest) {
|
if (props.stopRequest) {
|
||||||
props.stopRequest();
|
props.stopRequest();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 否则发送新消息
|
|
||||||
if (!inputMessage.value.trim()) return;
|
|
||||||
emit("send", inputMessage.value);
|
|
||||||
|
|
||||||
// 发送后保持焦点(可选)
|
|
||||||
if (props.holdKeyboard && textareaRef.value) {
|
|
||||||
nextTick(() => {
|
|
||||||
textareaRef.value.focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 否则发送新消息
|
||||||
|
if (!inputMessage.value.trim()) return;
|
||||||
|
emit("send", inputMessage.value);
|
||||||
|
|
||||||
|
// 发送后保持焦点(可选)
|
||||||
|
if (props.holdKeyboard && textareaRef.value) {
|
||||||
|
nextTick(() => {
|
||||||
|
textareaRef.value.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
isFocused.value = true;
|
isFocused.value = true;
|
||||||
emit("noHideKeyboard");
|
emit("noHideKeyboard");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
isFocused.value = false;
|
isFocused.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTouchStart = () => {
|
const handleTouchStart = () => {
|
||||||
emit("noHideKeyboard");
|
emit("noHideKeyboard");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTouchEnd = () => {
|
const handleTouchEnd = () => {
|
||||||
emit("noHideKeyboard");
|
emit("noHideKeyboard");
|
||||||
};
|
};
|
||||||
|
|
||||||
// 手动聚焦输入框
|
// 手动聚焦输入框
|
||||||
const focusInput = () => {
|
const focusInput = () => {
|
||||||
if (textareaRef.value) {
|
if (textareaRef.value) {
|
||||||
textareaRef.value.focus();
|
textareaRef.value.focus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 手动失焦输入框
|
// 手动失焦输入框
|
||||||
const blurInput = () => {
|
const blurInput = () => {
|
||||||
if (textareaRef.value) {
|
if (textareaRef.value) {
|
||||||
textareaRef.value.blur();
|
textareaRef.value.blur();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 暴露方法给父组件
|
// 暴露方法给父组件
|
||||||
@ -234,87 +236,92 @@ defineExpose({ focusInput });
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.area-input {
|
.area-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
border-radius: 22px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: 0px 0px 20px 0px rgba(52, 25, 204, 0.05);
|
||||||
|
margin: 0 12px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.input-container-voice {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 22px;
|
justify-content: center;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-button-container {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hold-to-talk-button {
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
color: #333333;
|
||||||
|
font-size: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
box-shadow: 0px 0px 20px 0px rgba(52, 25, 204, 0.05);
|
transition: all 0.2s ease;
|
||||||
margin: 0 12px;
|
user-select: none;
|
||||||
margin-bottom: 8px;
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
.input-container-voice {
|
.input-container-send {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-self: flex-end;
|
width: 44px;
|
||||||
width: 44px;
|
height: 44px;
|
||||||
height: 44px;
|
|
||||||
|
|
||||||
image {
|
.input-container-send-btn {
|
||||||
width: 22px;
|
display: flex;
|
||||||
height: 22px;
|
align-items: center;
|
||||||
}
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-button-container {
|
image {
|
||||||
flex: 1;
|
width: 28px;
|
||||||
position: relative;
|
height: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea {
|
||||||
|
flex: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 92px;
|
||||||
|
min-height: 44px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: normal;
|
||||||
|
|
||||||
|
&.android {
|
||||||
|
padding: 12px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hold-to-talk-button {
|
&.ios {
|
||||||
width: 100%;
|
padding: 6px 0;
|
||||||
height: 44px;
|
|
||||||
color: #333333;
|
|
||||||
font-size: 16px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: #ffffff;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-container-send {
|
&::placeholder {
|
||||||
display: flex;
|
color: #cccccc;
|
||||||
align-items: center;
|
line-height: normal;
|
||||||
justify-content: center;
|
|
||||||
align-self: flex-end;
|
|
||||||
width: 44px;
|
|
||||||
height: 44px;
|
|
||||||
|
|
||||||
.input-container-send-btn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
image {
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.textarea {
|
&:focus {
|
||||||
flex: 1;
|
outline: none;
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
max-height: 92px;
|
|
||||||
min-height: 22px;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 22px;
|
|
||||||
margin: 6px 0;
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: #cccccc;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -50,6 +50,12 @@ const sendReply = (text) => {
|
|||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
/* 隐藏滚动条 */
|
||||||
|
scrollbar-width: none;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-tips-item {
|
.more-tips-item {
|
||||||
|
|||||||
@ -1,143 +1,140 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="quick-access">
|
<view class="quick-access">
|
||||||
<view class="quick-access-scroll">
|
<view class="quick-access-scroll">
|
||||||
<view
|
<view class="quick-access-item" v-for="(item, index) in itemList" :key="index" @click="sendReply(item)">
|
||||||
class="quick-access-item"
|
<image class="quick-access-item-bg" src="/static/quick/quick_icon_bg.png" mode="aspectFill"></image>
|
||||||
v-for="(item, index) in itemList"
|
<view class="quick-access-item-title">
|
||||||
:key="index"
|
<image :src="item.icon"></image>
|
||||||
@click="sendReply(item)"
|
<text>{{ item.title }}</text>
|
||||||
>
|
</view>
|
||||||
<image
|
<text class="quick-access-item-content">{{ item.content }}</text>
|
||||||
class="quick-access-item-bg"
|
</view>
|
||||||
src="/static/quick/quick_icon_bg.png"
|
</view>
|
||||||
mode="aspectFill"
|
</view>
|
||||||
></image>
|
|
||||||
<view class="quick-access-item-title">
|
|
||||||
<image :src="item.icon"></image>
|
|
||||||
<text>{{ item.title }}</text>
|
|
||||||
</view>
|
|
||||||
<text class="quick-access-item-content">{{
|
|
||||||
item.content
|
|
||||||
}}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from 'vue';
|
||||||
const itemList = ref([]);
|
const itemList = ref([])
|
||||||
|
|
||||||
const emits = defineEmits(["replySent"]);
|
const emits = defineEmits(['replySent']);
|
||||||
|
|
||||||
const sendReply = (item) => {
|
const sendReply = (item) => {
|
||||||
emits("replySent", item); // 向父组件传递数据
|
emits('replySent', item); // 向父组件传递数据
|
||||||
};
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initData();
|
initData()
|
||||||
});
|
})
|
||||||
|
|
||||||
const initData = () => {
|
const initData = () => {
|
||||||
itemList.value = [
|
itemList.value = [
|
||||||
{
|
{
|
||||||
icon: "/static/quick/quick_icon_yuding.png",
|
icon: '/static/quick/quick_icon_yuding.png',
|
||||||
title: "快速预定",
|
title: '快速预定',
|
||||||
content: "预定门票、房间、餐食",
|
content: '预定门票、房间、餐食',
|
||||||
type: "Command.quickBooking",
|
type: 'Command.quickBooking'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "/static/quick/quick_icon_find.png",
|
icon: '/static/quick/quick_icon_find.png',
|
||||||
title: "探索发现",
|
title: '探索发现',
|
||||||
content: "探索玩法、出片佳地",
|
content: '探索玩法、出片佳地',
|
||||||
type: "Command.discovery",
|
type: 'Command.discovery'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "/static/quick/quick_icon_order.png",
|
icon: '/static/quick/quick_icon_order.png',
|
||||||
title: "订单/工单",
|
title: '订单/工单',
|
||||||
content: "我的订单/工单",
|
content: '我的订单/工单',
|
||||||
type: "MyOrder",
|
type: 'MyOrder'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "/static/quick/quick_icon_call.png",
|
icon: '/static/quick/quick_icon_call.png',
|
||||||
title: "呼叫服务",
|
title: '呼叫服务',
|
||||||
content: "加水、客房服务等",
|
content: '加水、客房服务等',
|
||||||
type: "Command.createWorkOrder",
|
type: 'Command.createWorkOrder'
|
||||||
},
|
}
|
||||||
];
|
]
|
||||||
};
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.quick-access {
|
.quick-access {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
&-scroll {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
|
||||||
|
/* 隐藏滚动条 */
|
||||||
|
scrollbar-width: none;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-access-item {
|
||||||
|
flex: 0 0 104px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 4px 4px 8px 4px;
|
||||||
|
box-shadow: 0 2px 5px 0px rgba(0,0,0,0.1);
|
||||||
|
padding: 12px;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-access-item-bg {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 128px;
|
||||||
|
height: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-access-item-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-family: PingFang SC, PingFang SC;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #201F32;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-access-item-content {
|
||||||
|
z-index: 1;
|
||||||
|
margin-top: 4px;
|
||||||
|
font-family: PingFang SC, PingFang SC;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #678CAD;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-scroll {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
overflow-x: auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-access-item {
|
|
||||||
flex: 0 0 104px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin: 4px 4px 8px 4px;
|
|
||||||
box-shadow: 0 2px 5px 0px rgba(0, 0, 0, 0.1);
|
|
||||||
padding: 12px;
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-access-item-bg {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 0;
|
|
||||||
border-radius: 8px;
|
|
||||||
width: 128px;
|
|
||||||
height: 56px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-access-item-title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
image {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
text {
|
|
||||||
font-family: PingFang SC, PingFang SC;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #201f32;
|
|
||||||
line-height: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quick-access-item-content {
|
|
||||||
z-index: 1;
|
|
||||||
margin-top: 4px;
|
|
||||||
font-family: PingFang SC, PingFang SC;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 10px;
|
|
||||||
color: #678cad;
|
|
||||||
line-height: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,75 +1,70 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="top-bg-content">
|
<view class="top-bg-content">
|
||||||
<view class="top-item">
|
<view class="top-item" >
|
||||||
<!-- :style="backgroundStyle" -->
|
<!-- :style="backgroundStyle" -->
|
||||||
<image
|
<image class="top-item-left" :src="initPageImages.welcomeImageUrl"></image>
|
||||||
class="top-item-left"
|
<image class="top-item-right" :src="initPageImages.logoImageUrl"></image>
|
||||||
:src="initPageImages.welcomeImageUrl"
|
</view>
|
||||||
></image>
|
<ChatCardAI v-if="welcomeContent.length" :text='welcomeContent'/>
|
||||||
<image
|
</view>
|
||||||
class="top-item-right"
|
|
||||||
:src="initPageImages.logoImageUrl"
|
|
||||||
></image>
|
|
||||||
</view>
|
|
||||||
<ChatCardAI v-if="welcomeContent.length" :text="welcomeContent" />
|
|
||||||
</view>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, computed, ref } from "vue";
|
import { defineProps, computed, ref } from "vue";
|
||||||
import ChatCardAI from "./ChatCardAI.vue";
|
import ChatCardAI from './ChatCardAI.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
initPageImages: {
|
initPageImages: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {
|
default: {
|
||||||
backgroundImageUrl: "",
|
backgroundImageUrl: '',
|
||||||
logoImageUrl: "",
|
logoImageUrl: '',
|
||||||
welcomeImageUrl: "",
|
welcomeImageUrl: ''
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
welcomeContent: {
|
welcomeContent: {
|
||||||
type: String,
|
type: String,
|
||||||
default:
|
default: '查信息、预定下单、探索玩法、呼叫服务、我通通可以满足,快试试问我问题吧!'
|
||||||
"查信息、预定下单、探索玩法、呼叫服务、我通通可以满足,快试试问我问题吧!",
|
}
|
||||||
},
|
})
|
||||||
});
|
|
||||||
|
// 计算背景样式
|
||||||
|
const backgroundStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
backgroundImage: `url(${props.initPageImages.backgroundImageUrl})`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundRepeat: 'no-repeat'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 计算背景样式
|
|
||||||
const backgroundStyle = computed(() => {
|
|
||||||
return {
|
|
||||||
backgroundImage: `url(${props.initPageImages.backgroundImageUrl})`,
|
|
||||||
backgroundSize: "cover",
|
|
||||||
backgroundPosition: "center",
|
|
||||||
backgroundRepeat: "no-repeat",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.top-bg-content {
|
.top-bg-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-item {
|
.top-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 32px;
|
padding: 0 32px;
|
||||||
margin-bottom: -6px;
|
margin-bottom: -8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-item-left {
|
.top-item-left {
|
||||||
width: 118px;
|
width: 118px;
|
||||||
height: 52px;
|
height: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-item-right {
|
.top-item-right {
|
||||||
width: 130px;
|
width: 130px;
|
||||||
height: 130px;
|
height: 130px;
|
||||||
}
|
margin: -12px 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -49,6 +49,14 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
.area-msg-list-content {
|
||||||
|
/* 隐藏滚动条 */
|
||||||
|
scrollbar-width: none;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.message-item-ai {
|
.message-item-ai {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
@ -132,6 +140,15 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
width: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
background: transparent;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
// 打字机光标闪烁动画
|
// 打字机光标闪烁动画
|
||||||
.typing-cursor {
|
.typing-cursor {
|
||||||
|
|||||||
@ -1,214 +1,201 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<ModuleTitle :title="commodityDTO.title" />
|
<ModuleTitle :title="commodityDTO.title" />
|
||||||
<view class="container-scroll">
|
<view class="container-scroll">
|
||||||
<view
|
<view v-for="(item, index) in commodityDTO.commodityList" :key="`${item.commodityId}-${index}`">
|
||||||
v-for="(item, index) in commodityDTO.commodityList"
|
|
||||||
:key="`${item.commodityId}-${index}`"
|
|
||||||
>
|
|
||||||
<view class="mk-card-item" @click="placeOrderHandle(item)">
|
<view class="mk-card-item" @click="placeOrderHandle(item)">
|
||||||
<!-- <view class="card-badge">超值推荐</view> -->
|
<!-- <view class="card-badge">超值推荐</view> -->
|
||||||
<image
|
<image class="card-img" :src="item.commodityIcon" mode="aspectFill" />
|
||||||
class="card-img"
|
<view class="card-content">
|
||||||
:src="item.commodityIcon"
|
<view class="card-title-column">
|
||||||
mode="aspectFill"
|
<text class="card-title">{{ item.commodityName }}</text>
|
||||||
/>
|
<view class="card-tags" v-for="(tag) in item.commodityTradeRuleList" :key="tag">
|
||||||
<view class="card-content">
|
<text class="card-tag">{{ tag }}</text>
|
||||||
<view class="card-title-column">
|
</view>
|
||||||
<text class="card-title">{{
|
</view>
|
||||||
item.commodityName
|
<template v-for="(serviceItem, index) in item.commodityServices" :key="serviceItem.serviceTitle">
|
||||||
}}</text>
|
<view v-if="index < 3" class="card-desc">· {{ serviceItem.serviceTitle }}</view>
|
||||||
<view
|
</template>
|
||||||
class="card-tags"
|
<view class="card-bottom-row">
|
||||||
v-for="tag in item.commodityTradeRuleList"
|
<view class="card-price-row">
|
||||||
:key="tag"
|
<text class="card-price-fu">¥</text>
|
||||||
>
|
<text class="card-price">{{ item.commodityPrice }}</text>
|
||||||
<text class="card-tag">{{ tag }}</text>
|
<text class="card-unit">/人</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
<template
|
|
||||||
v-for="(
|
|
||||||
serviceItem, index
|
|
||||||
) in item.commodityServices"
|
|
||||||
:key="serviceItem.serviceTitle"
|
|
||||||
>
|
|
||||||
<view v-if="index < 3" class="card-desc"
|
|
||||||
>· {{ serviceItem.serviceTitle }}</view
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<view class="card-bottom-row">
|
|
||||||
<view class="card-price-row">
|
|
||||||
<text class="card-price-fu">¥</text>
|
|
||||||
<text class="card-price">{{
|
|
||||||
item.commodityPrice
|
|
||||||
}}</text>
|
|
||||||
<text class="card-unit">/人</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<text class="card-btn">下单</text>
|
<text class="card-btn">下单</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
import ModuleTitle from '@/components/ModuleTitle/index.vue'
|
||||||
import { defineProps } from "vue";
|
import { defineProps } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
commodityDTO: {
|
commodityDTO: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {},
|
default: {}
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
|
/// 去下单
|
||||||
|
const placeOrderHandle = (item) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/goods/index?commodityId=${item.commodityId}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// 去下单
|
|
||||||
const placeOrderHandle = (item) => {
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages/goods/index?commodityId=${item.commodityId}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.container {
|
.container {
|
||||||
.container-scroll {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
margin: 4px 0;
|
|
||||||
|
|
||||||
.mk-card-item {
|
.container-scroll {
|
||||||
position: relative;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
margin: 4px 0;
|
||||||
|
|
||||||
display: flex;
|
/* 隐藏滚动条 */
|
||||||
flex-direction: column;
|
scrollbar-width: none;
|
||||||
align-items: start;
|
&::-webkit-scrollbar {
|
||||||
width: 188px;
|
display: none;
|
||||||
// height: 244px;
|
}
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-right: 8px;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
|
|
||||||
.card-badge {
|
.mk-card-item {
|
||||||
position: absolute;
|
position: relative;
|
||||||
top: 8px;
|
|
||||||
left: 8px;
|
|
||||||
background: #ffe7b2;
|
|
||||||
color: #b97a00;
|
|
||||||
font-size: 12px;
|
|
||||||
padding: 2px 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-img {
|
display: flex;
|
||||||
width: 188px;
|
flex-direction: column;
|
||||||
height: 114px;
|
align-items: start;
|
||||||
border-radius: 10px;
|
width: 188px;
|
||||||
object-fit: cover; /* 确保图片不变形,保持比例裁剪 */
|
// height: 244px;
|
||||||
flex-shrink: 0; /* 防止图片被压缩 */
|
background-color: #ffffff;
|
||||||
}
|
border-radius: 10px;
|
||||||
|
margin-right: 8px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
|
||||||
.card-content {
|
.card-badge {
|
||||||
box-sizing: border-box;
|
position: absolute;
|
||||||
padding: 10px 12px 0 12px;
|
top: 8px;
|
||||||
display: flex;
|
left: 8px;
|
||||||
flex-direction: column;
|
background: #ffe7b2;
|
||||||
justify-content: space-between;
|
color: #b97a00;
|
||||||
align-items: start;
|
font-size: 12px;
|
||||||
width: 100%;
|
padding: 2px 8px;
|
||||||
flex: 1; /* 让内容区域占据剩余空间 */
|
border-radius: 4px;
|
||||||
overflow: hidden; /* 防止内容溢出 */
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-title-column {
|
.card-img {
|
||||||
display: flex;
|
width: 188px;
|
||||||
align-items: start;
|
height: 114px;
|
||||||
flex-direction: column;
|
border-radius: 10px;
|
||||||
width: 100%;
|
object-fit: cover; /* 确保图片不变形,保持比例裁剪 */
|
||||||
}
|
flex-shrink: 0; /* 防止图片被压缩 */
|
||||||
|
}
|
||||||
|
|
||||||
.card-title {
|
.card-content {
|
||||||
font-size: 16px;
|
box-sizing: border-box;
|
||||||
font-weight: bold;
|
padding: 10px 12px 0 12px;
|
||||||
color: #222;
|
display: flex;
|
||||||
width: 100%;
|
flex-direction: column;
|
||||||
/* 限制标题最多显示两行 */
|
justify-content: space-between;
|
||||||
display: -webkit-box;
|
align-items: start;
|
||||||
-webkit-box-orient: vertical;
|
width: 100%;
|
||||||
-webkit-line-clamp: 2;
|
flex: 1; /* 让内容区域占据剩余空间 */
|
||||||
overflow: hidden;
|
overflow: hidden; /* 防止内容溢出 */
|
||||||
text-overflow: ellipsis;
|
}
|
||||||
line-height: 1.4;
|
|
||||||
max-height: 2.8em; /* 2行的高度 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-tags {
|
.card-title-column {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
align-items: start;
|
||||||
align-items: start;
|
flex-direction: column;
|
||||||
padding: 6px 0;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-tag {
|
.card-title {
|
||||||
background: #f5f5f5;
|
font-size: 16px;
|
||||||
color: #ff6600;
|
font-weight: bold;
|
||||||
font-size: 10px;
|
color: #222;
|
||||||
border-radius: 4px;
|
width: 100%;
|
||||||
padding: 0 6px;
|
/* 限制标题最多显示两行 */
|
||||||
margin-left: 2px;
|
display: -webkit-box;
|
||||||
border: 1px solid #ff6600;
|
-webkit-box-orient: vertical;
|
||||||
}
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 1.4;
|
||||||
|
max-height: 2.8em; /* 2行的高度 */
|
||||||
|
}
|
||||||
|
|
||||||
.card-desc {
|
.card-tags {
|
||||||
font-size: 13px;
|
display: flex;
|
||||||
color: #888;
|
flex-direction: row;
|
||||||
margin-top: 2px;
|
align-items: start;
|
||||||
}
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.card-bottom-row {
|
.card-tag {
|
||||||
display: flex;
|
background: #f5f5f5;
|
||||||
align-items: center;
|
color: #ff6600;
|
||||||
justify-content: space-between;
|
font-size: 10px;
|
||||||
margin-top: 8px;
|
border-radius: 4px;
|
||||||
width: 100%;
|
padding: 0 6px;
|
||||||
}
|
margin-left: 2px;
|
||||||
|
border: 1px solid #ff6600;
|
||||||
|
}
|
||||||
|
|
||||||
.card-price-row {
|
.card-desc {
|
||||||
.card-price-fu {
|
font-size: 13px;
|
||||||
color: #ff6600;
|
color: #888;
|
||||||
font-size: 11px;
|
margin-top: 2px;
|
||||||
font-weight: normal;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.card-price {
|
.card-bottom-row {
|
||||||
color: #ff6600;
|
display: flex;
|
||||||
font-size: 16px;
|
align-items: center;
|
||||||
font-weight: bold;
|
justify-content: space-between;
|
||||||
}
|
margin-top: 8px;
|
||||||
.card-unit {
|
width: 100%;
|
||||||
font-size: 11px;
|
}
|
||||||
color: #888;
|
|
||||||
font-weight: normal;
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-btn {
|
.card-price-row {
|
||||||
background: #ff6600;
|
.card-price-fu {
|
||||||
color: #fff;
|
color: #ff6600;
|
||||||
font-size: 15px;
|
font-size: 11px;
|
||||||
border-radius: 20px;
|
font-weight: normal;
|
||||||
padding: 0 18px;
|
}
|
||||||
height: 32px;
|
|
||||||
line-height: 32px;
|
.card-price {
|
||||||
}
|
color: #ff6600;
|
||||||
}
|
font-size: 16px;
|
||||||
}
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
.card-unit {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #888;
|
||||||
|
font-weight: normal;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-btn {
|
||||||
|
background: #ff6600;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 0 18px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,214 +1,200 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<ModuleTitle title="相关商品" />
|
<ModuleTitle title="相关商品" />
|
||||||
<view class="container-scroll">
|
<view class="container-scroll">
|
||||||
<view
|
<view v-for="(item, index) in commodityList" :key="`${item.commodityId}-${index}`">
|
||||||
v-for="(item, index) in commodityList"
|
<view class="mk-card-item" @click="placeOrderHandle(item)">
|
||||||
:key="`${item.commodityId}-${index}`"
|
<image class="card-img" :src="item.commodityPhoto" mode="aspectFill" />
|
||||||
>
|
<view class="card-content">
|
||||||
<view class="mk-card-item" @click="placeOrderHandle(item)">
|
<view class="card-title-column">
|
||||||
<image
|
<text class="card-title">{{ item.commodityName }}</text>
|
||||||
class="card-img"
|
<view class="card-tags" v-for="(tag) in item.commodityTradeRuleList" :key="tag">
|
||||||
:src="item.commodityPhoto"
|
<text class="card-tag">{{ tag }}</text>
|
||||||
mode="aspectFill"
|
</view>
|
||||||
/>
|
</view>
|
||||||
<view class="card-content">
|
<template v-for="(serviceItem, index) in item.commodityServices" :key="serviceItem.serviceTitle">
|
||||||
<view class="card-title-column">
|
<view v-if="index < 3" class="card-desc">· {{ serviceItem.serviceTitle }}</view>
|
||||||
<text class="card-title">{{
|
</template>
|
||||||
item.commodityName
|
<view class="card-bottom-row">
|
||||||
}}</text>
|
<view class="card-price-row">
|
||||||
<view
|
<text class="card-price-fu">¥</text>
|
||||||
class="card-tags"
|
<text class="card-price">{{ item.specificationPrice }}</text>
|
||||||
v-for="tag in item.commodityTradeRuleList"
|
<text class="card-unit">/人</text>
|
||||||
:key="tag"
|
</view>
|
||||||
>
|
<text class="card-btn">下单</text>
|
||||||
<text class="card-tag">{{ tag }}</text>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
<template
|
|
||||||
v-for="(
|
|
||||||
serviceItem, index
|
|
||||||
) in item.commodityServices"
|
|
||||||
:key="serviceItem.serviceTitle"
|
|
||||||
>
|
|
||||||
<view v-if="index < 3" class="card-desc"
|
|
||||||
>· {{ serviceItem.serviceTitle }}</view
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<view class="card-bottom-row">
|
|
||||||
<view class="card-price-row">
|
|
||||||
<text class="card-price-fu">¥</text>
|
|
||||||
<text class="card-price">{{
|
|
||||||
item.specificationPrice
|
|
||||||
}}</text>
|
|
||||||
<text class="card-unit">/人</text>
|
|
||||||
</view>
|
|
||||||
<text class="card-btn">下单</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
import ModuleTitle from '@/components/ModuleTitle/index.vue'
|
||||||
import { defineProps } from "vue";
|
import { defineProps } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
commodityList: {
|
commodityList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: [],
|
default: []
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
|
/// 去下单
|
||||||
|
const placeOrderHandle = (item) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/goods/index?commodityId=${item.commodityId}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// 去下单
|
|
||||||
const placeOrderHandle = (item) => {
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages/goods/index?commodityId=${item.commodityId}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.container {
|
.container {
|
||||||
margin: 6px 0 0;
|
margin: 6px 0 0;
|
||||||
|
|
||||||
.container-scroll {
|
.container-scroll {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
|
|
||||||
.mk-card-item {
|
/* 隐藏滚动条 */
|
||||||
position: relative;
|
scrollbar-width: none;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
.mk-card-item {
|
||||||
flex-direction: column;
|
position: relative;
|
||||||
align-items: start;
|
|
||||||
width: 188px;
|
|
||||||
// height: 244px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-right: 8px;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
|
|
||||||
.card-badge {
|
display: flex;
|
||||||
position: absolute;
|
flex-direction: column;
|
||||||
top: 8px;
|
align-items: start;
|
||||||
left: 8px;
|
width: 188px;
|
||||||
background: #ffe7b2;
|
// height: 244px;
|
||||||
color: #b97a00;
|
background-color: #ffffff;
|
||||||
font-size: 12px;
|
border-radius: 10px;
|
||||||
padding: 2px 8px;
|
margin-right: 8px;
|
||||||
border-radius: 4px;
|
padding-bottom: 12px;
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-img {
|
.card-badge {
|
||||||
width: 188px;
|
position: absolute;
|
||||||
height: 114px;
|
top: 8px;
|
||||||
border-radius: 10px;
|
left: 8px;
|
||||||
object-fit: cover; /* 确保图片不变形,保持比例裁剪 */
|
background: #ffe7b2;
|
||||||
flex-shrink: 0; /* 防止图片被压缩 */
|
color: #b97a00;
|
||||||
}
|
font-size: 12px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.card-content {
|
.card-img {
|
||||||
box-sizing: border-box;
|
width: 188px;
|
||||||
padding: 10px 12px 0 12px;
|
height: 114px;
|
||||||
display: flex;
|
border-radius: 10px;
|
||||||
flex-direction: column;
|
object-fit: cover; /* 确保图片不变形,保持比例裁剪 */
|
||||||
justify-content: space-between;
|
flex-shrink: 0; /* 防止图片被压缩 */
|
||||||
align-items: start;
|
}
|
||||||
width: 100%;
|
|
||||||
flex: 1; /* 让内容区域占据剩余空间 */
|
|
||||||
overflow: hidden; /* 防止内容溢出 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-title-column {
|
.card-content {
|
||||||
display: flex;
|
box-sizing: border-box;
|
||||||
align-items: start;
|
padding: 10px 12px 0 12px;
|
||||||
flex-direction: column;
|
display: flex;
|
||||||
width: 100%;
|
flex-direction: column;
|
||||||
}
|
justify-content: space-between;
|
||||||
|
align-items: start;
|
||||||
|
width: 100%;
|
||||||
|
flex: 1; /* 让内容区域占据剩余空间 */
|
||||||
|
overflow: hidden; /* 防止内容溢出 */
|
||||||
|
}
|
||||||
|
|
||||||
.card-title {
|
.card-title-column {
|
||||||
font-size: 16px;
|
display: flex;
|
||||||
font-weight: bold;
|
align-items: start;
|
||||||
color: #222;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
/* 限制标题最多显示两行 */
|
}
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
line-height: 1.4;
|
|
||||||
max-height: 2.8em; /* 2行的高度 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-tags {
|
.card-title {
|
||||||
display: flex;
|
font-size: 16px;
|
||||||
flex-direction: row;
|
font-weight: bold;
|
||||||
align-items: start;
|
color: #222;
|
||||||
padding: 6px 0;
|
width: 100%;
|
||||||
}
|
/* 限制标题最多显示两行 */
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 1.4;
|
||||||
|
max-height: 2.8em; /* 2行的高度 */
|
||||||
|
}
|
||||||
|
|
||||||
.card-tag {
|
.card-tags {
|
||||||
background: #f5f5f5;
|
display: flex;
|
||||||
color: #ff6600;
|
flex-direction: row;
|
||||||
font-size: 10px;
|
align-items: start;
|
||||||
border-radius: 4px;
|
padding: 6px 0;
|
||||||
padding: 0 6px;
|
}
|
||||||
margin-left: 2px;
|
|
||||||
|
.card-tag {
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #ff6600;
|
||||||
|
font-size: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0 6px;
|
||||||
|
margin-left: 2px;
|
||||||
border: 1px solid #ff6600;
|
border: 1px solid #ff6600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-desc {
|
.card-desc {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #888;
|
color: #888;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-bottom-row {
|
.card-bottom-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-price-row {
|
.card-price-row {
|
||||||
.card-price-fu {
|
.card-price-fu {
|
||||||
color: #ff6600;
|
color: #ff6600;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-price {
|
.card-price {
|
||||||
color: #ff6600;
|
color: #ff6600;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.card-unit {
|
.card-unit {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: #888;
|
color: #888;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-btn {
|
.card-btn {
|
||||||
background: #ff6600;
|
background: #ff6600;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
padding: 0 18px;
|
padding: 0 18px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,67 +1,72 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<ModuleTitle :title="recommendTheme.themeName" />
|
<ModuleTitle :title="recommendTheme.themeName" />
|
||||||
<view class="container-scroll">
|
<view class="container-scroll">
|
||||||
<view
|
<view v-for="(item, index) in recommendTheme.recommendPostsList" :key="index">
|
||||||
v-for="(item, index) in recommendTheme.recommendPostsList"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<view class="mk-card-item" @click="sendReply(item)">
|
<view class="mk-card-item" @click="sendReply(item)">
|
||||||
<image :src="item.coverPhoto" mode="widthFix"></image>
|
<image :src="item.coverPhoto" mode="widthFix"></image>
|
||||||
<text>{{ item.topic }}</text>
|
<text>{{ item.topic }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
import ModuleTitle from '@/components/ModuleTitle/index.vue'
|
||||||
import { RECOMMEND_POSTS_TITLE } from "@/constant/constant";
|
import { RECOMMEND_POSTS_TITLE } from '@/constant/constant'
|
||||||
import { defineProps } from "vue";
|
import { defineProps } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
recommendTheme: {
|
recommendTheme: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {},
|
default: {}
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
|
const sendReply = (item) => {
|
||||||
|
const topic = item.userInputContent || item.topic.replace(/^#/, '');
|
||||||
|
uni.$emit(RECOMMEND_POSTS_TITLE, topic);
|
||||||
|
}
|
||||||
|
|
||||||
const sendReply = (item) => {
|
|
||||||
const topic = item.userInputContent || item.topic.replace(/^#/, "");
|
|
||||||
uni.$emit(RECOMMEND_POSTS_TITLE, topic);
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.container {
|
.container {
|
||||||
.container-scroll {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin-top: 4px;
|
|
||||||
|
|
||||||
.mk-card-item {
|
.container-scroll {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: start;
|
overflow-x: auto;
|
||||||
width: 188px;
|
margin-top: 4px;
|
||||||
height: 154px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-right: 8px;
|
|
||||||
|
|
||||||
image {
|
/* 隐藏滚动条 */
|
||||||
width: 188px;
|
scrollbar-width: none;
|
||||||
height: 112px;
|
&::-webkit-scrollbar {
|
||||||
}
|
display: none;
|
||||||
text {
|
}
|
||||||
padding: 12px;
|
|
||||||
text-align: center;
|
.mk-card-item {
|
||||||
font-weight: 500;
|
display: flex;
|
||||||
font-size: 12px;
|
flex-direction: column;
|
||||||
color: #333333;
|
align-items: start;
|
||||||
}
|
width: 188px;
|
||||||
}
|
height: 154px;
|
||||||
}
|
background-color: #ffffff;
|
||||||
}
|
border-radius: 10px;
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 188px;
|
||||||
|
height: 112px;
|
||||||
|
}
|
||||||
|
text {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -44,6 +44,12 @@
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
|
|
||||||
|
/* 隐藏滚动条 */
|
||||||
|
scrollbar-width: none;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mk-card-item {
|
.mk-card-item {
|
||||||
flex-shrink: 0; /* 关键:防止 flex 布局压缩子元素宽度 */
|
flex-shrink: 0; /* 关键:防止 flex 布局压缩子元素宽度 */
|
||||||
width: 142px;
|
width: 142px;
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="100" height="100" style="shape-rendering: auto; display: block; background: transparent;" xmlns:xlink="http://www.w3.org/1999/xlink"><g><g transform="rotate(0 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.9166666666666666s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(30 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.8333333333333334s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(60 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.75s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(90 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.6666666666666666s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(120 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.5833333333333334s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(150 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.5s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(180 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.4166666666666667s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(210 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.3333333333333333s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(240 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.25s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(270 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.16666666666666666s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(300 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="-0.08333333333333333s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g transform="rotate(330 50 50)">
|
|
||||||
<rect fill="#00a6ff" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
||||||
<animate repeatCount="indefinite" begin="0s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
||||||
</rect>
|
|
||||||
</g><g></g></g><!-- [ldio] generated by https://loading.io --></svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.3 KiB |
Loading…
Reference in New Issue
Block a user