2 Commits
Author SHA1 Message Date
linxi d3957be379 Feat: 地标好物(服务) 2024-11-15 10:39:59 +08:00
linxi c18ec66653 Feat: 地标好物(页面&接口) 2024-11-14 17:58:52 +08:00
327 changed files with 24824 additions and 72497 deletions
-1
View File
@@ -26,5 +26,4 @@ export default {
@import "./assets/css/reset.less"; @import "./assets/css/reset.less";
@import "./assets/css/style.less"; @import "./assets/css/style.less";
@import "./assets/css/v12-style.less"; @import "./assets/css/v12-style.less";
@import "./assets/css/aiChat.less";
</style> </style>
-3
View File
@@ -9,9 +9,6 @@
#### 安装教程 #### 安装教程
1. xxxx 1. xxxx
2. xxxx 2. xxxx
3. xxxx 3. xxxx
-341
View File
@@ -1,341 +0,0 @@
<template>
<view
:class="{
'focus': inputOnFocus
}"
class="fix-page-bottom"
>
<view v-if="inputModel === 'input'" class="bottom-body flex-center-between">
<view class="history-wrap" @click="historyViewHandle">
历史
</view>
<view class="input-container">
<!-- 输入模式切换 -->
<view
class="input-model"
@click="toggleInputModel"
>
<image
:src="webUrl + '/aiChat/microphone.png'"
class="icon"
mode="widthFix"
/>
</view>
<!-- 输入框 -->
<view class="input-wrap flex-center-between">
<textarea
v-model.trim="prompt"
:show-confirm-bar="false"
:adjust-position="true"
:auto-height="true"
:disabled="loading"
:maxlength="500"
class="inp"
@confirm="sendHandle"
@focus="promptInputFocusHandle"
@blur="promptInputBlurHandle"
/>
<view v-if="!prompt && !inputOnFocus" class="placeholder-txt">发消息...</view>
</view>
<view
class="send-btn"
@click="sendHandle"
>
<image
:src="webUrl + '/aiChat/send.png'"
class="icon"
mode="widthFix"
/>
</view>
</view>
</view>
<!-- 语音输入 -->
<view
v-if="inputModel === 'sound'"
class="sound-input-wrap"
>
<view class="toggle-btn">
<image
:src="webUrl + '/aiChat/icon-06.png'"
class="input-icon"
mode="widthFix"
@click="toggleInputModel"
/>
</view>
<view
class="sound-wrap"
@touchstart="startRecord"
@touchend="stopRecord"
>
<view v-if="startTaskFlag" class="music-wrap">
<view class="item one" />
<view class="item two" />
<view class="item three" />
<view class="item four" />
<view class="item five" />
<view class="item six" />
<view class="item seven" />
</view>
<image
:src="webUrl + '/aiChat/microphone-big.png'"
class="icon"
mode="widthFix"
/>
<view v-if="startTaskFlag" class="music-wrap music-wrap2">
<view class="item one" />
<view class="item two" />
<view class="item three" />
<view class="item four" />
<view class="item five" />
<view class="item six" />
<view class="item seven" />
</view>
</view>
</view>
</view>
</template>
<script>
import {
makeFileTransTask,
getFileTransResult
} from '@/api/voiceToText/index'
import { VUE_APP_API_URL } from '@/config'
import cookie from '@/utils/store/cookie'
export default {
name: 'BottomSend',
props: {
loading: {
type: Boolean,
default: false
},
keyboardHeight: {
type: Number,
default: 0
},
voiceException: {
type: String,
default: '没有听清您说了什么,请再说一遍'
}
},
data() {
return {
token: cookie.get('login_status'),
userInfo: cookie.get('userInfo'),
webUrl: this.$VUE_APP_RESOURCES_URL,
// 输入模式:input-键盘,sound-语音
inputModel: 'input',
/**
* 端午节送礼攻略
* 丽江逛吃攻略
* 云南非遗有哪些?
* 怎么申请地理标志保护产品?
* 想找个像《去有风的地方》那样的治愈县城
* 云南有哪些小众县城适合旅居?
* 查询最近一个月的订单
*/
prompt: '',
recordManager: null,
// 录音权限是否开通
recordPermission: false,
taskId: '',
taskTimer: null,
startTaskFlag: false,
// 输入框是否聚焦
inputOnFocus: false
}
},
beforeDestroy() {
this.clearIntervalFn()
},
created() {
uni.getSetting({
success: res => {
if (res.authSetting['scope.record']) {
this.recordPermission = true
}
}
})
},
methods: {
promptInputFocusHandle() {
this.$emit('focus', 1)
setTimeout(() => {
this.inputOnFocus = true
}, 100)
},
promptInputBlurHandle() {
this.$emit('focus', 0)
this.inputOnFocus = false
},
toggleInputModel() {
if (!this.token) {
uni.reLaunch({ url: '/pages/auth/login' })
return
}
if (this.loading) return
if (this.inputModel === 'input') {
uni.getSetting({
success: res => {
if (!res.authSetting['scope.record']) {
uni.authorize({
scope: 'scope.record',
success: () => {
console.log('获取录音权限成功')
this.recordPermission = true
this.inputModel = 'sound'
},
fail: () => {
console.log('获取录音权限失败')
this.recordPermission = false
uni.showModal({
title: '提示',
content: '需要获取麦克风权限',
confirmText: '前往设置',
confirmColor: '#3D4CF1',
success(res2) {
if (res2.confirm) {
wx.openSetting()
}
}
})
}
})
} else {
this.recordPermission = true
this.inputModel = 'sound'
}
}
})
return
}
if (this.inputModel === 'sound') {
this.clearIntervalFn()
this.inputModel = 'input'
return
}
},
startRecord() {
if (this.loading) {
this.$toast('正在检索')
return
}
// 正在识别,不触发相关动作
if (this.startTaskFlag || this.taskTimer) {
return
}
this.recordManager = uni.getRecorderManager()
console.log('启动录音')
this.startTaskFlag = true
this.recordManager.start({
duration: 60 * 1000,
frameSize: 1,
sampleRate: 16000,
format: 'wav'
})
},
stopRecord() {
const _this = this
// 正在识别,不触发相关动作
if (this.taskTimer) {
return
}
if (_this.recordManager) {
_this.recordManager.stop()
console.log('停止录音')
_this.startTaskFlag = false
_this.recordManager.onStop((res) => {
console.log('录音结束------------')
console.log(res)
const { tempFilePath, fileSize, duration } = res
if (tempFilePath && fileSize && duration) {
_this.taskId = ''
_this.clearIntervalFn()
uni.showLoading({ title: '识别中...' })
uni.uploadFile({
url: `${VUE_APP_API_URL}/api/upload`,
filePath: tempFilePath,
header: {
Authorization: 'Bearer ' + (_this.token || '')
},
name: 'file',
success: uploadRes => {
console.log(JSON.parse(uploadRes.data))
_this.renderTransTask(uploadRes)
},
fail: err => {
console.log(err)
uni.hideLoading()
_this.$toast(_this.voiceException)
}
})
} else {
_this.$toast(_this.voiceException)
}
})
}
},
renderTransTask(uploadRes) {
const _this = this
const file = JSON.parse(uploadRes.data).link || ''
if (!file) return
makeFileTransTask({
file
}).then(taskRes => {
_this.taskId = taskRes.data
_this.getTransResultReq()
}).catch(() => {
uni.hideLoading()
_this.$toast(_this.voiceException)
})
},
getTransResultReq() {
const _this = this
_this.taskTimer = setInterval(() => {
getFileTransResult({
taskId: _this.taskId
}).then(res => {
const { success, data = [] } = res
if (success && data) {
uni.hideLoading()
_this.clearIntervalFn()
if (data === '__NULL__') {
_this.$toast(_this.voiceException)
} else {
if (data.length > 0) {
const prompt = data[0].Text
if (prompt) {
_this.$emit('send', { prompt: prompt.replace('。', '') })
}
}
}
}
}).catch(() => {
uni.hideLoading()
_this.$toast(_this.voiceException)
})
}, 1000)
},
clearIntervalFn() {
this.taskTimer && clearInterval(this.taskTimer)
this.taskTimer = null
setTimeout(() => {
this.startTaskFlag = false
}, 300)
},
sendHandle() {
if (this.loading) return
if (!this.prompt) {
this.$toast('请输入您想问的内容')
return
}
this.$emit('send', { prompt: this.prompt })
this.prompt = ''
this.inputOnFocus = false
},
historyViewHandle() {
this.$emit('history')
}
}
}
</script>
-293
View File
@@ -1,293 +0,0 @@
<template>
<view
:class="{
'show': showLayer
}"
class="history-wrap"
>
<view class="layer" @click="closeLayer" />
<view
:style="{
'padding-top': statusBarHeight + 'px'
}"
class="history-container"
>
<view class="history-type">
<view class="title">
<view class="txt">今日</view>
<image
v-if="todayList.length > 0"
:src="webUrl + '/aiChat/delete.png'"
class="icon"
mode="widthFix"
@click="deleteRecords(1)"
/>
</view>
<view v-if="todayList.length > 0" class="list-cont">
<view
v-for="(item, index) in todayList"
:key="index"
class="item"
@click="historyItemClick(item)"
>
<view class="item-txt one-t">
{{ item.title }}
</view>
</view>
</view>
<view v-else class="no-data">
<image
:src="webUrl + '/aiChat/ai-chat-no-data.png'"
class="img"
mode="widthFix"
/>
</view>
</view>
<view class="history-type">
<view class="title">
<view class="txt">30天内</view>
<image
v-if="list.length > 0"
:src="webUrl + '/aiChat/delete.png'"
class="icon"
mode="widthFix"
@click="deleteRecords(2)"
/>
</view>
<view v-if="list.length > 0" class="list-cont">
<view
v-for="(item, index) in list"
:key="index"
class="item"
@click="historyItemClick(item)"
>
<view class="item-txt one-t">
{{ item.title }}
</view>
</view>
</view>
<view v-else class="no-data">
<image
:src="webUrl + '/aiChat/ai-chat-no-data.png'"
class="img"
mode="widthFix"
/>
</view>
</view>
<view class="history-type">
<view class="title">
<view class="txt">超过30天</view>
<image
v-if="moreList.length > 0"
:src="webUrl + '/aiChat/delete.png'"
class="icon"
mode="widthFix"
@click="deleteRecords(3)"
/>
</view>
<view v-if="moreList.length > 0" class="list-cont">
<view
v-for="(item, index) in moreList"
:key="index"
class="item"
@click="historyItemClick(item)"
>
<view class="item-txt one-t">
{{ item.title }}
</view>
</view>
</view>
<view v-else class="no-data">
<image
:src="webUrl + '/aiChat/ai-chat-no-data.png'"
class="img"
mode="widthFix"
/>
</view>
</view>
</view>
</view>
</template>
<script>
import {
getChatList,
deleteChatListByType,
getCountyAiChatList,
deleteCountyChatListByType
} from '@/api/chat/index'
export default {
name: 'AiHistoryList',
props: {
statusBarHeight: {
type: Number,
default: 0
},
// 来源模块:''-首页,'history'-历史记录
formModule: {
type: String,
default: ''
},
countyId: {
type: String,
default: ''
}
},
data() {
return {
webUrl: this.$VUE_APP_RESOURCES_URL,
showLayer: false,
todayList: [],
list: [],
moreList: []
}
},
methods: {
showView() {
this.showLayer = true
this.getChatListReq()
},
getChatListReq() {
let reqFn = null
let params = {}
if (this.countyId) {
reqFn = getCountyAiChatList
params = {
countyId: this.countyId
}
} else {
reqFn = getChatList
}
reqFn(params).then(res => {
const { success, data } = res
if (success) {
this.todayList = data['今天'] || []
this.list = data['30天内'] || []
this.moreList = data['超过30天'] || []
}
})
},
deleteRecords(type) {
let reqFn = null
let params = ''
if (this.countyId) {
reqFn = deleteCountyChatListByType
params = `?countyId=${this.countyId}&type=${type}`
} else {
reqFn = deleteChatListByType
}
reqFn(type, params).then(res => {
const { success } = res
if (success) {
this.getChatListReq()
}
})
},
historyItemClick(item) {
const paramsStr = `?chatNumber=${item.chatNumber}&title=${item.title}&click=1&countyId=${this.countyId}`
if (!this.formModule) {
uni.navigateTo({
url: '/aiChat/views/history' + paramsStr
})
} else {
uni.redirectTo({
url: '/aiChat/views/history' + paramsStr
})
}
this.$emit('enterHistory')
this.closeLayer()
},
closeLayer() {
this.showLayer = false
}
}
}
</script>
<style scoped lang="less">
.history-wrap {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1001;
transform: translateX(-100%);
opacity: 0;
transition: all 0.3s;
.layer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
background-color: rgba(0, 0, 0, 0.5);
}
.history-container {
position: absolute;
left: 0;
top: 0;
bottom: 0;
z-index: 5;
width: 75%;
padding: 40rpx;
box-sizing: border-box;
border-top-right-radius: 60rpx;
border-bottom-right-radius: 60rpx;
overflow-y: auto;
background-color: #fff;
.history-type + .history-type {
padding: 40rpx 0 0 0;
}
.history-type {
.title {
display: flex;
align-items: center;
justify-content: space-between;
.txt {
font-size: 34rpx;
line-height: 50rpx;
}
.icon {
display: block;
width: 40rpx;
height: 40rpx;
}
}
.list-cont {
padding: 24rpx 0 0 0;
.item + .item {
margin: 12rpx 0 0 0;
}
.item {
.item-txt {
display: inline-block;
max-width: 100%;
height: 60rpx;
padding: 0 24rpx;
box-sizing: border-box;
border-radius: 30rpx;
color: #333;
font-size: 28rpx;
line-height: 60rpx;
background-color: #F1F2FF;
}
}
}
.no-data {
.img {
display: block;
width: 300rpx;
height: 300rpx;
margin: 40rpx auto 0 auto;
}
}
}
}
&.show {
opacity: 1;
transform: translateX(0);
}
}
</style>
-263
View File
@@ -1,263 +0,0 @@
<template>
<view
class="order-item"
>
<view class="order-header">
<view class="order-shop">
<view class="shop-name">
<image
:src="webUrl + '/aiChat/icon-57.png'"
class="icon"
mode="widthFix"
lazy-load
/>
{{ item.merName }}
</view>
<view class="order-id">
订单号{{ item.orderId }}
</view>
</view>
<view class="status">
{{ item.statusName }}
</view>
</view>
<view v-if="item.isGiftCardReceiveBlind === 0" class="product-info-wrap">
<view
v-for="cartItem in item.cartInfo"
:key="cartItem.productId"
class="product-info"
>
<view class="good-img">
<image
:src="cartItem.productInfo.image"
class="img"
mode="widthFix"
lazy-load
/>
</view>
<view class="name-wrap">
<view class="name one-t">
{{ cartItem.productInfo.storeName }}
</view>
<view class="attr">
规格{{ cartItem.productInfo.attrInfo.sku || '' }}
</view>
</view>
<view class="price-num">
<view>
{{ cartItem.truePrice }}
</view>
<view class="num">
x{{ cartItem.cartNum }}
</view>
</view>
</view>
</view>
<view v-else class="product-info-wrap">
<view
class="product-info product-info2"
>
<view class="good-img">
<image
:src="webUrl + '/orderIcon/盲盒礼包.png'"
class="img"
mode="widthFix"
lazy-load
/>
</view>
<view class="name-wrap">
<view class="name one-t">
盲盒礼物
</view>
<view class="attr">
待收货后展示商品信息
</view>
</view>
<view class="price-num">
<view style="color: #fff;">
0.00
</view>
<view class="num">
x1
</view>
</view>
</view>
</view>
<view class="order-bottom">
<view class="time-total">
<view class="time">
{{ formatDateTime(item.createTime) }}
</view>
<view class="total">
{{ item.totalNum }}件商品
<text v-if="item.isGiftCardReceiveBlind === 0" class="total-txt">
&nbsp;&nbsp;&nbsp;&nbsp;总金额<text class="color-red">{{ item.payPrice }}</text>
</text>
</view>
</view>
<view class="btns">
<view class="btn" @click="viewOrderTrack">查看物流</view>
</view>
</view>
</view>
</template>
<script>
import { formatDateTime } from '@/utils/index'
export default {
name: 'AiHistoryList',
props: {
item: {
type: Object,
default: () => {}
}
},
data() {
return {
webUrl: this.$VUE_APP_RESOURCES_URL
}
},
methods: {
formatDateTime,
viewOrderTrack() {
this.$emit('viewOrderTrack', this.item)
}
}
}
</script>
<style scoped lang="less">
.order-item {
padding: 20rpx;
border-radius: 20rpx;
background-color: #fff;
box-shadow: 0rpx 6rpx 20rpx rgba(101,101,101,0.16);
.order-header {
display: flex;
align-items: center;
justify-content: space-between;
.order-shop {
flex: 1;
width: calc(100% - 120rpx);
.shop-name {
display: flex;
align-items: center;
color: #333;
font-size: 28rpx;
line-height: 40rpx;
.icon {
display: block;
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
}
}
.order-id {
margin-top: 20rpx;
font-size: 24rpx;
color: #666;
}
.status {
width: 100rpx;
height: 40rpx;
border-radius: 10rpx;
color: #fff;
font-size: 24rpx;
line-height: 40rpx;
text-align: center;
background: rgba(197,39,51,1);
}
}
.product-info {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 0;
font-size: 28rpx;
.good-img {
.img {
display: block;
width: 120rpx;
height: 120rpx;
border-radius: 8rpx;
}
}
.name-wrap {
height: 120rpx;
width: calc(100% - 260rpx);
.name {
line-height: 40rpx;
}
.attr {
display: inline-block;
height: 50rpx;
max-width: 100%;
padding: 0 25rpx;
margin: 20rpx 0 0 0;
border-radius: 25rpx;
line-height: 50rpx;
color: #252525;
background: rgba(239,239,239,0.39);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.price-num {
width: 100rpx;
text-align: right;
line-height: 40rpx;
.num {
font-size: 20rpx;
}
}
}
.product-info2 {
.name-wrap {
display: flex;
flex-direction: column;
justify-content: space-between;
.attr {
padding: 0;
font-size: 24rpx;
color: #999;
background-color: #fff;
}
}
}
.order-bottom {
.time-total {
display: flex;
align-items: center;
justify-content: space-between;
color: #999;
font-size: 22rpx;
.total-txt {
color: #333;
font-size: 28rpx;
font-weight: 600;
}
.color-red {
color: #C52733;
}
}
.btns {
display: flex;
align-items: center;
justify-content: flex-end;
margin: 24rpx 0 0 0;
.btn {
height: 44rpx;
padding: 0 24rpx;
border-radius: 22rpx;
border: 1rpx solid #C52733;
color: #C52733;
font-size: 28rpx;
line-height: 44rpx;
text-align: center;
}
}
}
}
</style>
-568
View File
@@ -1,568 +0,0 @@
import {
getSseConfigV1,
getCompletionsV2,
deleteChatItemByConversationId,
// getAnalyzeKeywordsV1,
getAnalyzeKeywordsChangeV1
} from '@/api/chat/index'
import { VUE_APP_API_URL } from '@/config'
import settings from '@/config/baseSetting.js'
import { formatAiMsgContent } from '../utils/aiChat'
import cookie from '@/utils/store/cookie'
import { handleLoginFailure } from '@/utils'
const plugin = requirePlugin('WechatSI')
const removeMarkdown = require('remove-markdown')
export const chatMixins = {
data() {
return {
token: cookie.get('login_status'),
userInfo: cookie.get('userInfo'),
webUrl: this.$VUE_APP_RESOURCES_URL,
bottomTools: Object.freeze([
{
icon: 'icon-50',
text: '我要送礼',
type: 'prompt',
prompt: '我要送礼,请给我推荐一些平台的礼品',
url: ''
},
{
icon: 'icon-51',
text: '订单查询',
type: 'prompt',
prompt: '订单查询',
url: ''
},
{
icon: 'icon-52',
text: '拍照识图',
type: 'link',
prompt: '',
url: '/aiChat/views/imageRecognition'
}
]),
scrollData: {},
scrollTop: 0,
isScrollToBottom: false,
// 状态栏高度
statusBarHeight: 20,
fileHttpStr: Object.freeze(VUE_APP_API_URL + settings.sysPrefix),
keyboardHeight: 0,
optionsFrom: '',
onFocus: false,
loading: false,
chatNumber: '',
infoResData: {},
chatMessageList: [
/*
{
type: -2,
isError: false,
showCursor: false,
conversationId: '',
prompt: '',
nodes: '-------------监听 WebSocket 接受到服务器的消息事件',
content: '-------------监听 WebSocket 接受到服务器的消息事件',
listQuestion: [
'监听 WebSocket 接受到服务器的消息事件',
'监听 WebSocket 接受到服务器的消息事件',
'监听 WebSocket 接受到服务器的消息事件'
]
}
*/
],
errorMsg: Object.freeze('您提的问题未能理解,云灵思想跑偏啦,重新整理一下问题或者重新提问,让云灵再试试!'),
audioAyy: [],
isPlayAudio: false,
audioContext: null,
audioPlayId: ''
}
},
computed: {
chatMessageListLength() {
return this.chatMessageList.length
}
},
onPageScroll(e) {
this.scrollData = e
const scrollTop = e.scrollTop
this.scrollTop = scrollTop
const query = wx.createSelectorQuery().in(this)
query.select('#fixTbabarBody').boundingClientRect(function(rect) {
const contentHeight = rect.height
const windowInfo = wx.getWindowInfo()
const windowHeight = windowInfo.windowHeight
if (scrollTop + windowHeight + 30 >= contentHeight) {
this.isScrollToBottom = true
} else {
this.isScrollToBottom = false
}
}.bind(this)).exec()
},
onUnload() {
this.audioStopHandle()
this.closeWsFn()
},
created() {
const _this = this
uni.getSystemInfo({
success: (e) => {
let statusBar = 0
// #ifdef MP-WEIXIN
statusBar = e.statusBarHeight
const custom = uni.getMenuButtonBoundingClientRect()
_this.rightDistance = e.windowWidth - custom.left + 10
// #endif
// 状态栏高度
_this.statusBarHeight = statusBar
}
})
_this.createdCallbak()
},
methods: {
createdCallbak() {
console.log('页面初始话回调')
},
inputFocusHandle(value) {
this.onFocus = value === 1
this.scrollToBottomHandle()
},
historyViewHandle() {
console.log(this.$refs.historyView)
this.$refs.historyView.showView()
},
copyContentHandle(data) {
uni.setClipboardData({
data,
success: () => {
uni.showToast({
title: '已复制'
})
}
})
},
copyMoreInfoHandle(item) {
uni.setClipboardData({
data: JSON.stringify(item.showMoreInfo),
success: () => {
uni.showToast({
title: '已复制'
})
}
})
},
shareHandle() {
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline'],
success: (res) => {
console.log(res)
},
fail: err => {
console.log(err)
}
})
},
scrollToBottomHandle() {
uni.pageScrollTo({
duration: 100,
selector: '#bottom_postion'
})
this.isScrollToBottom = true
},
// 重新生成
regenerateHandle(item) {
this.audioStopHandle()
deleteChatItemByConversationId(item.conversationId).then(res => {
const { success } = res
if (success) {
this.chatMessageList.splice(this.chatMessageListLength - 1, 1)
this.streamReq({
prompt: item.prompt,
init: 1
})
}
})
},
// 建议提问
suggestionItemClickHandle(question) {
this.streamReq({
prompt: question,
init: 0
})
},
// 大家都在问
topicItemClickHandle(question) {
this.streamReq({
prompt: question,
init: 0
})
},
streamReq(params) {
const _this = this
// 需要校验登录状态
if (!_this.token) {
handleLoginFailure()
return
}
const prompt = params.prompt
if (params.init !== 1) {
_this.chatMessageList.push({
prompt,
type: -1
})
}
_this.$nextTick(() => {
_this.scrollToBottomHandle()
})
_this.chatMessageList.push({
content: '',
nodes: '',
isError: false,
showCursor: false,
conversationId: '',
prompt,
listQuestion: [],
type: -2,
showMoreInfo: {}
})
_this.loading = true
_this.showCursor = false
getSseConfigV1({
'chatNumber': _this.chatNumber,
prompt
}).then(resConfig => {
const conversationId = resConfig.data.conversationId
_this.chatNumber = resConfig.data.chatNumber || ''
_this.chatMessageList[_this.chatMessageListLength - 1].showCursor = true
_this.chatMessageList[_this.chatMessageListLength - 1].conversationId = conversationId
if (conversationId) {
_this.initWebSocket(conversationId, () => {
getCompletionsV2({
conversationId,
ws: true,
isNoNeedPublicErrorNotification: 1
}).then(sseRes => {
console.log(sseRes)
// _this.closeWsFn()
}).catch(err => {
console.log(err)
_this.chatErrorSetContent()
})
})
/*
getAnalyzeKeywordsV1({
'chatNumber': _this.chatNumber,
conversationId,
prompt
}).then(keywordRes => {
if (keywordRes.success) {
const keywordResData = keywordRes.data
const show = (keywordResData.searchArtworks ||
keywordResData.searchDiscount ||
keywordResData.searchGoods ||
keywordResData.searchLandmark ||
keywordResData.searchTowns ||
keywordResData.searchTravelGuide
) && (keywordResData.resultItems && keywordResData.resultItems.length > 0)
_this.chatMessageList[_this.chatMessageListLength - 1].showMoreInfo = keywordResData
_this.chatMessageList[_this.chatMessageListLength - 1].showMoreInfo.show = show
// 展示类型
_this.chatMessageList[_this.chatMessageListLength - 1].showMoreInfo.showType = ''
if (show && keywordResData.resultItems) {
keywordResData.resultItems.map(resItem => {
_this.chatMessageList[_this.chatMessageListLength - 1].showMoreInfo.showType = resItem.type
})
}
console.log(_this.chatMessageList[_this.chatMessageListLength - 1])
}
})
*/
} else {
_this.chatErrorSetContent()
}
}).catch(err => {
console.log(err)
_this.chatErrorSetContent()
})
},
analyzeKeywordsChangeHandle(conversationId, showMoreInfo) {
getAnalyzeKeywordsChangeV1({
conversationId,
...showMoreInfo
}).then(res => {
const { success, data } = res
if (success) {
let resultItems = []
let idx = -1
this.chatMessageList.map((item, index) => {
if (item.conversationId === conversationId) {
resultItems = data.resultItems || []
idx = index
}
})
if (idx > -1) {
this.$set(this.chatMessageList[idx].showMoreInfo, 'resultItems', resultItems)
this.$forceUpdate()
}
}
})
},
productItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
path: '/pages/shop/GoodsCon/index',
query: {
id: item.id
}
})
},
hotelItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
path: '/pagesInn/inn/innHome',
query: {
id: item.id
}
})
},
ichItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
path: '/pkg_product/views/heritage/details',
query: {
id: item.id
}
})
},
qianxianItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
path: '/pkg_product/views/famousQianxianShop',
query: {
id: item.id
}
})
},
prizeItemClickHandle() {
this.audioStopHandle()
this.$yrouter.push({ path: '/pkg-video/views/lottery' })
},
chatErrorSetContent() {
this.chatMessageList[this.chatMessageListLength - 1].isError = true
this.chatMessageList[this.chatMessageListLength - 1].content = this.errorMsg
this.chatMessageList[this.chatMessageListLength - 1].nodes = this.errorMsg
this.closeWsFn()
},
closeWsFn() {
this.loading = false
if (this.chatMessageListLength) {
this.chatMessageList[this.chatMessageListLength - 1].showCursor = false
}
uni.closeSocket({
success: () => {
console.log('-----关闭连接')
}
})
this.$nextTick(() => {
this.scrollToBottomHandle()
})
},
initWebSocket(conversationId, cb) {
const _this = this
console.log('------------------创建连接')
uni.connectSocket({
url: VUE_APP_API_URL.replace('https', 'wss') + settings.sysPrefix + `v1/chat/websocket/${_this.userInfo.unionId}-${conversationId}`,
header: {
'content-type': 'application/json'
},
timeout: 10 * 1000,
success: () => {
console.log('------------WebSocket初始化成功')
},
fail: (err) => {
uni.showModal({
showCancel: false,
content: err
})
}
})
uni.onSocketMessage(res => {
_this.websocketOnmessage(res)
})
uni.onSocketOpen(() => {
cb && cb()
_this.websocketOnopen()
})
uni.onSocketError(err => {
_this.websocketOnerror(err)
})
},
websocketOnmessage(res) {
console.log('-------------监听 WebSocket 接受到服务器的消息事件')
const resData = JSON.parse(res.data)
if (resData) {
const message = resData.message
if (message && this.chatMessageListLength > 1) {
const mesContent = message.content
this.chatMessageList[this.chatMessageListLength - 1].nodes = formatAiMsgContent(mesContent)
this.chatMessageList[this.chatMessageListLength - 1].content = mesContent
this.chatMessageList[this.chatMessageListLength - 1].listQuestion = message.listQuestion || []
this.$forceUpdate()
this.$nextTick(() => {
this.scrollToBottomHandle()
if (message.finish) {
this.closeWsFn()
}
})
}
}
},
websocketOnopen() {
console.log('------------------监听 WebSocket 连接打开事件')
// this.websocketSend(JSON.stringify({ msg: '1' }))
},
websocketOnerror(e) {
console.log('-----------------监听 WebSocket 错误事件')
console.log(e)
},
websocketSend(msg) {
// 数据发送
try {
uni.sendSocketMessage({
data: msg,
success: () => {
console.log('-----------发送消息成功了')
}
})
} catch (err) {
console.log('send failed (' + err.code + ')')
}
},
audioStopHandle() {
// Fix bug#4049
this.audioAyy = []
if (this.audioContext) {
this.audioContext.stop()
this.audioContext.destroy() // 强制销毁释放资源
this.audioContext = null
}
this.isPlayAudio = false
// 强制关闭微信小程序背景音频
if (typeof wx !== 'undefined' && wx.getBackgroundAudioManager) {
wx.getBackgroundAudioManager().stop()
}
},
ttsHandle(item) {
this.audioAyy = []
if (this.audioContext) {
this.audioContext.stop()
// this.audioContext.destroy()
}
// 如果正在播放,点击当前播放的则认为是暂停
if (this.isPlayAudio && item.conversationId === this.audioPlayId) {
this.isPlayAudio = false
this.audioPlayId = ''
return
}
this.isPlayAudio = false
this.audioPlayId = item.conversationId
const flag = 1
if (flag === 1) {
console.log(removeMarkdown(item.content).replace(/[\n\t\s]/g, ''))
uni.showLoading({
title: '合成中...'
})
this.splitAndSynthesize(removeMarkdown(item.content).replace(/[\n\t\s]/g, ''))
} else {
// 调试数据
this.audioAyy = [
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749075_2f71887cc48d9b3753c39d119862d4bb&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749077_0970508786c5e3edc3a68a5eb9de048c&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749079_e77cec52cc077ba981892887c3df4cdf&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749080_02db4235771f5561cdb73c06d8c67e53&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749082_534e455c5d6ac5e9a4192ecf9952851a&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749083_78c4a2fecad538561f81c48dc4ecd645&filekey=871027724&source=miniapp_plugin'
]
this.playNextChunk()
}
},
splitAndSynthesize(text) {
const _this = this
if (text) {
const textLength = text.length
const chunkSize = 100
const chunk = text.slice(0, textLength > chunkSize ? chunkSize : textLength)
plugin.textToSpeech({
// 语言
lang: 'zh_CN',
tts: true,
// 要转换的文字
content: chunk,
success: function(res) {
console.log("语音文件路径:", res.filename)
_this.audioAyy.push(res.filename)
// 首次就立即播放,增强体验
if (!_this.isPlayAudio) {
_this.playNextChunk()
}
if (textLength > chunkSize) {
// 递归调用,播放一定要按照文本分割顺序
_this.splitAndSynthesize(text.substr(chunkSize, textLength))
} else {
// 最后一条合成,没有正在播放则立即播放
if (!_this.isPlayAudio) {
_this.playNextChunk()
}
}
uni.hideLoading()
},
fail: function(err) {
console.log("转换失败:", err)
uni.hideLoading()
}
})
} else {
if (!_this.isPlayAudio) {
_this.playNextChunk()
}
uni.hideLoading()
}
},
playNextChunk() {
if (this.audioAyy.length > 0 && this.audioPlayId) {
const src = this.audioAyy.shift()
this.isPlayAudio = true
const audioContext = uni.createInnerAudioContext({
// 是否使用 WebAudio 作为底层音频驱动,默认关闭。对于短音频、播放频繁的音频建议开启此选项,开启后将获得更优的性能表现。由于开启此选项后也会带来一定的内存增长,因此对于长音频建议关闭此选项
useWebAudioImplement: false
})
this.audioContext = audioContext
audioContext.src = src
audioContext.onEnded(() => {
audioContext.destroy()
this.playNextChunk()
})
audioContext.play()
console.log('------------src' + src)
} else {
console.log('------------end')
this.isPlayAudio = false
}
},
bottomToolClickHandle(item) {
if (item.type === 'prompt') {
this.streamReq({
prompt: item.prompt,
init: 0
})
}
if (item.type === 'link') {
uni.navigateTo({
url: item.url
})
}
}
}
}
-969
View File
@@ -1,969 +0,0 @@
import {
getSseConfigV1,
getCompletionsV3,
deleteChatItemByConversationId,
// getAnalyzeKeywordsV1,
getAnalyzeKeywordsChangeV3,
getSseCountyAiConfigV1,
getCountyAiCompletionsV1,
getGiftRecommendOptions,
getGiftRecommendPrompt
} from '@/api/chat/index'
import {
getExceptionConfig,
getBottomNavigationConfigList
} from '@/api/public'
import {
getProductDetail,
postCartAdd
} from '@/api/store'
import { VUE_APP_API_URL } from '@/config'
import settings from '@/config/baseSetting.js'
import { formatAiMsgContent } from '../utils/aiChat'
import cookie from '@/utils/store/cookie'
import { handleLoginFailure } from '@/utils'
const plugin = requirePlugin('WechatSI')
const removeMarkdown = require('remove-markdown')
export const chatMixinsV2 = {
data() {
return {
token: cookie.get('login_status'),
userInfo: cookie.get('userInfo'),
webUrl: this.$VUE_APP_RESOURCES_URL,
bottomTools: [],
scrollData: {},
scrollTop: 0,
isScrollToBottom: false,
// 状态栏高度
statusBarHeight: 20,
bottomSafeDistance: 0,
fileHttpStr: Object.freeze(VUE_APP_API_URL + settings.sysPrefix),
keyboardHeight: 0,
optionsFrom: '',
onFocus: false,
loading: false,
chatNumber: '',
infoResData: {},
chatMessageList: [],
audioAyy: [],
isPlayAudio: false,
audioContext: null,
audioPlayId: '',
showGiftBtn: false,
buyLoading: false,
buyActionLock: false,
exceptionConfig: {
model_exception: '您提的问题未能理解,云灵思想跑偏啦,重新整理一下问题或者重新提问,让云灵再试试!',
voice_exception: ''
},
giftStepLoading: false,
onlyOneToAddCart: false
}
},
computed: {
chatMessageListLength() {
return this.chatMessageList.length
}
},
onPageScroll(e) {
this.scrollData = e
const scrollTop = e.scrollTop
this.scrollTop = scrollTop
const query = wx.createSelectorQuery().in(this)
query.select('#fixTbabarBody').boundingClientRect(function(rect) {
const contentHeight = rect.height
const windowInfo = wx.getWindowInfo()
const windowHeight = windowInfo.windowHeight
if (scrollTop + windowHeight + 30 >= contentHeight) {
this.isScrollToBottom = true
} else {
this.isScrollToBottom = false
}
}.bind(this)).exec()
},
onUnload() {
this.audioStopHandle()
this.closeWsFn()
},
onHide() {
this.audioStopHandle()
},
created() {
const _this = this
uni.getSystemInfo({
success: (e) => {
let statusBar = 0
// #ifdef MP-WEIXIN
statusBar = e.statusBarHeight
const custom = uni.getMenuButtonBoundingClientRect()
_this.rightDistance = e.windowWidth - custom.left + 10
// #endif
// 状态栏高度
_this.statusBarHeight = statusBar
_this.bottomSafeDistance = e.safeAreaInsets.bottom
}
})
_this.createdCallbak()
},
methods: {
createdCallbak() {
this.$nextTick(() => {
this.scrollToBottomHandle()
getExceptionConfig().then(res => {
const { success, data } = res
if (success) {
this.exceptionConfig = data || {}
}
})
// 县域AI没有底部快捷操作和送礼配置
if (!this.countyId) {
getBottomNavigationConfigList().then(res => {
const { success, data } = res
if (success) {
this.bottomTools = data || []
this.bottomTools.forEach(item => {
item.display = true
})
}
})
getGiftRecommendOptions().then(res => {
const { success, data } = res
if (success) {
this.giftBuyOptions = data || {}
}
})
}
this.extraReqFn()
})
},
extraReqFn() {
console.log('首页/历史详情页面单独请求接口逻辑')
},
inputFocusHandle(value) {
this.onFocus = value === 1
this.scrollToBottomHandle()
},
historyViewHandle() {
console.log(this.$refs.historyView)
this.$refs.historyView.showView()
},
copyContentHandle(data) {
uni.setClipboardData({
data,
success: () => {
uni.showToast({
title: '已复制'
})
}
})
},
copyMoreInfoHandle(item) {
uni.setClipboardData({
data: JSON.stringify(item.showMoreInfo),
success: () => {
uni.showToast({
title: '已复制'
})
}
})
},
shareHandle() {
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline'],
success: (res) => {
console.log(res)
},
fail: err => {
console.log(err)
}
})
},
scrollToBottomHandle() {
uni.pageScrollTo({
duration: 100,
selector: '#bottom_postion'
})
this.isScrollToBottom = true
},
// 重新生成
regenerateHandle(item) {
this.audioStopHandle()
deleteChatItemByConversationId(item.conversationId).then(res => {
const { success } = res
if (success) {
this.chatMessageList.splice(this.chatMessageListLength - 1, 1)
this.streamReq({
prompt: item.prompt,
init: 1
})
}
})
},
// 建议提问
suggestionItemClickHandle(question) {
this.streamReq({
prompt: question,
init: 0
})
},
// 大家都在问
topicItemClickHandle(question) {
this.streamReq({
prompt: question,
init: 0
})
},
streamReq(params) {
const _this = this
// 需要校验登录状态
if (!_this.token) {
handleLoginFailure()
return
}
if (params.prompt.length > 500) {
uni.showToast({
title: "字数已超出限制",
icon: "none",
duration: 5000
})
return
}
if (this.loading) return
const prompt = params.prompt.substr(0, 500)
if (params.init !== 1) {
_this.chatMessageList.push({
prompt,
type: -1
})
}
_this.$nextTick(() => {
_this.scrollToBottomHandle()
})
_this.chatMessageList.push({
content: '',
nodes: '',
isError: false,
showCursor: false,
conversationId: '',
prompt,
listQuestion: [],
// 特产商品
goodsList: [],
// 礼品商品
giftGoodsList: [],
// 非遗文化
ichList: [],
// 千县名品
qianxianList: [],
// 抽奖
prizeList: [],
// 店铺
shopList: [],
// 地标好物--屏蔽原因:实现此功能时,后端通过AI动态返回的图片不满足需求,后面就不要了
landmarksList: [],
// 订单
orderList: [],
type: -2,
showMoreInfo: {},
currentSwiperIndex: 0,
showChangeBtn: true,
changeIsRotate: false
})
_this.loading = true
_this.showCursor = false
let reqFn = null
let postData = {}
if (_this.countyId) {
reqFn = getSseCountyAiConfigV1
postData = {
'countyId': _this.countyId,
'chatNumber': _this.chatNumber,
prompt
}
} else {
reqFn = getSseConfigV1
postData = {
'chatNumber': _this.chatNumber,
prompt
}
}
reqFn(postData).then(resConfig => {
const conversationId = resConfig.data.conversationId
_this.chatNumber = resConfig.data.chatNumber || ''
_this.chatMessageList[_this.chatMessageListLength - 1].showCursor = true
_this.chatMessageList[_this.chatMessageListLength - 1].conversationId = conversationId
if (conversationId) {
_this.initWebSocket(conversationId, () => {
let completionsReqFn = null
let completionsPostData = {}
if (_this.countyId) {
completionsReqFn = getCountyAiCompletionsV1
completionsPostData = {
conversationId,
countyId: _this.countyId,
ws: true,
isNoNeedPublicErrorNotification: 1
}
} else {
completionsReqFn = getCompletionsV3
completionsPostData = {
conversationId,
ws: true,
isNoNeedPublicErrorNotification: 1
}
}
completionsReqFn(completionsPostData).then(sseRes => {
console.log(sseRes)
// _this.closeWsFn()
}).catch(err => {
console.log(err)
_this.chatErrorSetContent()
})
})
} else {
_this.chatErrorSetContent()
}
}).catch(err => {
console.log(err)
_this.chatErrorSetContent()
})
},
initWebSocket(conversationId, cb) {
const _this = this
console.log('------------------创建连接')
uni.connectSocket({
url: VUE_APP_API_URL.replace('https', 'wss') + settings.sysPrefix + `v1/chat/websocket/${_this.userInfo.unionId}-${conversationId}`,
header: {
'content-type': 'application/json'
},
timeout: 10 * 1000,
success: () => {
console.log('------------WebSocket初始化成功')
},
fail: (err) => {
uni.showModal({
showCancel: false,
content: err
})
}
})
uni.onSocketMessage(res => {
_this.websocketOnmessage(res)
})
uni.onSocketOpen(() => {
cb && cb()
_this.websocketOnopen()
})
uni.onSocketError(err => {
_this.websocketOnerror(err)
})
},
websocketOnmessage(res) {
console.log('-------------监听 WebSocket 接受到服务器的消息事件')
const resData = JSON.parse(res.data)
if (resData) {
const message = resData.message
console.log(message)
if (message && this.chatMessageListLength > 1) {
const mesContent = message.content
const contentType = message.contentType
const finish = message.finish
if (contentType === 'text') {
if (!finish && mesContent) {
this.chatMessageList[this.chatMessageListLength - 1].nodes = formatAiMsgContent(mesContent)
this.chatMessageList[this.chatMessageListLength - 1].content = mesContent
this.chatMessageList[this.chatMessageListLength - 1].listQuestion = message.listQuestion || []
}
}
if (contentType === 'order') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].orderList = message.listCards || []
}
}
if (contentType === 'shop') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].shopList = message.listCards || []
}
}
if (contentType === 'gift') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].giftGoodsList = message.listCards || []
}
}
if (contentType === 'discount') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].prizeList = message.listCards || []
}
}
if (contentType === 'goods') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].goodsList = message.listCards || []
}
}
if (contentType === 'famous') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].qianxianList = message.listCards || []
}
}
if (contentType === 'ich') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].ichList = message.listCards || []
}
}
if (contentType === 'landmarks') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].landmarksList = message.listCards || []
}
}
this.$forceUpdate()
this.$nextTick(() => {
this.scrollToBottomHandle()
if (finish) {
this.closeWsFn()
}
})
}
}
},
websocketOnopen() {
console.log('------------------监听 WebSocket 连接打开事件')
// this.websocketSend(JSON.stringify({ msg: '1' }))
},
websocketOnerror(e) {
console.log('-----------------监听 WebSocket 错误事件')
console.log(e)
},
websocketSend(msg) {
// 数据发送
try {
uni.sendSocketMessage({
data: msg,
success: () => {
console.log('-----------发送消息成功了')
}
})
} catch (err) {
console.log('send failed (' + err.code + ')')
}
},
onSwiperChange(index, e) {
this.chatMessageList[index].currentSwiperIndex = e.detail.current
},
analyzeKeywordsChangeHandle(conversationId, item) {
let idx = -1
this.chatMessageList.map((item, index) => {
if (item.conversationId === conversationId) {
idx = index
}
})
if (idx > -1) {
if (this.chatMessageList[idx].changeIsRotate) {
return
}
this.$set(this.chatMessageList[idx], 'changeIsRotate', true)
}
let listKey = ''
// 抽奖和订单查询没有换一换
if (item.goodsList.length > 0) {
listKey = 'goodsList'
}
if (item.giftGoodsList.length > 0) {
listKey = 'giftGoodsList'
}
if (item.ichList.length > 0) {
listKey = 'ichList'
}
if (item.qianxianList.length > 0) {
listKey = 'qianxianList'
}
if (item.shopList.length > 0) {
listKey = 'shopList'
}
getAnalyzeKeywordsChangeV3({
conversationId
}).then(res => {
const { success, data } = res
if (success) {
let changeList = []
this.chatMessageList.map((item) => {
if (item.conversationId === conversationId) {
changeList = data.list || []
}
})
if (idx > -1 && listKey) {
this.$set(this.chatMessageList[idx], listKey, changeList)
this.$forceUpdate()
}
setTimeout(() => {
this.$set(this.chatMessageList[idx], 'changeIsRotate', false)
}, 1000)
}
}).catch(error => {
this.$set(this.chatMessageList[idx], 'changeIsRotate', false)
})
},
productItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
path: '/pages/shop/GoodsCon/index',
query: {
id: item.id
}
})
},
productItemSupplierClickHandle(item) {
if (!item.storeId) {
return
}
this.audioStopHandle()
this.$yrouter.push({
path: '/pagesInn/inn/innHome',
query: {
id: item.storeId
}
})
},
productItemBuyNowClickHandle(item) {
this.showGiftBtn = false
this.productItemBuyNowOrGiftBuy(item, 1)
},
productItemGiftBuyClickHandle(item) {
this.showGiftBtn = true
this.productItemBuyNowOrGiftBuy(item, 2)
},
productItemBuyNowOrGiftBuy(item, BuyNowOrGiftBuyType) {
if (this.buyActionLock) {
return
}
this.buyActionLock = true
this.audioStopHandle()
this.cart_num = 1
this.m_id = item.id
getProductDetail(item.id).then(res => {
const { data } = res
this.storeInfo = {...data.storeInfo}
if(data.storeInfo.stock === 0) {
this.buyActionLock = false
uni.showToast({
title: "产品库存不足,请选择其他商品",
icon: "none",
duration: 5000
})
return
}
this.isWenwan = data.isWenwan
this.qualifications = data.qualifications || []
// 给 attr 赋值,将请求回来的规格赋值给 attr
if (this.source !== 'pre' && this.source !== 'day' && this.source !== 'kill' && this.source !== 'spe') {
this.attr.productAttr = data.productAttr || []
this.productValueArr = []
for (const key in data.productValue) {
this.productValueArr.push({
attrItemkey: key,
...data.productValue[key]
})
}
// 初始化认为所有的规格都是可以选的
this.attr.productAttr.map(item => {
item.attrValue.map(subItem => {
subItem.canUsed = true
})
})
}
this.attr.defaultSku = data.defaultSku
this.attr.defaultSkuIndex = data.defaultSkuIndex
this.DefaultSelect()
// 是否单一规格
const onlyOne = Object.keys(data.productValue).length === 1
if(onlyOne) {
this.buyNowOrGiftBuyReq(BuyNowOrGiftBuyType)
return
}
this.attr.cartAttr = !this.isOpen ? true : false
this.buyActionLock = false
}).catch(error => {
this.buyActionLock = false
uni.showToast({
title: error.msg || '操作失败,请稍后重试',
icon: "none",
duration: 3000
})
})
},
buyNowOrGiftBuyReq(type) {
const _this = this
if (_this.buyLoading) {
return
}
_this.buyLoading = true
postCartAdd({
productId: _this.m_id,
cartNum: _this.attr.productSelect.cart_num,
new: 1,
uniqueId: _this.attr.productSelect !== undefined ? _this.attr.productSelect.unique : ''
}).then(function (res) {
try {
_this.closeAttrWindow()
const { cartId } = res.data
if (type === 1) {
uni.navigateTo({
url: '/pages/order/OrderSubmission/index?id=' + cartId
})
return
}
if(type === 2) {
uni.navigateTo({
url: '/pkg_user/views/gift/gift?cartId=' + cartId
})
return
}
} catch (error) {
console.log(error)
}
}).catch(error => {
uni.showToast({
title: error.msg,
icon: "none",
duration: 5000
})
}).finally(() => {
_this.buyLoading = false
_this.buyActionLock = false
})
},
closeAttrWindow() {
this.$set(this.attr, 'cartAttr', false)
},
hotelItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
path: '/pagesInn/inn/innHome',
query: {
id: item.id
}
})
},
ichItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
path: '/pkg_product/views/heritage/details',
query: {
id: item.id
}
})
},
qianxianItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
path: '/pkg_product/views/famousQianxianShop',
query: {
id: item.id
}
})
},
prizeItemClickHandle() {
this.audioStopHandle()
this.$yrouter.push({ path: '/pkg-video/views/lottery' })
},
chatErrorSetContent() {
this.chatMessageList[this.chatMessageListLength - 1].isError = true
this.chatMessageList[this.chatMessageListLength - 1].content = this.exceptionConfig.model_exception
this.chatMessageList[this.chatMessageListLength - 1].nodes = this.exceptionConfig.model_exception
this.closeWsFn()
},
closeWsFn() {
this.loading = false
if (this.chatMessageListLength) {
this.chatMessageList[this.chatMessageListLength - 1].showCursor = false
}
uni.closeSocket({
success: () => {
console.log('-----关闭连接')
}
})
this.$nextTick(() => {
this.scrollToBottomHandle()
})
},
audioStopHandle() {
// 强制关闭微信小程序背景音频
try {
const bgAudio = wx.getBackgroundAudioManager ? wx.getBackgroundAudioManager() : null
if (bgAudio && typeof bgAudio.stop === 'function') {
bgAudio.stop()
bgAudio.src = ''
bgAudio.title = ''
}
} catch (e) {
console.warn('stop background audio failed', e)
}
this.audioPlayId = ''
// Fix bug#4049
this.audioAyy = []
if (this.audioContext) {
this.audioContext.stop()
this.audioContext.destroy() // 强制销毁释放资源
this.audioContext = null
}
this.isPlayAudio = false
},
ttsHandle(item) {
this.audioAyy = []
if (this.audioContext) {
this.audioContext.stop()
// this.audioContext.destroy()
}
// 如果正在播放,点击当前播放的则认为是暂停
if (this.isPlayAudio && [item.conversationId, item.messageId, item.parentMessageId].includes(this.audioPlayId)) {
this.isPlayAudio = false
this.audioPlayId = ''
return
}
this.isPlayAudio = false
this.audioPlayId = item.conversationId || item.messageId || item.parentMessageId
const flag = 1
if (flag === 1) {
console.log(removeMarkdown(item.content).replace(/[\n\t\s]/g, ''))
uni.showLoading({
title: '合成中...'
})
this.splitAndSynthesize(removeMarkdown(item.content).replace(/[\n\t\s]/g, ''))
} else {
// 调试数据
this.audioAyy = [
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749075_2f71887cc48d9b3753c39d119862d4bb&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749077_0970508786c5e3edc3a68a5eb9de048c&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749079_e77cec52cc077ba981892887c3df4cdf&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749080_02db4235771f5561cdb73c06d8c67e53&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749082_534e455c5d6ac5e9a4192ecf9952851a&filekey=871027724&source=miniapp_plugin',
'https://ae.weixin.qq.com/cgi-bin/mmasrai-bin/getmedia?filename=1750749083_78c4a2fecad538561f81c48dc4ecd645&filekey=871027724&source=miniapp_plugin'
]
this.playNextChunk()
}
},
splitAndSynthesize(text) {
const _this = this
if (text) {
const textLength = text.length
const chunkSize = 100
const chunk = text.slice(0, textLength > chunkSize ? chunkSize : textLength)
plugin.textToSpeech({
// 语言
lang: 'zh_CN',
tts: true,
// 要转换的文字
content: chunk,
success: function(res) {
console.log("语音文件路径:", res.filename)
_this.audioAyy.push(res.filename)
// 首次就立即播放,增强体验
if (!_this.isPlayAudio) {
_this.playNextChunk()
}
if (textLength > chunkSize) {
// 递归调用,播放一定要按照文本分割顺序
_this.splitAndSynthesize(text.substr(chunkSize, textLength))
} else {
// 最后一条合成,没有正在播放则立即播放
if (!_this.isPlayAudio) {
_this.playNextChunk()
}
}
uni.hideLoading()
},
fail: function(err) {
console.log("转换失败:", err)
uni.hideLoading()
}
})
} else {
if (!_this.isPlayAudio) {
_this.playNextChunk()
}
uni.hideLoading()
}
},
playNextChunk() {
if (!this.audioAyy.length || !this.audioPlayId) {
this.isPlayAudio = false
return
}
// 销毁旧实例
if (this.audioContext) {
this.audioContext.stop()
this.audioContext.destroy()
this.audioContext = null
}
const src = this.audioAyy.shift()
this.isPlayAudio = true
const audioContext = uni.createInnerAudioContext({
useWebAudioImplement: true // 短音频建议 true
})
this.audioContext = audioContext
audioContext.src = src
audioContext.onPlay(() => {
console.log('audio play:', src)
})
audioContext.onEnded(() => {
this.audioContext = null
audioContext.destroy()
this.playNextChunk()
})
audioContext.onError((err) => {
console.error('audio error', err)
this.audioContext = null
audioContext.destroy()
this.playNextChunk()
})
audioContext.play()
},
bottomToolClickHandle(item) {
// 非界面跳转的需要校验登录状态
if (!this.token && item.navType !== 'url') {
handleLoginFailure()
return
}
const idx = this.bottomTools.findIndex((i) => i.giftCardEnabled === 1)
if (item.giftCardEnabled === 1) {
// 新建会话
this.createNewHandle('giftChat')
this.$set(this, 'showGiftSteps', true)
if (idx > -1) {
this.$set(this.bottomTools[idx], 'display', false)
}
return
}
this.$set(this, 'showGiftSteps', false)
if (idx > -1) {
this.$set(this.bottomTools[idx], 'display', true)
}
if (item.navType === 'prompt') {
this.streamReq({
prompt: item.promptContent,
init: 0
})
}
if (item.navType === 'url') {
uni.navigateTo({
url: item.url
})
}
},
viewOrderTrackHandle(order) {
uni.navigateTo({
url: '/pagesOrder/order/OrderDetails/index?id=' + order.orderId
})
},
isGiftOptionSelected(configId, optionId) {
if (!this.giftSelections[configId]) return false
return this.giftSelections[configId].includes(optionId)
},
toggleGiftOption(configId, optionId) {
if (!this.giftSelections[configId]) {
this.$set(this.giftSelections, configId, [])
}
const index = this.giftSelections[configId].indexOf(optionId)
if (index > -1) {
this.giftSelections[configId].splice(index, 1)
} else {
this.giftSelections[configId].push(optionId)
}
},
prevGiftStep() {
if (this.currentGiftStepIndex > 0) {
this.currentGiftStepIndex--
}
},
nextGiftStep() {
const currentStep = this.giftBuyOptions[this.currentGiftStepIndex]
let hasSelection = false
// 校验是否已选择
if (currentStep.type === 'option_card') {
const selectedIds = this.giftSelections[currentStep.id] || []
hasSelection = selectedIds.length > 0
} else if (currentStep.type === 'price_input') {
hasSelection = !!this.giftBudget
}
if (!hasSelection) {
uni.showToast({
title: '请完善信息后再点击下一步',
icon: 'none'
})
return
}
if (this.currentGiftStepIndex < this.giftBuyOptions.length - 1) {
this.currentGiftStepIndex++
} else {
this.finishGiftSteps()
}
},
skipGiftStep() {
if (this.currentGiftStepIndex < this.giftBuyOptions.length - 1) {
this.currentGiftStepIndex++
} else {
this.finishGiftSteps()
}
},
finishGiftSteps() {
if (this.giftStepLoading || this.loading) return
const selectedSteps = []
this.giftBuyOptions.forEach(step => {
if (step.type === 'option_card') {
const selectedIds = this.giftSelections[step.id] || []
if (selectedIds.length > 0) {
const selectedNames = step.options.filter(opt => selectedIds.includes(opt.id)).map(opt => opt.optionName)
selectedSteps.push({
sort: step.sort,
title: step.title,
type: step.type,
options: selectedNames
})
}
} else if (step.type === 'price_input') {
if (this.giftBudget) {
selectedSteps.push({
sort: step.sort,
title: step.title,
type: step.type,
options: [this.giftBudget]
})
}
}
})
console.log(selectedSteps)
uni.showLoading()
this.giftStepLoading = true
getGiftRecommendPrompt(selectedSteps).then(res => {
const { success, data } = res
if (success) {
this.showGiftSteps = false
this.streamReq({
prompt: data.prompt || '我想送礼',
init: 0
})
// 清空所有送礼选项
this.giftSelections = {}
this.giftBudget = ''
this.currentGiftStepIndex = 0
}
}).finally(() => {
uni.hideLoading()
this.giftStepLoading = false
})
}
}
}
-90
View File
@@ -1,90 +0,0 @@
// 引入markdown-it库
import MarkdownIt from './/markdown-it.min.js'
// hljs是由 Highlight.js 经兼容性修改后的文件,请勿直接升级。否则会造成uni-app-vue3-Android下有兼容问题
import hljs from './highlight/highlight-uni.min.js'
// 初始化 MarkdownIt库
const markdownIt = MarkdownIt({
// 在源码中启用 HTML 标签
html: true,
// 如果结果以 <pre ... 开头,内部包装器则会跳过。
highlight: function(str, lang) {
// if (lang && hljs.getLanguage(lang)) {
// console.error('lang', lang)
// try {
// return '<pre class="hljs" style="padding: 5px 8px;margin: 5px 0;overflow: auto;display: block;"><code>' +
// hljs.highlight('lang', str, true).value +
// '</code></pre>';
// } catch (__) {}
// }
// 经过highlight.js处理后的html
let preCode = ''
try {
preCode = hljs.highlightAuto(str).value
} catch (err) {
preCode = markdownIt.utils.escapeHtml(str)
}
// 以换行进行分割
const lines = preCode.split(/\n/).slice(0, -1)
// 添加自定义行号
let html = lines.map((item, index) => {
// 去掉空行
if (item === '') {
return ''
}
return '<li><span class="line-num" data-line="' + (index + 1) + '"></span>' + item + '</li>'
}).join('')
html = '<ol style="padding: 0px 30px;">' + html + '</ol>'
let htmlCode = `<div style="background:#0d1117;margin-top: 5px;color: #888;padding:5px 0;border-radius: 5px;">`
htmlCode += `<pre class="hljs" style="padding:0 8px;margin-bottom:5px;overflow: auto;display: block;border-radius: 5px;"><code>${html}</code></pre>`
htmlCode += '</div>'
return htmlCode
}
})
export function formatAiMsgContent(val) {
if (!val) {
return ''
}
let htmlString = ''
// 修改转换结果的htmlString值 用于正确给界面增加鼠标闪烁的效果
// 判断markdown中代码块标识符的数量是否为偶数
if (val.split('```').length % 2) {
let msgContent = val
if (msgContent[msgContent.length - 1] !== '\n') {
msgContent += '\n'
}
msgContent += ' <span class="cursor">|</span>'
htmlString = markdownIt.render(msgContent)
} else {
htmlString = markdownIt.render(val)
htmlString = markdownIt.render(val) + ' \n <span class="cursor">|</span>'
}
// console.log(htmlString)
return htmlString
}
/**
* 简单实现防抖方法
*
* 防抖(debounce)函数在第一次触发给定的函数时,不立即执行函数,而是给出一个期限值(delay),比如100ms。
* 如果100ms内再次执行函数,就重新开始计时,直到计时结束后再真正执行函数。
* 这样做的好处是如果短时间内大量触发同一事件,只会执行一次函数。
*
* @param fn 要防抖的函数
* @param delay 防抖的毫秒数
* @returns {Function}
*/
export function simpleDebounce(fn, delay = 100) {
let timer = null
return function() {
const args = arguments
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(null, args)
}, delay)
}
}
-10
View File
@@ -1,10 +0,0 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: GitHub Dark
Description: Dark theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-dark
Current colors taken from GitHub's CSS
*/.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-733
View File
@@ -1,733 +0,0 @@
<template>
<view
:class="scrollTop > 0 ? 'page-scroll' : ''"
class="fix-tabbar-page"
>
<hx-navbar
:back="true"
:fixed="true"
:statusBar="true"
:pageScroll.sync="scrollData"
:title="pageTitle"
color="#333"
transparent="auto"
barPlaceholder="hidden"
/>
<view
id="fixTbabarBody"
:style="{
'padding-top': (44 + statusBarHeight) + 'px'
}"
class="fix-tabbar-body"
>
<view class="chat-wrap">
<view v-if="chatMessageListLength > 0" class="chat-list-wrap">
<view
v-for="(item, index) in chatMessageList"
:key="index"
class="chat-message-item"
>
<view v-if="item.type === -1" class="chat-message-body">
<view class="item-right">
<view class="txt">
{{ item.prompt }}
</view>
</view>
<view class="item-right-tools">
<view class="btn" @click="copyContentHandle(item.prompt)">
<image
:src="webUrl + '/aiChat/icon-02.png'"
class="icon"
mode="widthFix"
/>
复制
</view>
</view>
</view>
<view v-if="item.type === -2" class="chat-message-body">
<view class="avatar">
<image
:src="webUrl + '/aiChat/avatar.png'"
class="chat-avatar"
mode="widthFix"
/>
</view>
<view class="item-left">
<view class="txt">
<view
ref="rich-text-box"
:class="{
'show-cursor': item.showCursor
}"
class="rich-text-box"
>
<rich-text
v-if="item.nodes && item.nodes.length"
:nodes="item.nodes"
space="nbsp"
/>
<view v-if="!(item.nodes && item.nodes.length) && loading" class="loader-wrap">
<div class="loading2" />
</view>
</view>
<view
v-if="!item.showCursor && item.nodes && item.nodes.length && !item.isError"
class="bottom-btns"
>
<!-- <button
open-type="share"
plain="true"
class="item"
@click="shareHandle"
>
<image
:src="webUrl + '/icon-25.png'"
class="icon"
mode="widthFix"
/>
分享
</button> -->
<view class="item" @click="copyContentHandle(item.content)">
<image
:src="webUrl + '/aiChat/icon-02.png'"
class="icon"
mode="widthFix"
/>
复制
</view>
<view
v-if="index === (chatMessageListLength - 1)"
class="item"
@click="regenerateHandle(item)"
>
<image
:src="webUrl + '/aiChat/icon-04.png'"
class="icon"
mode="widthFix"
/>
重新生成
</view>
<view
:class="{
'playing': [item.conversationId, item.messageId, item.parentMessageId].includes(audioPlayId) && isPlayAudio
}"
class="item"
@click="ttsHandle(item)"
>
<image
:src="webUrl + '/aiChat/' + (([item.conversationId, item.messageId, item.parentMessageId].includes(audioPlayId) && isPlayAudio) ? 'audio-on' : 'audio-off') +'.png'"
class="icon"
mode="widthFix"
/>
语音播放
</view>
</view>
</view>
</view>
<!-- 换一换 -->
<view
v-if="!item.showCursor &&
!item.isError &&
(item.orderList.length > 0 ||
item.giftGoodsList.length > 0 ||
item.goodsList.length > 0 ||
item.shopList.length > 0 ||
item.prizeList.length > 0 ||
item.ichList.length > 0 ||
item.qianxianList.length > 0
)
"
class="change-list-wrap"
>
<!-- 礼品 -->
<view
v-if="item.giftGoodsList.length > 0"
class="recommend-goods-wrap"
>
<swiper
class="goods-swiper"
:indicator-dots="false"
:autoplay="false"
:current="item.currentSwiperIndex"
previous-margin="120rpx"
next-margin="120rpx"
circular
@change="e => onSwiperChange(index, e)"
>
<swiper-item
v-for="(goodItem, goodIndex) in item.giftGoodsList"
:key="goodIndex"
>
<view
:class="{ 'active': item.currentSwiperIndex === goodIndex }"
class="goods-item"
@click="productItemClickHandle(goodItem)"
>
<view class="supplier" @click.stop="productItemSupplierClickHandle(goodItem)">
<image
:src="webUrl + '/aiChat/icon-57.png'"
class="icon"
mode="widthFix"
lazy-load
/>
<text class="s-name">{{ goodItem.merName ||goodItem.storeName }}</text>
<u-icon name="arrow-right" color="#999" size="12"></u-icon>
</view>
<view class="title one-t">{{ goodItem.name }}</view>
<image :src="goodItem.img" class="p-img" mode="aspectFill" lazy-load />
<view class="price">
<text class="unit">¥</text>
<text class="num">{{ goodItem.price }}</text>
</view>
<view class="actions">
<view class="btn-buy" @click.stop="productItemBuyNowClickHandle(goodItem)">立即下单</view>
<view class="btn-gift" @click.stop="productItemGiftBuyClickHandle(goodItem)">送给朋友</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
<!-- 特产商品 -->
<view v-if="item.goodsList.length > 0" class="list-wrap">
<view
v-for="(productItem, productIndex) in item.goodsList"
:key="productIndex"
class="product-item"
@click="productItemClickHandle(productItem)"
>
<image
:src="productItem.img"
class="img"
lazy-load
/>
<view class="product-info">
<view class="name one-t">
{{ productItem.name }}
</view>
<view class="price-wrap">
<view class="price">
<text class="txt">¥</text>{{ productItem.price }}
</view>
<view class="btn">立即查看</view>
</view>
</view>
</view>
</view>
<!-- 店铺 -->
<view v-if="item.shopList.length > 0" class="list-wrap">
<view
v-for="(hotel, hotelIndex) in item.shopList"
:key="hotelIndex"
class="product-item"
@click="hotelItemClickHandle(hotel)"
>
<view class="hotel-type">
{{ hotel.hotelTypeName }}
</view>
<image
:src="hotel.img + ((hotel.img && hotel.img.indexOf('.mp4') > -1) ? '?vframe/jpg/offset/1' : '')"
class="img"
lazy-load
/>
<view class="product-info">
<view class="name one-t">
{{ hotel.name }}
</view>
<view class="desc-wrap one-t">
{{ hotel.description || '' }}
</view>
</view>
</view>
</view>
<!-- 非遗 -->
<view v-if="item.ichList.length > 0" class="list-wrap">
<view
v-for="(ich, ichIndex) in item.ichList"
:key="ichIndex"
class="product-item"
@click="ichItemClickHandle(ich)"
>
<image
:src="ich.img"
class="img"
/>
<view class="product-info">
<view class="name one-t">
{{ ich.name }}
</view>
<view class="desc-wrap one-t">
{{ ich.description || '' }}
</view>
</view>
</view>
</view>
<!-- 千县 -->
<view v-if="item.qianxianList.length > 0" class="list-wrap">
<view
v-for="(qianxian, qianxianIndex) in item.qianxianList"
:key="qianxianIndex"
class="product-item"
@click="qianxianItemClickHandle(qianxian)"
>
<image
:src="qianxian.img"
class="img"
lazy-load
/>
<view class="product-info">
<view class="name name2 one-t">
{{ qianxian.name }}
</view>
</view>
</view>
</view>
<!-- 抽奖 -->
<view v-if="item.prizeList.length > 0" class="list-wrap prize-list-wrap">
<view
v-for="(prize, prizeIndex) in item.prizeList"
:key="prizeIndex"
class="prize-item"
@click="prizeItemClickHandle(prize)"
>
<image
:src="prize.img"
class="img"
mode="widthFix"
lazy-load
/>
</view>
</view>
<!-- 订单 -->
<view v-if="item.orderList.length > 0" class="order-list-wrap">
<view
v-for="(order, orderIndex) in item.orderList"
:key="orderIndex"
class="order-item-wrap"
>
<order-item
:item="order"
@viewOrderTrack="viewOrderTrackHandle"
/>
</view>
</view>
<view
v-if="(item.shopList.length > 0 ||
item.goodsList.length > 0 ||
item.giftGoodsList.length > 0 ||
item.ichList.length > 0 ||
item.qianxianList.length > 0 ||
item.shopList.length > 0) && item.showChangeBtn
"
class="change-btn"
>
<view class="change-btn-content" @click="analyzeKeywordsChangeHandle(item.conversationId, item)">
<image
:src="webUrl + '/aiChat/icon-53.png'"
:class="{
'rotate': item.changeIsRotate
}"
class="icon"
mode="widthFix"
/>
换一换
</view>
</view>
</view>
<!-- 建议提问 -->
<view
v-if="index === (chatMessageListLength - 1) && item.listQuestion.length > 0"
class="suggestion-wrap"
>
<view class="suggestion-list">
<view
v-for="(question, questionIndex) in item.listQuestion"
:key="questionIndex"
class="item"
@click="suggestionItemClickHandle(question)"
>
<view class="item-cont">
<view class="txt">
{{ question }}
</view>
<image
:src="webUrl + '/aiChat/icon-03.png'"
class="pic"
mode="widthFix"
/>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view id="bottom_postion" class="bottom-postion" />
</view>
</view>
<view
:class="{
'focus': onFocus
}"
class="page-to-bottom"
>
<view class="down-icon-wrap">
<image
v-if="chatMessageListLength > 0 && !isScrollToBottom && !loading"
:src="webUrl + '/aiChat/down.png'"
class="icon down-icon"
mode="widthFix"
@click="scrollToBottomHandle"
/>
</view>
<view
:class="{
'container-county': !!countyId
}"
class="container"
>
<view
v-if="chatNumber"
class="new-chat"
@click="createNewHandle"
>
<image
:src="webUrl + '/aiChat/icon-54.png'"
class="btn-icon"
mode="widthFix"
/>
开启新对话
</view>
<view
v-if="!countyId"
v-for="(item, index) in bottomTools"
:key="index"
:class="{
'hide': !item.display
}"
class="bottom-tool-item"
@click="bottomToolClickHandle(item)"
>
<image
:src="item.icon"
class="tool-icon"
mode="widthFix"
/>
{{ item.name }}
</view>
</view>
</view>
<bottom-send
ref="bottomSend"
:loading="loading"
:keyboard-height="keyboardHeight"
:voice-exception="exceptionConfig.voice_exception"
@send="streamReq"
@history="historyViewHandle"
@focus="inputFocusHandle"
/>
<AiHistoryList
ref="historyView"
:status-bar-height="statusBarHeight"
:county-id="countyId"
form-module="history"
@enter-history="audioStopHandle"
/>
<ProductWindow
ref="attrWindow"
:attr="attr"
:cart-num="cart_num"
:show-ok="!showGiftBtn"
:is-gift="showGiftBtn"
:padding-bottom="'60px'"
class-name="ai-product-window"
ok-text="立即购买"
@changeFun="changeFun"
@ok="buyNowOrGiftBuyReq(1)"
@gift="buyNowOrGiftBuyReq(2)"
/>
</view>
</template>
<script>
import { chatMixinsV2 } from '../mixins/chatMixinsV2.js'
import goCartMixin from '@/mixins/goCartMixins'
import AiHistoryList from '../components/historyList'
import BottomSend from '../components/bottomSend.vue'
import OrderItem from '../components/orderItem.vue'
import ProductWindow from '@/components/ProductWindow'
import {
historyChatMessage,
getCountyAiHistoryChatMessage
} from '@/api/chat/index'
import { formatAiMsgContent } from '../utils/aiChat'
export default {
name: 'AiChatHistoryPage',
components: {
AiHistoryList,
BottomSend,
OrderItem,
ProductWindow
},
mixins: [chatMixinsV2, goCartMixin],
data() {
return {
pageTitle: '',
countyId: ''
}
},
onLoad(options) {
this.chatNumber = options.chatNumber
this.pageTitle = options.title || ''
this.countyId = options.countyId || ''
this.pageTitle = this.pageTitle.length > 8 ? (this.pageTitle.substring(0, 8) + '...') : this.pageTitle
this.init()
},
methods: {
init() {
this.loading = true
let reqFn = null
if (this.countyId) {
reqFn = getCountyAiHistoryChatMessage
} else {
reqFn = historyChatMessage
}
reqFn({
chatNumber: this.chatNumber
}).then(res => {
const { success, data = [] } = res
if (success) {
this.loading = false
try {
data.map(item => {
if (item.role === 'user') {
this.chatMessageList.push({
type: -1,
prompt: item.content
})
} else {
if (['text', 'skill_list'].includes(item.contentType)) {
const tempItemData = {
...item,
nodes: formatAiMsgContent(item.content),
prompt: this.getParentPrompt(data, item.parentMessageId),
conversationId: item.messageId,
showCursor: false,
listQuestion: item.listQuestion || [],
// 特产商品
goodsList: [],
// 礼品商品
giftGoodsList: [],
// 非遗文化
ichList: [],
// 千县名品
qianxianList: [],
// 抽奖
prizeList: [],
// 店铺
shopList: [],
// 地标好物--屏蔽原因:实现此功能时,后端通过AI动态返回的图片不满足需求,后面就不要了
landmarksList: [],
// 订单
orderList: [],
type: -2,
showMoreInfo: {},
currentSwiperIndex: 0,
showChangeBtn: false,
changeIsRotate: false
}
if (item.cardData) {
const { contentType, finish, items = [] } = item.cardData
if (contentType === 'order') {
tempItemData.orderList = items || []
}
if (contentType === 'shop') {
tempItemData.shopList = items || []
}
if (contentType === 'gift') {
tempItemData.giftGoodsList = items || []
}
if (contentType === 'discount') {
tempItemData.prizeList = items || []
}
if (contentType === 'goods') {
tempItemData.goodsList = items || []
}
if (contentType === 'famous') {
tempItemData.qianxianList = items || []
}
if (contentType === 'ich') {
tempItemData.ichList = items || []
}
if (contentType === 'landmarks') {
tempItemData.landmarksList = items || []
}
}
this.chatMessageList.push(tempItemData)
}
}
})
console.log(this.chatMessageList)
this.$nextTick(() => {
this.scrollToBottomHandle()
})
} catch (err) {
uni.showModal({
title: '错误提示',
content: JSON.stringify(err)
})
console.log(err)
}
}
}).catch(() => {
this.loading = false
})
},
getParentPrompt(list = '', parentMessageId) {
let prompt = ''
list.map(item => {
if (item.messageId === parentMessageId) {
prompt = item.content
}
})
return prompt
},
// 创建新会话
createNewHandle() {
uni.setStorageSync('addNewChat', '1')
uni.navigateBack()
},
bottomToolClickHandle(item) {
if (item.giftCardEnabled === 1) {
uni.setStorageSync('addNewChat', '2')
uni.navigateBack()
return
}
if (item.navType === 'prompt') {
this.streamReq({
prompt: item.promptContent,
init: 0
})
}
if (item.navType === 'url') {
uni.navigateTo({
url: item.url
})
}
}
}
}
</script>
<style lang="scss" scoped>
.chat-wrap {
padding: 0 0 180rpx 0;
.chat-info-wrap {
padding: 24rpx;
.chat-list-wrap2 {
padding: 0;
}
}
}
.loading-wrap {
text-align: center;
color: #666;
line-height: 120rpx;
}
.rich-text-box {
max-width: 100%;
}
.show-cursor .cursor {
display: inline-block;
color: #3D4CF1;
font-weight: bold;
animation: blinking 1s infinite;
}
@keyframes blinking {
from {
opacity: 1.0;
}
to {
opacity: 0.0;
}
}
.focus-guide-wrap {
display: flex;
align-items: center;
justify-content: space-between;
padding: 60rpx 40rpx;
.guide-left {
.avatar {
display: block;
width: 267rpx;
height: 530rpx;
}
}
.guide-right {
padding: 30rpx;
margin: 0 0 0 40rpx;
border-radius: 20rpx;
font-size: 24rpx;
background-color: #fff;
box-shadow: 0rpx 12rpx 30rpx rgba(0,0,0,0.1);
.title {
font-weight: bold;
}
.content {
padding: 30rpx 0 0 0;
color: #999;
}
}
}
.topic-wrap {
width: 100%;
.title {
display: flex;
align-items: center;
justify-content: center;
.txt {
width: 186rpx;
height: 46rpx;
margin: 0 20rpx;
border-radius: 24rpx;
text-align: center;
line-height: 46rpx;
color: #fff;
font-size: 26rpx;
background-color: #3D4CF1;
}
.icon {
display: flex;
width: 40rpx;
}
}
.list-wrap {
width: 100%;
margin: 60rpx 0 0 0;
overflow-x: auto;
.list-cont {
display: flex;
flex-wrap: wrap;
width: 150%;
.list-item {
display: flex;
align-items: center;
height: 40rpx;
padding: 0 12rpx;
margin: 0 30rpx 30rpx 0;
border-radius: 20rpx;
font-size: 24rpx;
color: #666;
background: rgba(255,255,255,0.39);
box-shadow: 0rpx 6rpx 12rpx rgba(0,0,0,0.1);
.icon {
display: block;
width: 24rpx;
height: 24rpx;
margin: 0 8rpx 0 0;
}
}
}
}
}
</style>
-227
View File
@@ -1,227 +0,0 @@
<template>
<view
:style="{ 'background-image': 'url(' + webUrl + '/aiChat/bg-05.png)' }"
class="image-recognition-page"
>
<hx-navbar
:back="true"
:fixed="true"
:statusBar="true"
left-icon="arrowleft"
color="#333"
transparent="auto"
barPlaceholder="hidden"
title="云灵"
/>
<view
class="main-content"
:style="{ 'padding-top': (44 + statusBarHeight) + 'px' }"
>
<!-- 拍照区域 -->
<view class="camera-section" @click="takePhoto">
<view class="dashed-border-box">
<view class="icon-wrap">
<image
:src="webUrl + '/aiChat/icon-55.png'"
class="camera-icon"
mode="widthFix"
/>
</view>
<view class="main-title">对准商品拍照</view>
<view class="sub-tip">示例特产/零食/茶叶/纪念品</view>
</view>
</view>
<!-- 底部相册上传按钮 -->
<view class="bottom-action">
<button class="album-btn" @click="chooseImage">
<image
:src="webUrl + '/aiChat/icon-56.png'"
class="upload-icon"
mode="widthFix"
/>
<text>从相册上传图片进行识别</text>
</button>
</view>
</view>
</view>
</template>
<script>
import { chatMixins } from '../mixins/chatMixins.js'
import { VUE_APP_API_URL } from '@/config'
export default {
name: 'AiChatImageRecognitionPage',
mixins: [chatMixins],
data() {
return {
}
},
methods: {
createdCallbak() {
// 覆盖 mixins 中的 createdCallbak,避免触发默认逻辑
},
takePhoto() {
if (this.loading) return
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['camera'],
success: (res) => {
this.handleUpload(res.tempFilePaths[0])
}
})
},
chooseImage() {
if (this.loading) return
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album'],
success: (res) => {
this.handleUpload(res.tempFilePaths[0])
}
})
},
handleUpload(filePath) {
const _this = this
uni.showLoading({ title: '识别中...' })
_this.loading = true
uni.uploadFile({
url: `${VUE_APP_API_URL}/api/upload`,
filePath: filePath,
header: {
Authorization: 'Bearer ' + (_this.token || '')
},
name: 'file',
success: (uploadRes) => {
const resData = JSON.parse(uploadRes.data)
if (resData.link) {
_this.performRecognition(resData.link)
} else {
uni.hideLoading()
_this.loading = false
_this.$toast('上传失败,请重试')
}
},
fail: (err) => {
console.log('Upload Error:', err)
uni.hideLoading()
_this.loading = false
_this.$toast('网络异常,请重试')
}
})
},
performRecognition(imageUrl) {
// 存储识别到的图片URL
uni.setStorageSync('recognitionImage', imageUrl)
uni.navigateTo({
url: '/aiChat/views/imageRecognitionResult'
})
uni.hideLoading()
this.loading = false
}
}
}
</script>
<style lang="scss" scoped>
.image-recognition-page {
height: 100vh;
background-size: 100% 100%;
.main-content {
display: flex;
flex-direction: column;
align-items: center;
padding: 60rpx 40rpx;
height: 100vh;
box-sizing: border-box;
}
.camera-section {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 60rpx;
.dashed-border-box {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 600rpx;
width: 100%;
margin-top: 80rpx;
border: 2rpx dashed #DCDFE6;
border-radius: 24rpx;
background-color: rgba(255, 255, 255, 0.5);
.icon-wrap {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
border: 6rpx solid #7A3DF1;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 40rpx;
.camera-icon {
width: 80rpx;
height: 80rpx;
}
}
.main-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.sub-tip {
font-size: 28rpx;
color: #999;
}
}
}
.bottom-action {
width: 100%;
padding-bottom: 60rpx;
.album-btn {
width: 100%;
height: 100rpx;
background: #3D4CF1;
border-radius: 20rpx;
display: flex;
justify-content: center;
align-items: center;
color: #FFFFFF;
font-size: 32rpx;
border: none;
box-shadow: 0 8rpx 20rpx rgba(61, 76, 241, 0.3);
.upload-icon {
width: 36rpx;
height: 36rpx;
margin-right: 16rpx;
}
&::after {
border: none;
}
&:active {
opacity: 0.8;
}
}
}
}
</style>
-358
View File
@@ -1,358 +0,0 @@
<template>
<view class="image-recognition-result-page">
<view
class="page-body"
>
<view class="header">
<view
class="header-bg"
:style="{ 'background-image': imageUrl ? `url(${imageUrl})` : '' }"
/>
<view class="header-mask" />
<view class="scan-wrap">
<image
v-if="imageUrl"
:src="imageUrl"
class="scan-image"
mode="aspectFill"
/>
<view class="corner tl" />
<view class="corner tr" />
<view class="corner bl" />
<view class="corner br" />
</view>
</view>
<view class="sheet">
<view class="sheet-thumb-row">
<image
v-if="imageUrl && confidenceFlag"
:src="imageUrl"
class="sheet-thumb"
mode="aspectFill"
lazy-load
/>
<view v-else class="empty-state">
<view class="empty-text">未识别到物品请重新尝试</view>
<view class="empty-title">为你推荐</view>
</view>
</view>
<view class="sheet-divider" />
<view v-if="!loaded" class="loading-state">
<u-loading-icon mode="circle" size="36" text="正在识别中..." vertical textSize="14"></u-loading-icon>
</view>
<view v-else class="goods-grid">
<view
v-for="(item, index) in goodsList"
:key="index"
class="goods-card"
@click="goGoods(item)"
>
<image
:src="item.img"
class="goods-img"
mode="aspectFill"
lazy-load
/>
<view class="goods-title">
{{ item.name }}
</view>
<view class="goods-price-row">
<view class="price-left">
<text class="price-symbol"></text>
<text class="price-val">{{ item.price }}</text>
</view>
<image
:src="webUrl + '/home/icon-cart.png'"
class="cart-btn"
mode="aspectFit"
lazy-load
/>
</view>
<view v-if="item.similarityScore > 0" class="goods-desc">
相似度{{ item.similarityScore }}%
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { getAnalyzeByImageV3 } from '@/api/chat'
import Recommend from '@/components/Recommend'
export default {
name: 'AiChatImageRecognitionResultPage',
components: {
Recommend
},
data() {
return {
loaded: false,
webUrl: this.$VUE_APP_RESOURCES_URL,
statusBarHeight: 20,
imageUrl: '',
goodsList: [],
confidenceFlag: true
}
},
onLoad(options) {
const urlFromQuery = options.imageUrl || ''
const urlFromStorage = uni.getStorageSync('recognitionImage') || ''
this.imageUrl = urlFromQuery || urlFromStorage || ''
if (urlFromStorage) {
// uni.removeStorageSync('recognitionImage')
}
this.init()
},
methods: {
init() {
this.loaded = false
getAnalyzeByImageV3({
imageUrl: this.imageUrl
}).then(res => {
const { data, success } = res
if (success) {
this.goodsList = data.cards || []
this.confidenceFlag = data.success
}
}).finally(() => {
this.loaded = true
})
},
goGoods(item) {
if (!item || !item.id) return
uni.navigateTo({
url: `/pages/shop/GoodsCon/index?id=${item.id}`
})
},
addToCart() {
}
}
}
</script>
<style lang="scss" scoped>
.image-recognition-result-page {
min-height: 100vh;
background: #fff;
.page-body {
min-height: 100vh;
}
.header {
position: relative;
height: 480rpx;
overflow: hidden;
}
.header-bg {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: #DDE6FF;
background-size: cover;
background-position: center;
filter: blur(18rpx);
transform: scale(1.2);
}
.header-mask {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.18);
}
.scan-wrap {
position: absolute;
left: 50%;
top: 45%;
width: 320rpx;
height: 320rpx;
transform: translate(-50%, -52%);
border-radius: 24rpx;
overflow: hidden;
// box-shadow: 0 18rpx 48rpx rgba(0, 0, 0, 0.18);
}
.scan-image {
display: block;
width: 100%;
height: 100%;
border-radius: 12rpx;
transform: scale(0.8);
}
.corner {
position: absolute;
width: 44rpx;
height: 44rpx;
border: 6rpx solid rgba(255, 255, 255, 0.95);
}
.corner.tl {
left: 16rpx;
top: 16rpx;
border-right: 0;
border-bottom: 0;
}
.corner.tr {
right: 16rpx;
top: 16rpx;
border-left: 0;
border-bottom: 0;
}
.corner.bl {
left: 16rpx;
bottom: 16rpx;
border-right: 0;
border-top: 0;
}
.corner.br {
right: 16rpx;
bottom: 16rpx;
border-left: 0;
border-top: 0;
}
.sheet {
position: relative;
margin-top: -70rpx;
background: #FFFFFF;
border-top-left-radius: 42rpx;
border-top-right-radius: 42rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 28rpx);
}
.sheet-thumb-row {
padding: 28rpx 0 18rpx 0;
display: flex;
justify-content: center;
}
.sheet-thumb {
width: 100rpx;
height: 100rpx;
border-radius: 18rpx;
display: block;
box-shadow: 0 10rpx 24rpx rgba(0, 0, 0, 0.12);
}
.sheet-divider {
height: 2rpx;
background: #EDEDED;
margin: 0 32rpx;
}
.loading-state {
padding: 120rpx 0;
display: flex;
justify-content: center;
align-items: center;
}
.empty-state {
text-align: center;
}
.empty-text {
font-size: 28rpx;
color: #999;
margin-bottom: 20rpx;
}
.empty-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.goods-grid {
padding: 28rpx 24rpx 0 24rpx;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.goods-card {
width: 344rpx;
background: #FFFFFF;
border-radius: 22rpx;
overflow: hidden;
margin-bottom: 22rpx;
box-shadow: 0 10rpx 24rpx rgba(0, 0, 0, 0.06);
}
.goods-img {
width: 344rpx;
height: 344rpx;
display: block;
}
.goods-title {
padding: 14rpx 14rpx 0 14rpx;
font-size: 28rpx;
line-height: 38rpx;
color: #333;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
min-height: 76rpx;
}
.goods-price-row {
padding: 10rpx 14rpx 16rpx 14rpx;
display: flex;
align-items: flex-end;
justify-content: space-between;
}
.goods-desc {
padding: 10rpx 14rpx 20rpx 14rpx;
font-size: 24rpx;
color: #999;
line-height: 1;
}
.price-left {
display: flex;
align-items: flex-end;
}
.price-symbol {
font-size: 26rpx;
color: #C52733;
line-height: 1;
margin-right: 2rpx;
}
.price-val {
font-size: 40rpx;
font-weight: bold;
color: #C52733;
line-height: 1;
}
.origin-price {
font-size: 24rpx;
color: #999;
line-height: 1;
margin-left: 12rpx;
text-decoration: line-through;
}
.cart-btn {
width: 52rpx;
height: 52rpx;
display: block;
}
}
</style>
File diff suppressed because it is too large Load Diff
-10
View File
@@ -151,13 +151,3 @@ export function getBargainUserList(data) {
export function getBargainUserCancel(data) { export function getBargainUserCancel(data) {
return request.post("/bargain/user/cancel", data); return request.post("/bargain/user/cancel", data);
} }
/**
* 新品专区
* @param {*} data
* @returns
*/
export function queryNewZone() {
return request.get("/newGoods");
}
-95
View File
@@ -1,95 +0,0 @@
import request from '@/utils/request'
export function getSseConfigV1(data) {
return request.post('/v1/chat/sse/message', data, { login: true })
}
export function getCompletions(params) {
return request.get('/v1/chat/sse/completions', params, { login: true })
}
export function getCompletionsV2(params) {
return request.get('/v1/chat/sse/completions2', params, { login: true })
}
// 通过关键字-搜索列表
export function getAnalyzeKeywordsV1(data) {
return request.post('/v1/chat/analyzeKeywords', data, { login: true })
}
// 通过关键字-搜索列表-换一换
export function getAnalyzeKeywordsChangeV1(data) {
return request.post('/v1/chat/aiSearch', data, { login: true })
}
export function deleteChatItemByConversationId(id) {
return request.delete('/v1/chat/message/' + id, {}, { login: true })
}
export function getChatList(params) {
return request.get('/v1/chat', params, { login: true })
}
export function historyChatMessage(params) {
return request.get('/v1/chat/message', params, { login: true })
}
export function deleteChatListByType(type) {
return request.delete('/v1/chat/type/' + type, {}, { login: true })
}
export function deleteCountyChatListByType(type, params) {
return request.delete('/county-ai/chat/type/' + type + params, {}, { login: true })
}
export function getWeatherData(params) {
return request.get('/v1/chat/weatherData', params, { login: true })
}
export function getHolidayData(params) {
return request.get('/v1/chat/holidayData', params, { login: true })
}
export function getCompletionsV3(params) {
return request.get('/v1/chat/intent/recognize', params, { login: true })
}
// 通过关键字-搜索列表-换一换
export function getAnalyzeKeywordsChangeV3(data) {
return request.post('/v1/chat/skill/refresh', data, { login: true })
}
// 以图搜索商品
export function getAnalyzeByImageV3(data) {
return request.post('/v1/chat/image/recognition', data, { login: true })
}
// 获取送礼选项配置
export function getGiftRecommendOptions(params) {
return request.get('/ai/gift-recommend/options', params, { login: true })
}
// 获取县域AI详情
export function getCountyAiDetail(params) {
return request.get('/county-ai/detail', params, { login: true })
}
export function getSseCountyAiConfigV1(data) {
return request.post('/county-ai/chat', data, { login: true })
}
export function getCountyAiCompletionsV1(params) {
return request.get('/county-ai/chat/recognize', params, { login: true })
}
export function getCountyAiChatList(params) {
return request.get('/county-ai/chat/list', params, { login: true })
}
export function getCountyAiHistoryChatMessage(params) {
return request.get('/county-ai/chat/message', params, { login: true })
}
export function getGiftRecommendPrompt(data) {
return request.post('/ai/gift-recommend/build-prompt', data, { login: true })
}
-27
View File
@@ -1,27 +0,0 @@
import request from "@/utils/request";
export function getFarmerShop(id) {
return request.get("/countyFamous/farmerShop/" + id)
}
export function setFarmerShopZan(data) {
return request.post("/countyFamous/farmerShop/zan", data)
}
export function getFarmerShopNews(data) {
return request.get("/countyFamous/farmerShop/news", data)
}
export function getFarmerShopQualification(data) {
return request.get("/countyFamous/farmerShop/qualification", data)
}
export function setFarmerShopCollection(data) {
return request.post("/collection/farmerShop/add", data)
}
export function removeFarmerShopCollection(data) {
return request.post("/collection/farmerShop/remove", data)
}
-126
View File
@@ -1,126 +0,0 @@
import request from "@/utils/request";
/**
* 礼品卡送礼订单确认
* @param {*} data
*/
export function getGiftCardSendOrderConfirm(data) {
return request.post("/giftCard/confirm", data);
}
/**
* 礼品卡送礼订单创建
* @param {*} data
*/
export function getGiftCardSendOrder(key, data) {
return request.post("/giftCard/create/" + key, data);
}
/**
* 礼品详情
* @param {*} data
*/
export function getGiftCardDetail(data) {
return request.get("/giftCard/info", data);
}
/**
* 领取礼品卡
* @param {*} data
*/
export function getGiftCardReceive(data) {
return request.post("/giftCard/receive", data);
}
/**
* 礼品卡赠礼须知
* @param {*} data
*/
export function getGiftCardSendNotice(data) {
return request.get("/giftCard/giftNotice", data);
}
/**
* 计算订单金额
* @param {*} data
*/
export function getGiftCardSendOrderAmount(key, data) {
return request.post("giftCard/computed/" + key, data);
}
/**
* 再送一份
* @param {*} data
*/
export function getGiftCardResend(data) {
return request.post("/giftCard/makeAgain", data);
}
/**
* 获取背景图
* @param {*} data
*/
export function getGiftCardSendBackground(data) {
return request.get("giftCard/giftCardBackgroundImage", data);
}
/**
* 创建团购礼品
* @param {*} data
*/
export function createGroupBuyGift(data) {
return request.post("/travel/giftCardOrder/confirm", data);
}
/**
* 旅居团购礼品卡订单创建
* @param {*} data
*/
export function createSojoumGroupBuyGift(key, data) {
return request.post("/travel/giftCardOrder/create/" + key, data);
}
/**
* 旅居团购礼品卡订单详情
* @param {*} params
* @returns
*/
export function fetchSojoumGroupBuyGiftDetail(params) {
return request.get("/travel/giftCard/info",params, {
login: true
})
}
/**
* 领取旅居团购礼品卡
* @param {*} params
* @returns
*/
export function receiveSojoumGroupBuyGift(params) {
return request.post("/travel/giftCard/receive", params, {
login: true
})
}
/**
* 旅居礼品卡送礼入口轮播图
* @param {*} params
* @returns
*/
export function fetchSojoumGroupBuyGiftCarousel(params) {
return request.get("/travel/giftCardTravelBanner",params, {
login: true
})
}
/**
* 计算旅居团购礼品订单价格
* @param {*} params
* @returns
*/
export function computedSojoumGroupBuyGiftOrderPrice(params) {
return request.post("/travel/giftCardOrder/computed/" + params.key, params, {
login: true
})
}
-29
View File
@@ -1,29 +0,0 @@
import request from '@/utils/request'
/**
* 收到的礼品卡列表
* */
export function giftCardReceiveList(param) {
return request.get('/giftCard/receiveList', param)
}
/**
* 送出的礼品卡列表
* */
export function giftCardSendList(param) {
return request.get('/giftCard/sendList', param)
}
/**
* 赠礼须知
* */
export function giftNotice(param) {
return request.get('/giftCard/giftNotice', param)
}
/**
* 退款
*/
export function refund(param) {
return request.post('/giftCard/refund', param)
}
-89
View File
@@ -1,89 +0,0 @@
import request from "@/utils/request";
/**
* 康养生活-养生圣地分类列表
* @returns
*/
export function getCategory() {
return request.get("/wellness/place/category")
}
/**
* 康养生活-养生圣地列表
* @param {*} params
* @returns
*/
export function getWellnessPlace(params) {
return request.get("/wellness/place", params)
}
/**
* 康养生活-展会列表
* @param {*} params
* @returns
*/
export function getWellnessExhibition(params) {
return request.get("/wellness/exhibition", params)
}
/**
* 康养生活-展会详情
* @param {*} id
* @returns
*/
export function getWellnessExhibitionDetails(id) {
return request.get("/wellness/exhibition/" + id)
}
/**
* 康养生活-养生榜单
* @param {*} params
* @returns
*/
export function getRank(params) {
return request.get("/wellness/place/ranking", params)
}
/**
* 康养生活-养生食材列表
* @param {*} params
* @returns
*/
export function getFoods(params) {
return request.get("/wellness/place/food", params)
}
/**
* 康养生活-配方详情
* @param {*} id
* @returns
*/
export function getFoodDetails(id) {
return request.get("/wellness/recipe/" + id)
}
/**
* 康养生活-配方列表
* @param {*} params
* @returns
*/
export function getRecipe(params) {
return request.get("/wellness/recipe", params)
}
/**
* 康养生活-展会轮播图
* @returns
*/
export function getBanner() {
return request.get("/wellness/exhibition/banner")
}
/**
* 康养生活-康养旅居顶部配置
* @returns
*/
export function getWellnessTopImage() {
return request.get("/wellness/topImage")
}
-29
View File
@@ -1,29 +0,0 @@
import request from "@/utils/request";
/**
* 省份非遗数据
* @param {*} id
* @returns
*/
export function getIch(id) {
return request.get("/ich/v2/" + id);
}
/**
* 省份非遗专题数据
* @param {*} id
* @returns
*/
export function getIchContent(id) {
return request.get("/ich/v2/content/" + id);
}
/**
* 获取省份非遗推荐数据
* @param {*} params
* @returns
*/
export function getIchRecommend(params) {
return request.get("/ich/v2/recommend", params);
}
-17
View File
@@ -1,17 +0,0 @@
import request from '@/utils/request'
export function getAction(url, params) {
return request.get(url, params)
}
export function postAction(url, data) {
return request.post(url, data)
}
export function putAction(url, data) {
return request.put(url, data)
}
export function deleteAction(url, data) {
return request.delete(url, data)
}
-55
View File
@@ -191,10 +191,6 @@ export function getHotelTypeList() {
}); });
} }
export function getHotelBanner(params) {
return request.get("/hotelBanner", params);
}
/** /**
* 店铺详情海报 * 店铺详情海报
* @param id 店铺ID int * @param id 店铺ID int
@@ -240,54 +236,3 @@ export function getHotelShareBackgroundImage(id) {
export function hotelNewsView(data) { export function hotelNewsView(data) {
return request.post("/api/hotelNews/view", data, {login: true}) return request.post("/api/hotelNews/view", data, {login: true})
} }
export function getFarmerShop(id) {
return request.get("/api/countyFamous/farmerShop/" + id)
}
export function getAncientTownIcon() {
return request.get("/ancientTown/icon")
}
export function getAncientTownList(params) {
return request.get("/ancientTown", params)
}
export function getAncientTownInfo(id) {
return request.get("/ancientTown/" + id)
}
export function getAncientTownActive(params) {
return request.get("/ancientTown/activity", params)
}
export function watchTownActive(data) {
return request.post("/ancientTown/activity/view", data, {login: true})
}
export function shareTown(id) {
return request.get("/ancientTown/poster/" + id, {login: true})
}
/**
* 获取用户店铺列表
*/
export function getMerchantApply() {
return request.get("/merchantApply/userHotels", {}, {login: true})
}
/**
* 获取用户评论列表
*/
export function getCommentList(params) {
return request.get("/user/reply/list", params, {login: true})
}
/**
* 添加用户评论
*/
export function addComment(data) {
return request.post("/user/reply/add", data, {login: true})
}
+10 -77
View File
@@ -11,8 +11,10 @@ export function getImages() {
} }
// 商户申请页面数据 // 商户申请页面数据
export function getShopData(params) { export function getShopData(partnerId) {
return request.get("/merchantApply/index", params, {login: true}) let param = {};
if (partnerId) param.partnerId = partnerId;
return request.get("/merchantApply/index", param, {login: true})
} }
// 查看商户申请 // 查看商户申请
@@ -27,38 +29,23 @@ export function getWholesaler() {
} }
// 提交店铺入驻申请 // 提交店铺入驻申请
export function saveShop(hotelInfo, partnerId = '', promoterUid = '') { export function saveShop(hotelInfo, captcha, partnerId) {
let param = {hotelInfo, captcha: hotelInfo.captcha}; let param = {hotelInfo, captcha: hotelInfo.captcha};
if (partnerId && partnerId.length > 0) { if (partnerId && partnerId.length > 0) param.partnerId = partnerId;
param.partnerId = partnerId;
}
if (promoterUid && promoterUid.length > 0) {
param.promoterUid = promoterUid;
}
return request.post("/merchantApply/hotel/submit", param, {login: true}) return request.post("/merchantApply/hotel/submit", param, {login: true})
} }
// 提交特产供应商入驻申请 // 提交特产供应商入驻申请
export function saveSupplier(hotelInfo, supplierInfo, partnerId = '', promoterUid = '') { export function saveSupplier(hotelInfo, supplierInfo, partnerId) {
let param = {hotelInfo, supplierInfo, captcha: supplierInfo.captcha}; let param = {hotelInfo, supplierInfo, captcha: supplierInfo.captcha};
if (partnerId && partnerId.length > 0) { if (partnerId && partnerId.length > 0) param.partnerId = partnerId;
param.partnerId = partnerId;
}
if (promoterUid && promoterUid.length > 0) {
param.promoterUid = promoterUid;
}
return request.post("/merchantApply/goodSupplier/submit", param, {login: true}) return request.post("/merchantApply/goodSupplier/submit", param, {login: true})
} }
// 提交文玩供应商入驻申请 // 提交文玩供应商入驻申请
export function saveWenwanSupplier(hotelInfo, supplierInfo, partnerId = '', promoterUid = '') { export function saveWenwanSupplier(hotelInfo, supplierInfo, partnerId) {
let param = {hotelInfo, supplierInfo, captcha: supplierInfo.captcha}; let param = {hotelInfo, supplierInfo, captcha: supplierInfo.captcha};
if (partnerId && partnerId.length > 0) { if (partnerId && partnerId.length > 0) param.partnerId = partnerId;
param.partnerId = partnerId;
}
if (promoterUid && promoterUid.length > 0) {
param.promoterUid = promoterUid;
}
return request.post("/merchantApply/wenwanSupplier/submit", param, {login: true}) return request.post("/merchantApply/wenwanSupplier/submit", param, {login: true})
} }
@@ -68,61 +55,7 @@ export function saveWholesaler(wholesalerInfo) {
return request.post("/merchantApply/wholesaler/submit", param, {login: true}) return request.post("/merchantApply/wholesaler/submit", param, {login: true})
} }
export function saveExperienceStore(params) {
return request.post("/merchantApply/experienceStore/submit", params, {login: true})
}
export function saveExperienceStoreDraft(params) {
return request.post("/merchantApply/experienceStore/saveDraft", params, {login: true})
}
export function getExperienceStoreCategoryList() {
return request.get("/experienceStore/categoryList", {}, {login: true})
}
export function getExperienceStoreInfo(params) {
return request.get("merchantApply/info/experienceStore", params, {login: true})
}
// 撤销入驻申请 // 撤销入驻申请
export function removeApply() { export function removeApply() {
return request.post("/merchantApply/revoke") return request.post("/merchantApply/revoke")
} }
// 特色店铺入驻信息
export function getHotelInfo(params) {
return request.get("merchantApply/info/hotel", params, {login: true})
}
// 获取千县名品店铺类型列表
export function getCountyFamousHotelType(params) {
return request.get("/countyFamous/hotelType", params, {login: true})
}
/**
* 旅居管家入驻申请详情
*/
export function getTravelInfo(params) {
return request.get("merchantApply/info/travel", params, {login: true})
}
/**
* 提交旅居管家入驻申请
*/
export function saveTravel(params) {
return request.post("/merchantApply/travel/submit", params, {login: true})
}
/**
* 旅居管家申请草稿保存
*/
export function saveTravelDraft(params) {
return request.post("/merchantApply/travel/saveDraft", params, {login: true})
}
/**
* 旅居管家撤销申请
*/
export function revokeTravel(params) {
return request.post("/merchantApply/travel/revoke", params, {login: true})
}
+4 -114
View File
@@ -3,77 +3,15 @@ import request from '@/utils/request'
/** /**
* 抽奖活动信息 * 抽奖活动信息
* */ * */
export function getDetail(params = {}) { export function getDetail() {
return request.get('/lottery/dice/detail', params) return request.get('/lottery/dice/detail')
} }
/** /**
* 抽奖 * 抽奖
* */ * */
export function getPrize(data = {}) { export function getPrize() {
return request.post('/lottery/dice/draw', data) return request.post('/lottery/dice/draw')
}
/**
* 县域抽奖活动详情
* @param activityId 抽奖活动ID
*/
export function getDrawActivityInfo(activityId) {
return request.get('/draw/activityInfo', { activityId })
}
/**
* 县域抽奖活动规则
*/
export function getDrawRuleConfig() {
return request.get('/draw/ruleConfig')
}
/**
* 我的抽奖码列表
* @param status 抽奖码状态(0:等待开奖, 1:已中奖, 2:未中奖, -1:已失效)
*/
export function getDrawMyTickets(status) {
const params = {}
if (status !== undefined && status !== null && status !== '') {
params.status = status
}
return request.get('/draw/myTickets', params)
}
/**
* 抽奖活动中奖记录
* @param activityId 抽奖活动ID
*/
export function getActivityWinRecord(activityId) {
return request.get('/draw/activityWinRecord', { activityId })
}
/**
* 获取最新中奖名单
* @param activityId 抽奖活动ID(可选)
*/
export function getDrawLatestWinners(activityId) {
const params = {}
if (activityId !== undefined && activityId !== null && activityId !== '') {
params.activityId = activityId
}
return request.get('/draw/latestWinners', params)
}
/**
* 历史抽奖活动列表
* 用于在中奖名单页面切换历史抽奖活动
*/
export function getDrawHistoryActivities() {
return request.get('/draw/historyActivities')
}
/**
* 获取抽奖相关显示配置
*/
export function getDrawConfig() {
return request.get('/draw/config')
} }
/** /**
@@ -98,51 +36,3 @@ export function getLogs(page = 1, limit = 10) {
export function getLotteryShareInfo() { export function getLotteryShareInfo() {
return request.get('/lottery/shareImage') return request.get('/lottery/shareImage')
} }
/**
* 订单支付完成后检查抽奖码
* @param orderId 订单号
*/
export function getDrawTicketByOrder(orderId) {
return request.get('/draw/ticketCheck', { orderId })
}
/**
* 校验抽奖活动是否到开奖时间
* @param activityId 抽奖活动ID
*/
export function checkDrawTime(activityId) {
return request.get('/draw/checkTime', { activityId })
}
/**
* 领取优惠券奖品
* @param ticketId 抽奖券ID
*/
export function claimCoupon(ticketId) {
return request.post('/draw/claimCoupon', { ticketId })
}
/**
* 领取实物奖品
* @param ticketId 抽奖券ID
* @param addressId 用户收货地址ID
*/
export function claimPrize(ticketId, addressId) {
return request.post('/draw/claimPrize', { ticketId, addressId })
}
/**
* 获取实名认证信息
*/
export function getDrawRealname() {
return request.get('/draw/realname')
}
/**
* 提交实名认证
* @param data { realName, idCard, phone }
*/
export function submitDrawRealname(data = {}) {
return request.post('/draw/realname', data)
}
-46
View File
@@ -3,14 +3,6 @@
* */ * */
import request from "@/utils/request"; import request from "@/utils/request";
/**
* 获取默认地址
* @returns {*}
*/
export function getAddressDefaultSelected() {
return request.get("/address/defaultSelected")
}
/** /**
* 通过购物车 id 获取订单信息 * 通过购物车 id 获取订单信息
* @param cartId * @param cartId
@@ -102,17 +94,6 @@ export function postOrderRefund(data) {
return request.post("/order/refund/verify", data); return request.post("/order/refund/verify", data);
} }
/**
* 取消退款申请
* @param uni
* @returns {*}
*/
export function cancelOrderRefund(uni) {
return request.post("/order/refund/cancel", {
uni
});
}
/** /**
* 确认收货 * 确认收货
* @returns {*} * @returns {*}
@@ -198,30 +179,3 @@ export function aginConfirm(params) {
export function editAddress(params) { export function editAddress(params) {
return request.post('/order/editAddress', params) return request.post('/order/editAddress', params)
} }
/**
* 申请修改订单收货地址
* @param {*} params
* @returns
*/
export function applyEditAddress(params) {
return request.post('/order/applyEditAddress', params)
}
/**
* 订单预计到达时间
* @param {*} params
* @returns
*/
export function orderExpectedArrivalTime(params) {
return request.post('/order/express/estimatedTime', params)
}
/**
* 旅居团购订单详情
* @param {*} params
* @returns
*/
export function groupOrderDetail(params) {
return request.post('/travel/travelGroupOrder/detail/' + params.key, params)
}
-32
View File
@@ -156,35 +156,3 @@ export function hadLike(data) {
export function hadView(data) { export function hadView(data) {
return request.post('/landmarkGoods/news/view', data, {login: false}) return request.post('/landmarkGoods/news/view', data, {login: false})
} }
export function getShareImg(id) {
return request.get('/landmarkGoods/poster/' + id, {}, {login: false})
}
export function getLatestExperienceCoupon() {
return request.get('/experienceCoupon/latest', {}, {login: true})
}
export function getExperienceCouponList() {
return request.get('/experienceCoupon/list', {}, {login: true})
}
export function getExperienceCouponItems(params) {
return request.get('/experienceCoupon/items', params, {login: true})
}
export function getExperienceCouponCategoryList(params) {
return request.get('/experienceCoupon/categoryList', params, {login: true})
}
export function createExperienceCouponOrder(data) {
return request.post('/experienceCoupon/order/create', data, {login: true})
}
export function getExperienceCouponOrderDetail(orderId) {
return request.get(`/experienceCoupon/order/detail/${orderId}`, {}, {login: true})
}
export function checkExperienceCoupon(params) {
return request.get('/experienceCoupon/check', params, {login: true})
}
+1 -26
View File
@@ -9,7 +9,7 @@ export function getSplashScreen() {
* @returns {*} * @returns {*}
*/ */
export function getHomeData(params) { export function getHomeData(params) {
return request.get("/index", params, { return request.get("index", params, {
login: false login: false
}); });
} }
@@ -212,28 +212,3 @@ export function getXiaoZhi() {
export function pushSystemStatic(data) { export function pushSystemStatic(data) {
return request.post("/systemStats/push", data, { login: false }) return request.post("/systemStats/push", data, { login: false })
} }
// 获取AI系统设置
export function getAiSystemInfoSetting() {
return request.get('/ai/systemInfo', {}, { login: false })
}
// 获取AI系统预设话题列表
export function getAiSystemInfoTopic() {
return request.get('/ai/systemTopic', {}, { login: false })
}
// 获取异常提示配置
export function getExceptionConfig() {
return request.get('/ai/exceptionConfig', {}, { login: true })
}
// 获取已启用的底部导航配置列表
export function getBottomNavigationConfigList() {
return request.get('/ai/bottom-navigation/list', {}, { login: true })
}
// 获取通用分享配置
export function getWeixinShareConfig() {
return request.get('/weixinShareConfig', {}, { login: false })
}
-239
View File
@@ -94,242 +94,3 @@ export function getCountyFamousVillageDetail(id) {
export function getCountyFamousVillageNews(param) { export function getCountyFamousVillageNews(param) {
return request.get('/countyFamous/village/news', param, { login: true }) return request.get('/countyFamous/village/news', param, { login: true })
} }
// 获取千县分享图
export function getShareImg(id) {
return request.get('/countyFamous/poster/' + id, {login: true})
}
export function getSaleList(params) {
return request.get('/countyFamous/village/category', params, {login: true})
}
// 旅居列表
// export function getJiaLouList(params) {
// return request.get('/countyFamous/sojourn', params, {login: true})
// }
// 旅居详情
export function getJiaLouDetail1(id) {
return request.get('/countyFamous/sojourn/' + id, {}, {login: true})
}
// 旅居资讯数据
export function getJiaLouNews(params) {
return request.get('/countyFamous/sojourn/news', params, {login: true})
}
// 收藏旅居
export function postJiaLouCollect(data) {
return request.post('/collection/sojourn/add', data, {login: true})
}
// 取消收藏旅居
export function postJiaLouRemoveCollect(data) {
return request.post('/collection/sojourn/remove', data, {login: true})
}
// 收藏旅居列表
export function getJiaLouCollectList(params) {
return request.get('/collection/sojourn/list', params, {login: true})
}
// 旅居点赞
export function postJiaLouZan(data) {
return request.post('/countyFamous/sojourn/zan', data, {login: true})
}
// 旅居资讯查看
export function postJiaLouNewsView(data) {
return request.post('/travel/news/view', data, {login: true})
}
// 旅居资讯点赞
export function postJiaLouNewsZan(data) {
return request.post('/travel/news/zan', data, {login: true})
}
// 分享旅居
export function postJiaLouShare(id) {
return request.get('/countyFamous/sojourn/poster/' + id, {login: true})
}
// 分享旅居1
export function postTravelShare(id) {
return request.get('/travel/poster/' + id, {login: true})
}
/**
* 获取旅居列表
* countyId int 县城ID
shopType string 所属板块(countyFamous-千县;wellness-康养)
wellnessPlaceCateId int 康养圣地分类ID
name string 名称
page int 页码
limit int 每页数量
*/
export function getJiaLouList(params) {
return request.get('/travel/merchantList', params, {login: true})
}
/**
* 获取旅居详情
* @param {*} id
*/
export function getJiaLouDetail(id) {
return request.get('/travel/merchant/' + id, {}, {login: true})
}
/**
* 旅居团购产品列表
merId int 商户ID
page int 页码
limit int 每页数量
*/
export function getJiaLouProductList(params) {
return request.get('/travel/products', params, {login: true})
}
/**
* 旅居团购产品详情
* @param {*} id 产品ID
*/
export function getJiaLouProductDetail(id) {
return request.get('/travel/product/' + id, {}, {login: true})
}
/**
* 旅居团购产品评论列表
* travelGroupProductId int 旅居团购产品ID
* type int 0-全部 1-好评 2-中评 3-差评
* page int 页码
* limit int 每页数量
*/
export function getJiaLouProductReply(params) {
return request.get('/travel/product/reply', params, {login: true})
}
/**
* 获取旅居团购产品评论统计
* travelGroupProductId int 旅居团购产品ID
*/
export function getJiaLouProductReplyCount(params) {
return request.get('/travel/product/reply/count', params, {login: true})
}
export function getTravelGroupOrderAgreement() {
return request.get('/travel/travelGroupOrderAgreement', {}, {login: true})
}
/**
* 管家列表
* merId int 商户ID
page int 页码
limit int 每页数量
*/
export function getJiaLouStewardList(params) {
return request.get('/travel/steward', params, {login: true})
}
/**
* 指定月份可预约日期
* @param {*} params
* travelGroupProductId int 旅居团购产品ID
month string 月份(yyyy-MM
*/
export function getJiaLouCalendar(params) {
return request.get('/travel/product/calendar', params, {login: true})
}
/**
* 获取预定必读
*/
export function getJiaLouBookingRules() {
return request.get('/travel/orderRule', {}, {login: true})
}
/**
* 创建订单
* @param {*} params
* travelGroupProductId int 旅居团购产品ID
orderStartDate string 订单开始日期(yyyy-MM-dd
orderEndDate string 订单结束日期(yyyy-MM-dd
*/
export function createJiaLouOrder(params) {
return request.post('/travel/travelGroupOrder/confirm', params, {login: true})
}
/**
* 旅居团购订单创建
* @param {*} params
*/
export function createJiaLouOrderPay(params) {
return request.post('/travel/travelGroupOrder/create/' + params.key, params, {login: true})
}
/**
* 旅居资讯列表
* merId int 旅居管家商户ID
page int 页码
limit int 每页条数
*/
export function getJiaLouNewsList(params) {
return request.get('/travel/news', params, {login: true})
}
/**
* 分享管家
*/
export function getShareHousekeeper(id) {
return request.get('/travel/steward/poster/' + id, {login: true})
}
/**
* 管家详情
*/
export function getJiaLouStewardDetail(id) {
return request.get('/travel/steward/' + id, {}, {login: true})
}
/**
* 获取县城资讯详情
*/
export function getCityNewsDetail(id) {
return request.get('/countyFamous/news/' + id, {}, {login: true})
}
/**
* 获取县城资讯类别
*/
export function getCityNewsCategory() {
return request.get('/countyFamous/newsCategory', {}, {login: true})
}
/**
* 获取县城店铺列表
*/
export function getCityShopList(params) {
return request.get('/countyFamous/hotel', params, {login: true})
}
export function getCountyFamousHotelType(params) {
return request.get('/countyFamous/hotelType', params, {login: true})
}
/**
* б
* travelMerchantId int þ̻ID
* experienceStoreCategoryId int ID
*/
export function getExperienceStoreList(params) {
return request.get('/experienceStore/list', params, { login: true })
}
export function getExperienceStoreProject(experienceMerchantId) {
return request.get('/experienceStoreProject/' + experienceMerchantId, {}, { login: true })
}
export function getExperienceStoreDetail(id) {
return request.get('/experienceStore/detail/' + id, {}, { login: true })
}
-29
View File
@@ -1,29 +0,0 @@
import request from "@/utils/request";
/**
* 获取未读消息数量
*/
export function getUnreadMessageCount() {
return request.get("/user/reply/messages/unreadCount", {}, {login: true})
}
/**
* 标记消息为已读
*/
export function markMessagesAsRead() {
return request.post("/user/reply/messages/readAll", {}, {login: true})
}
/**
* 获取消息列表
*/
export function getMessageList(params) {
return request.get("/user/reply/messages", params, {login: true})
}
/**
* 回复消息
*/
export function replyMessage(data) {
return request.post("/user/reply/add", data, {login: true})
}
-6
View File
@@ -1,6 +0,0 @@
import request from '@/utils/request'
// 文玩店铺列表
export function getSearchPageConfig() {
return request.get('/searchPage', {}, { login: false })
}
-74
View File
@@ -1,74 +0,0 @@
import request from "@/utils/request";
/**
* 旅居团购订单详情
* @param {*} params
* @returns
*/
export function fetchSojoumOrderDetail(params) {
return request.get("/travel/travelGroupOrder/detail/" + params.key, params, {
login: true
})
}
/**
* 旅居团购订单退款
* @param {*} params
* @returns
*/
export function sojoumOrderRefund(params) {
return request.post("/travel/travelGroupOrder/refund", params, {
login: true
})
}
/**
* 旅居团购订单修改入住时间
* @param {*} params
* @returns
*/
export function sojoumOrderCheckInTime(params) {
return request.post("/travel/travelGroupOrder/changeDate", params, {
login: true
})
}
/**
* 获取产品指定月份的预约日历
* @param {*} params
* travelGroupProductId int 旅居团购产品ID
month string 月份(yyyy-MM
* @returns
*/
export function sojoumOrderCalendar(params) {
return request.get("/travel/product/calendar", params, {
login: true
})
}
/**
* 旅居团购订单退款信息
* @param {*} params
* @returns
*/
export function sojoumOrderRefundInfo(params) {
return request.post("/travel/travelGroupOrder/refundInfo", params, {
login: true
})
}
/**
* 旅居团购订单检查日期是否可预约
* @param {*} params
* @returns
*/
export function sojoumOrderCheckDate(params) {
return request.post("/travel/travelGroupOrder/checkDate", params, {
login: true
})
}
export function sojoumOrderComment(params) {
return request.post("/travel/travelGroupOrder/comment", params, {
login: true
})
}
-17
View File
@@ -578,10 +578,6 @@ export function getHistory(params) {
return request.get('/history/list', params) return request.get('/history/list', params)
} }
export function deleteHistory(id) {
return request.delete(`/history/${id}`)
}
/** /**
* 购物车猜你喜欢 * 购物车猜你喜欢
* @param {*} params * @param {*} params
@@ -590,16 +586,3 @@ export function deleteHistory(id) {
export function getUserLike(params) { export function getUserLike(params) {
return request.get('/cart/guessYouLike',params) return request.get('/cart/guessYouLike',params)
} }
/**
* 用户功能指引状态
* @param {*} params
* @returns
*/
export function queryUserGuide(params) {
return request.get('/user/guide/status', params)
}
export function setUserGuide(params) {
return request.post('/user/guide/status', params)
}
-9
View File
@@ -1,9 +0,0 @@
import request from '@/utils/request'
export function makeFileTransTask(data) {
return request.post('/app/voiceToText/makeFileTransTask', data, { login: true })
}
export function getFileTransResult(data) {
return request.post('/app/voiceToText/getFileTransResult', data, { login: true })
}
File diff suppressed because it is too large Load Diff
-4
View File
@@ -296,7 +296,3 @@ checkbox .wx-checkbox-input.wx-checkbox-input-checked {
font-size: 28rpx; font-size: 28rpx;
color: #C2C5CC; color: #C2C5CC;
} }
.bg-color-hui {
background-color: #999 !important;
}
+5 -4
View File
@@ -17,15 +17,16 @@
} }
.search-box { .search-box {
width: 90%; width: 686rpx;
height: 60rpx; height: 60rpx;
margin: 0 auto;
padding: 0 24rpx 0 32rpx; padding: 0 24rpx 0 32rpx;
box-sizing: border-box; box-sizing: border-box;
background: #F7F7F7; background: #F7F7F7;
border-radius: 30rpx; border-radius: 30rpx;
input { input {
width: 540rpx; width: 560rpx;
font-size: 24rpx; font-size: 24rpx;
} }
@@ -65,8 +66,8 @@
} }
.active { .active {
border-left: 6rpx solid #C52733; border-left: 6rpx solid #FD574B;
color: #C52733; color: #FD574B;
font-weight: bold; font-weight: bold;
} }
} }
-6
View File
@@ -37,12 +37,6 @@ input{line-height: normal; box-sizing:border-box;}
.line1{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width: 100%;} .line1{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width: 100%;}
.line2{word-break:break-all;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;} .line2{word-break:break-all;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.mask{position:fixed;top:0;left:0;right:0;bottom:0;z-index:55;background-color:rgba(0,0,0,0.5);} .mask{position:fixed;top:0;left:0;right:0;bottom:0;z-index:55;background-color:rgba(0,0,0,0.5);}
.ai-product-window.product-window {
z-index: 1002;
}
.ai-product-window.mask {
z-index: 1001;
}
+6 -3
View File
@@ -9,9 +9,10 @@
} }
.box-share { .box-share {
width: 600rpx;
.box-img { .box-img {
position: relative; position: relative;
width: 500rpx;
height: 632rpx;
border-radius: 40rpx; border-radius: 40rpx;
overflow: hidden; overflow: hidden;
} }
@@ -25,12 +26,14 @@
} }
.main-img { .main-img {
width: 100%; width: 500rpx;
height: 632rpx;
border-radius: 40rpx; border-radius: 40rpx;
} }
.btn { .btn {
width: 100%; width: 500rpx;
height: 100rpx;
margin-top: 20rpx; margin-top: 20rpx;
} }
} }
-189
View File
@@ -8231,192 +8231,3 @@ rich-text {
font-size: 28rpx; font-size: 28rpx;
} }
} }
.draw-ticket-mask {
position: fixed;
inset: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.45);
display: flex;
align-items: center;
justify-content: center;
padding: 24rpx;
box-sizing: border-box;
}
.draw-ticket-popup {
width: 100%;
max-width: 640rpx;
background: #fff;
border-radius: 40rpx;
padding: 50rpx 40rpx 60rpx;
position: relative;
box-sizing: border-box;
.draw-ticket-close {
position: absolute;
top: 30rpx;
right: 30rpx;
width: 40rpx;
height: 40rpx;
border: 4rpx solid #333;
border-radius: 50%;
color: #333;
text-align: center;
font-weight: bold;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
line-height: 40rpx;
}
.draw-ticket-icon {
display: flex;
justify-content: center;
margin-top: 20rpx;
}
.ticket-icon-box {
width: 100rpx;
height: 70rpx;
border-radius: 10rpx;
position: relative;
box-sizing: border-box;
}
.ticket-icon-check {
width: 100%;
height: 100%;
}
.draw-ticket-title {
font-size: 56rpx;
color: #222;
font-weight: 800;
text-align: center;
margin-top: 24rpx;
letter-spacing: 2rpx;
}
.ticket-card-container {
margin-top: 50rpx;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.ticket-badge {
background-color: #fff9eb;
border: 6rpx solid #111;
border-radius: 40rpx;
padding: 12rpx 40rpx;
font-size: 46rpx;
font-weight: 800;
color: #222;
position: relative;
z-index: 2;
margin-bottom: -36rpx;
letter-spacing: 2rpx;
}
.ticket-badge-arrow {
position: absolute;
bottom: -22rpx;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 22rpx solid transparent;
border-right: 22rpx solid transparent;
border-top: 22rpx solid #111;
&::after {
content: '';
position: absolute;
top: -26rpx;
left: -16rpx;
border-left: 16rpx solid transparent;
border-right: 16rpx solid transparent;
border-top: 16rpx solid #fff9eb;
}
}
.ticket-card {
width: 100%;
background: #c23326;
border-radius: 36rpx;
padding: 70rpx 36rpx 40rpx;
box-sizing: border-box;
text-align: center;
position: relative;
}
.ticket-card-subtitle {
display: flex;
justify-content: center;
}
.ticket-card-subtitle-text {
color: #fff;
font-size: 34rpx;
font-weight: 700;
border: 2rpx solid #fff;
border-radius: 40rpx;
padding: 8rpx 50rpx;
letter-spacing: 4rpx;
}
.ticket-card-code-box {
background: #fff;
border-radius: 20rpx;
margin-top: 36rpx;
padding: 36rpx 0;
}
.ticket-card-code {
color: #c23326;
font-size: 72rpx;
font-weight: 800;
letter-spacing: 8rpx;
}
.ticket-card-time {
color: #fff;
font-size: 30rpx;
margin-top: 36rpx;
text-align: left;
}
.draw-ticket-actions {
margin-top: 60rpx;
display: flex;
justify-content: space-between;
align-items: center;
gap: 20rpx;
.action-btn {
flex: 1;
height: 86rpx;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
white-space: nowrap;
&.home-btn {
color: #c23326;
border: 2rpx solid #c23326;
background: #fff;
}
&.primary {
color: #fff;
background: #c23326;
}
}
}
}
+3 -8
View File
@@ -3,8 +3,8 @@
@dark-color: #333333; @dark-color: #333333;
@white-color: #fff; @white-color: #fff;
@colors: #C52733, #333333, #fff, #666, #F0F0F0, #999999, #E92727, #FFC543, #69C573, #A5A5A5; @colors: #C52733, #333333, #fff, #666, #F0F0F0, #999999, #E92727, #FFC543;
@classnames: primary, dark, white, secondary-dark, grey, dark1, red, yellow, success, dark2; @classnames: primary, dark, white, secondary-dark, grey, dark1, red, yellow;
/*=====================================*/ /*=====================================*/
each(@colors, { each(@colors, {
@@ -169,9 +169,7 @@ each(@colors, {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} }
.v12-gap-10{
grid-gap: 20rpx 20rpx;
}
.v12-text-right{ .v12-text-right{
text-align: right; text-align: right;
@@ -194,9 +192,6 @@ each(@colors, {
.v12-full-width{ .v12-full-width{
width: 100%; width: 100%;
} }
.v12-nowrap{
white-space: nowrap
}
+57
View File
@@ -0,0 +1,57 @@
<template>
<view class="components-checkbox-icon jc-center ai-center" :class="{'isSelected':isSelected}" @click="change"
v-if="ready">
<image class="icon-hook" :src="webUrl+'/20240109175325131970.png'" mode="scaleToFill" v-if="isSelected"/>
</view>
</template>
<script setup>
import {computed, getCurrentInstance, onMounted, ref} from '@vue/composition-api'
import {VUE_APP_RESOURCES_URL} from '../config/index'
const webUrl = VUE_APP_RESOURCES_URL
const emit = defineEmits(['change'])
const {proxy} = getCurrentInstance()
const props = defineProps({
defaultState: {
type: Boolean,
default: false
},
mark: Array
})
const ready = ref(false)
onMounted(() => {
ready.value = true
})
const isSelected = computed(() => {
return props.defaultState
})
const change = () => {
emit('change', !isSelected.value, props.mark)
}
</script>
<style scoped lang="less">
.components-checkbox-icon {
display: inline-flex;
width: 32rpx;
height: 32rpx;
box-sizing: border-box;
border: 2rpx solid #D5D7D8;
border-radius: 50%;
}
.icon-hook {
width: 24rpx;
height: 24rpx;
}
.isSelected {
border: 3px solid #FD5749;
background: #FD5749;
}
</style>
+2 -3
View File
@@ -87,7 +87,7 @@ export default {
components: { components: {
uniPopup uniPopup
}, },
props: ["callback", "items", "defaultValue", 'disabled'], props: ["callback", "items", "defaultValue"],
data() { data() {
return { return {
value: "请选择", value: "请选择",
@@ -107,7 +107,7 @@ export default {
}, },
defaultValue(newValue) { defaultValue(newValue) {
this.value = newValue; this.value = newValue;
this.adjustDefaultValue(); // this.adjustDefaultValue();
} }
}, },
mounted() { mounted() {
@@ -147,7 +147,6 @@ export default {
return idx; return idx;
}, },
open() { open() {
if(this.disabled) return;
if (this.$refs.popup.showPopup) { if (this.$refs.popup.showPopup) {
this.$refs.popup.close(); this.$refs.popup.close();
return; return;
+1 -5
View File
@@ -6,7 +6,7 @@
class="coupons__cover" class="coupons__cover"
mode="widthFix" mode="widthFix"
/> />
<view @click="selectCoupon" class="check-radio" :class="{'v12-primary': data.checked}" v-if="showRadio"> <view @click="selectCoupon" class="check-radio" :class="{'v12-primary': data.checked}">
<radio <radio
v-if="radioModel && data.status === 0" v-if="radioModel && data.status === 0"
:value="data.id" :value="data.id"
@@ -50,10 +50,6 @@
export default { export default {
name: "Coupons", name: "Coupons",
props: { props: {
showRadio: {
type: Boolean,
default: true
},
data: { data: {
type: Object, type: Object,
default: () => { default: () => {
+9 -67
View File
@@ -1,11 +1,7 @@
<template> <template>
<view class="popup-coupons"> <view class="popup-coupons">
<view class="popup-box"> <view class="popup-box">
<view class="popup-title bold tc v12-justify-between"> <view class="popup-title bold tc">优惠详情</view>
<text></text>
<text>优惠详情</text>
<u-icon name="close" color="#666" size="14" @click.stop="close"></u-icon>
</view>
<SubSection <SubSection
:current="current" :current="current"
:can-use="canUse" :can-use="canUse"
@@ -14,8 +10,7 @@
@change="changeNav" @change="changeNav"
v-if="showTab" v-if="showTab"
/> />
<!-- 先隐藏 --> <view class="v12-radius-20 v12-white v12-align-center v12-justify-around v12-pa-3" v-else>
<!-- <view class="v12-radius-20 v12-white v12-justify-around v12-pa-3" style="align-items: flex-end;" v-if="!showTab && showRadio">
<view class=""> <view class="">
<view class="v12-text-center v12-font-28"> <view class="v12-text-center v12-font-28">
券后价 券后价
@@ -30,10 +25,7 @@
</view> </view>
</view> </view>
<view class="v12-text-center v12-font-44"> <view class="v12-text-center v12-font-44">
<view class="v12-text-center v12-font-28"> =
&nbsp;
</view>
<view class="v12-mt-3 v12-text-center">=</view>
</view> </view>
<view class=""> <view class="">
<view class="v12-text-center v12-font-28"> <view class="v12-text-center v12-font-28">
@@ -49,10 +41,7 @@
</view> </view>
</view> </view>
<view class="v12-text-center v12-font-44"> <view class="v12-text-center v12-font-44">
<view class="v12-text-center v12-font-28"> -
&nbsp;
</view>
<view class="v12-mt-3 v12-text-center">-</view>
</view> </view>
<view class=""> <view class="">
<view class="v12-text-center"> <view class="v12-text-center">
@@ -62,13 +51,12 @@
{{ selectItem.couponPrice || 0 }} {{ selectItem.couponPrice || 0 }}
</view> </view>
</view> </view>
</view> --> </view>
<view class="list-box"> <view class="list-box">
<view class="larg-one v12-mb-3"> <view class="larg-one v12-mb-3">
<Coupons <Coupons
:data="largOne" :data="largOne"
:showRadio="showRadio"
:radio-model="current === 0" :radio-model="current === 0"
@change="selectCoupon" @change="selectCoupon"
/> />
@@ -83,14 +71,10 @@
> >
<Coupons <Coupons
:data="item" :data="item"
:showRadio="showRadio"
:radio-model="current === 0" :radio-model="current === 0"
@change="selectCoupon" @change="selectCoupon"
v-if="index !== maxIndex" v-if="index !== maxIndex"
/> />
<view v-if="list.length === 1" class="no-quan v12-font-28 v12-dark1-text text-center">
暂无更多可使用优惠券快去抽奖去吧~
</view>
</view> </view>
<view <view
v-if="list.length === 0" v-if="list.length === 0"
@@ -102,7 +86,7 @@
</view> </view>
<button disabled></button> <button disabled></button>
<view <view
v-if="current === 0 && showRadio" v-if="current === 0"
:class="{ 'btn-disabled': current === 1 }" :class="{ 'btn-disabled': current === 1 }"
class="btn-done bold flex jc-center ai-center v12-primary" class="btn-done bold flex jc-center ai-center v12-primary"
@click="setCoupon" @click="setCoupon"
@@ -120,10 +104,6 @@ export default {
name: 'CouponsPopup', name: 'CouponsPopup',
components: { SubSection, Coupons }, components: { SubSection, Coupons },
props: { props: {
showRadio: {
type: Boolean,
default: true
},
twoList: { twoList: {
type: Object, type: Object,
default: { default: {
@@ -138,14 +118,6 @@ export default {
currentPrice: { currentPrice: {
default: 0, default: 0,
type: Number type: Number
},
id: {
type: Number,
default: 0
},
couponId1: {
type: Number,
default: 0
} }
}, },
data() { data() {
@@ -158,23 +130,11 @@ export default {
}, },
} }
}, },
watch: {
couponId1: {
immediate: true,
handler(value) {
console.log(value);
if(value) {
this.selectCoupon(value)
}
}
}
},
computed: { computed: {
list() { list() {
const temp = this.current === 0 ? this.twoList['usable'] : this.twoList['unusable'] const temp = this.current === 0 ? this.twoList['usable'] : this.twoList['unusable']
if (this.current === 0) { if (this.current === 0) {
const localCouponId = this.couponId1 || 0 const localCouponId = uni.getStorageSync('couponId') || 0
temp.map(item => { temp.map(item => {
item.checked = localCouponId === item.id item.checked = localCouponId === item.id
}) })
@@ -198,8 +158,8 @@ export default {
}, },
largOne() { largOne() {
if(this.list[this.maxIndex]) { if(this.list[this.maxIndex]) {
// this.selectCoupon(this.list[this.maxIndex].id) this.selectCoupon(this.list[this.maxIndex].id)
// uni.setStorageSync('couponId', this.list[this.maxIndex].id) uni.setStorageSync('couponId', this.list[this.maxIndex].id)
} }
// this.$emit('max', this.list[this.maxIndex] || {}) // this.$emit('max', this.list[this.maxIndex] || {})
return this.list[this.maxIndex] || {} return this.list[this.maxIndex] || {}
@@ -210,19 +170,6 @@ export default {
this.$emit('max', this.largOne) this.$emit('max', this.largOne)
}, },
methods: { methods: {
close() {
this.couponId = this.couponId1
this.selectItem = this.list.find(e => e.id === this.couponId1) || {}
// this.$emit('select', this.selectItem)
this.list.map(item => {
item.checked = this.couponId1 === item.id
})
this.$emit('close')
// uni.setStorageSync('couponId', this.couponId)
// this.$emit('change', this.selectItem || {})
// this.$emit('ok', this.couponId)
},
force2Decimal(value) { force2Decimal(value) {
return this.$force2Decimal(value); return this.$force2Decimal(value);
}, },
@@ -232,7 +179,6 @@ export default {
selectCoupon(id) { selectCoupon(id) {
this.couponId = id this.couponId = id
this.selectItem = this.list.find(e => e.id === id) || {} this.selectItem = this.list.find(e => e.id === id) || {}
// this.$emit('select', this.selectItem)
this.list.map(item => { this.list.map(item => {
item.checked = id === item.id item.checked = id === item.id
}) })
@@ -241,16 +187,12 @@ export default {
if (this.current === 1) return if (this.current === 1) return
uni.setStorageSync('couponId', this.couponId) uni.setStorageSync('couponId', this.couponId)
this.$emit('change', this.selectItem || {}) this.$emit('change', this.selectItem || {})
this.$emit('ok', this.couponId)
} }
} }
} }
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.text-center{
text-align: center;
}
.popup-coupons { .popup-coupons {
background: #F0F0F0; background: #F0F0F0;
.popup-box { .popup-box {
@@ -1,813 +0,0 @@
<template>
<view class="date-range-picker">
<u-popup :show="show" @close="handleClose" mode="center" round="16" closeable>
<view class="picker-container">
<view class="picker-header">
<text class="title">查看可预约日期</text>
</view>
<view class="v12-align-center v12-justify-between">
<view class="v12-my-3">
<text class="v12-font-24 v12-dark-text v12-mr-3">请选择入住日期</text>
<text class="v12-font-24 v12-primary-text">{{ ` 共计${minBookingDays}` }}</text>
</view>
<view v-if="originDate" class="v12-font-24 v12-primary-text">
原定时间{{ originDate }}
</view>
</view>
<view class="calendar" @touchstart="onTouchStart" @touchend="onTouchEnd">
<view class="calendar-header">
<view class="month-nav">
<text class="nav-btn" @click="changeMonth(-1)"></text>
<text class="month-text">{{ currentYear }}{{ currentMonth + 1 }}</text>
<text class="nav-btn" @click="changeMonth(1)"></text>
</view>
<view class="weekdays">
<text v-for="day in ['日', '一', '二', '三', '四', '五', '六']" :key="day" class="weekday v12-dark-text">
{{ day }}
</text>
</view>
</view>
<view class="calendar-body">
<view class="days" :class="[isAnimating ? 'absolute ' + transitionMode + '-enter' : '']">
<view
v-for="(day, index) in calendarDays"
:key="index"
class="day"
:class="{
'empty': !day,
'selected': isSelected(day),
'in-range': isInRange(day),
'start-date': isStartDate(day),
'end-date': isEndDate(day),
'selecting-start': isSelectingStart(day),
'disabled': isDisabled(day),
'booked': getDateStatus(day) === '已被预约',
'unavailable': getDateStatus(day) === '不可预约',
'available': getDateStatus(day) === '可预约'
}"
@click="selectDate(day)"
>
<text>{{ day || '' }}</text>
<view class="v12-font-20" v-if="day && getDateStatus(day) !== null">{{ getDateStatus(day) }}</view>
</view>
</view>
<view class="days absolute" v-if="isAnimating" :class="[transitionMode + '-leave']">
<view
v-for="(day, index) in prevMonthDays"
:key="'prev-' + index"
class="day"
:class="{
'empty': !day,
'selected': isSelected(day, prevYear, prevMonth),
'in-range': isInRange(day, prevYear, prevMonth),
'start-date': isStartDate(day, prevYear, prevMonth),
'end-date': isEndDate(day, prevYear, prevMonth),
'selecting-start': isSelectingStart(day, prevYear, prevMonth),
'disabled': isDisabled(day, prevYear, prevMonth),
'booked': getDateStatus(day, prevYear, prevMonth) === '已被预约',
'unavailable': getDateStatus(day, prevYear, prevMonth) === '不可预约',
'available': getDateStatus(day, prevYear, prevMonth) === '可预约'
}"
>
<text>{{ day || '' }}</text>
<view class="v12-font-20" v-if="day && getDateStatus(day, prevYear, prevMonth) !== null">{{ getDateStatus(day, prevYear, prevMonth) }}</view>
</view>
</view>
</view>
</view>
<view class="picker-footer">
<button class="btn btn-confirm" @click="confirmSelect">立即预订</button>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import { sojoumOrderCalendar, sojoumOrderCheckDate } from "@/api/sojoumOrder";
export default {
name: 'DateRangePicker',
props: {
originDate: {
type: String,
default: ''
},
show: {
type: Boolean,
default: false
},
value: {
type: Array,
default: () => [null, null]
},
minDate: {
type: [String, Date],
default: null
},
maxDate: {
type: [String, Date],
default: null
},
format: {
type: String,
default: 'YYYY-MM-DD'
},
travelGroupProductId: {
type: String,
default: ''
},
minBookingDays: {
type: Number,
default: 0
},
},
data() {
return {
currentYear: new Date().getFullYear(),
currentMonth: new Date().getMonth(),
startDate: null,
endDate: null,
activeCalendar: 'start', // 'start' or 'end'
tempStartDate: null,
tempEndDate: null,
dateStatusMap: {}, // 存储日期状态
selectionState: 'initial', // 'initial' | 'selecting' | 'completed'
touchStartX: 0,
touchStartY: 0,
// 动画相关状态
isAnimating: false,
transitionMode: '', // 'next' or 'prev'
prevYear: null,
prevMonth: null,
prevMonthDays: []
}
},
computed: {
calendarDays() {
const days = []
const firstDay = new Date(this.currentYear, this.currentMonth, 1)
const lastDay = new Date(this.currentYear, this.currentMonth + 1, 0)
// 填充月初空白天数
for (let i = 0; i < firstDay.getDay(); i++) {
days.push(null)
}
// 填充当月天数
for (let i = 1; i <= lastDay.getDate(); i++) {
days.push(i)
}
// 填充月末空白天数
const remainingDays = 42 - days.length // 保持6行固定高度
for (let i = 0; i < remainingDays; i++) {
days.push(null)
}
return days
}
},
watch: {
show(newVal) {
if (newVal) {
this.initDates()
this.getDays()
}
},
currentMonth() {
this.getDays()
},
currentYear() {
this.getDays()
},
value: {
handler(newVal) {
if (newVal && newVal.length === 2) {
this.startDate = newVal[0] ? new Date(newVal[0]) : null
this.endDate = newVal[1] ? new Date(newVal[1]) : null
this.tempStartDate = this.startDate
this.tempEndDate = this.endDate
}
},
immediate: true
}
},
methods: {
getDays(){
// uni.showLoading({
// title: '加载中...',
// mask: true,
// })
sojoumOrderCalendar({
travelGroupProductId: this.travelGroupProductId,
month: `${this.currentYear}-${String(this.currentMonth + 1).padStart(2, '0')}`
}).then(res => {
if (res.data) {
// 更新日期状态映射,使用合并而不是覆盖,以支持动画时的旧数据显示
const newStatusMap = {}
res.data.forEach(day => {
// inventoryStatus int 状态 (0:可预约, 1:已被预约, 2:不可预约)
newStatusMap[day.date] = day.inventoryStatus === 0 ? '可预约' : day.inventoryStatus === 1 ? '已被预约' : '不可预约'
})
this.dateStatusMap = { ...this.dateStatusMap, ...newStatusMap }
}
}).finally(() => {
uni.hideLoading()
})
},
getDateStatus(day, year, month) {
if (!day) return null
const date = this.formatDate(this.getDateFromDay(day, year, month))
return this.dateStatusMap[date]
},
isDisabled(day, year, month) {
if (!day) return true
const date = this.getDateFromDay(day, year, month)
// 禁用过去的日期(今天之前的日期)
const today = new Date()
today.setHours(0, 0, 0, 0)
if (date < today) return true
// 检查最小和最大日期限制
if (this.minDate && date < new Date(this.minDate)) return true
if (this.maxDate && date > new Date(this.maxDate)) return true
// 检查预约状态
const status = this.getDateStatus(day, year, month)
// 只允许选择可预约的日期(状态为"可预约"),其他状态都禁用
return status !== '可预约'
},
initDates() {
this.tempStartDate = this.startDate
this.tempEndDate = this.endDate
// 根据当前选择状态设置selectionState
if (this.tempStartDate && this.tempEndDate) {
this.selectionState = 'completed'
this.activeCalendar = 'start'
} else if (this.tempStartDate) {
this.selectionState = 'selecting'
this.activeCalendar = 'end'
} else {
this.selectionState = 'initial'
this.activeCalendar = 'start'
}
if (this.startDate) {
this.currentYear = this.startDate.getFullYear()
this.currentMonth = this.startDate.getMonth()
} else {
const now = new Date()
this.currentYear = now.getFullYear()
this.currentMonth = now.getMonth()
}
},
changeMonth(delta) {
if (this.isAnimating) return
// Setup animation state
this.prevYear = this.currentYear
this.prevMonth = this.currentMonth
this.prevMonthDays = [...this.calendarDays]
this.transitionMode = delta > 0 ? 'next' : 'prev'
this.isAnimating = true
let newMonth = this.currentMonth + delta
if (newMonth < 0) {
this.currentYear--
newMonth = 11
} else if (newMonth > 11) {
this.currentYear++
newMonth = 0
}
this.currentMonth = newMonth
// Reset animation state after transition
setTimeout(() => {
this.isAnimating = false
this.prevMonthDays = []
}, 300)
},
onTouchStart(e) {
if (!e || !e.changedTouches || !e.changedTouches.length) return
this.touchStartX = e.changedTouches[0].clientX
this.touchStartY = e.changedTouches[0].clientY
},
onTouchEnd(e) {
if (!e || !e.changedTouches || !e.changedTouches.length) return
const touchEndX = e.changedTouches[0].clientX
const touchEndY = e.changedTouches[0].clientY
const deltaX = touchEndX - this.touchStartX
const deltaY = touchEndY - this.touchStartY
if (Math.abs(deltaX) <= Math.abs(deltaY)) return
const minDistance = 50
if (Math.abs(deltaX) < minDistance) return
if (deltaX < 0) {
this.changeMonth(1)
} else {
this.changeMonth(-1)
}
},
formatDate(date) {
if (!date) return ''
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
getDateFromDay(day, year, month) {
const y = year !== undefined ? year : this.currentYear
const m = month !== undefined ? month : this.currentMonth
return day ? new Date(y, m, day) : null
},
// isDisabled(day) {
// if (!day) return true
// const date = this.getDateFromDay(day)
// // 禁用过去的日期(今天之前的日期)
// const today = new Date()
// today.setHours(0, 0, 0, 0)
// if (date < today) return true
// // 检查最小和最大日期限制
// if (this.minDate && date < new Date(this.minDate)) return true
// if (this.maxDate && date > new Date(this.maxDate)) return true
// return false
// },
isSelected(day, year, month) {
if (!day) return false
// const date = this.getDateFromDay(day, year, month) // Unused?
return this.isStartDate(day, year, month) || this.isEndDate(day, year, month)
},
isStartDate(day, year, month) {
if (!day || !this.tempStartDate) return false
const date = this.getDateFromDay(day, year, month)
return date.getTime() === this.tempStartDate.getTime()
},
isEndDate(day, year, month) {
if (!day || !this.tempEndDate) return false
const date = this.getDateFromDay(day, year, month)
return date.getTime() === this.tempEndDate.getTime()
},
isInRange(day, year, month) {
if (!day || !this.tempStartDate || !this.tempEndDate) return false
const date = this.getDateFromDay(day, year, month)
return date > this.tempStartDate && date < this.tempEndDate
},
isSelectingStart(day, year, month) {
if (!day || !this.tempStartDate || this.tempEndDate) return false
// 只有在选择状态且只有开始日期时才显示特殊样式
if (this.selectionState !== 'selecting') return false
const date = this.getDateFromDay(day, year, month)
return date.getTime() === this.tempStartDate.getTime()
},
selectDate(day, year, month) {
if (!day || this.isDisabled(day, year, month)) return
const selectedDate = this.getDateFromDay(day, year, month)
// 如果设置了最小预订天数,则自动计算结束日期
if (this.minBookingDays > 0) {
this.tempStartDate = selectedDate
const endDate = new Date(selectedDate)
endDate.setDate(selectedDate.getDate() + this.minBookingDays - 1)
this.tempEndDate = endDate
this.selectionState = 'completed'
return
}
// 如果已有完整的日期区间(开始日期和结束日期都存在),重置选择
if (this.tempStartDate && this.tempEndDate && this.selectionState === 'completed') {
// 重置选择状态,将点击的日期作为新的开始日期
this.tempStartDate = selectedDate
this.tempEndDate = null
this.activeCalendar = 'end'
this.selectionState = 'selecting'
return
}
// 如果点击已选择的开始日期,则取消选择
if (this.tempStartDate && selectedDate.getTime() === this.tempStartDate.getTime()) {
this.tempStartDate = null
this.tempEndDate = null
this.activeCalendar = 'start'
this.selectionState = 'initial'
return
}
// 如果点击已选择的结束日期,则只清除结束日期
if (this.tempEndDate && selectedDate.getTime() === this.tempEndDate.getTime()) {
this.tempEndDate = null
this.activeCalendar = 'end'
this.selectionState = 'selecting'
return
}
if (this.activeCalendar === 'start' || this.selectionState === 'initial') {
// 选择开始日期
this.tempStartDate = selectedDate
this.tempEndDate = null
this.activeCalendar = 'end'
this.selectionState = 'selecting'
} else if (this.activeCalendar === 'end') {
if (selectedDate < this.tempStartDate) {
// 如果选择的结束日期小于开始日期,将其设为开始日期
this.tempStartDate = selectedDate
this.tempEndDate = null
this.selectionState = 'selecting'
} else {
// 设置结束日期,完成选择
this.tempEndDate = selectedDate
this.selectionState = 'completed'
}
}
},
clearDates() {
this.tempStartDate = null
this.tempEndDate = null
this.activeCalendar = 'start'
this.selectionState = 'initial'
},
confirmSelect() {
// 验证选择的日期数量
if (!this.tempStartDate || !this.tempEndDate) {
uni.showToast({
title: '请选择起始和结束日期',
icon: 'none'
})
return
}
// 计算选择的天数
const daysDiff = Math.floor((this.tempEndDate - this.tempStartDate) / (1000 * 60 * 60 * 24)) + 1
// 必须要选够天数
if (daysDiff !== this.minBookingDays) {
uni.showToast({
title: `此套餐预约需连续选择${this.minBookingDays}`,
icon: 'none'
})
return
}
// 验证选择的日期范围内是否包含禁用日期
// const currentDate = new Date(this.tempStartDate)
// while (currentDate <= this.tempEndDate) {
// const day = currentDate.getDate()
// if (this.isDisabled(day)) {
// uni.showToast({
// title: '所选日期范围包含不可预约日期,请重新选择',
// icon: 'none'
// })
// return
// }
// currentDate.setDate(currentDate.getDate() + 1)
// }
sojoumOrderCheckDate({
travelGroupProductId: this.travelGroupProductId,
orderStartDate: this.formatDate(this.tempStartDate),
orderEndDate: this.formatDate(this.tempEndDate)
}).then(res => {
if (res.status === 200) {
// 验证通过,更新日期并关闭弹窗
this.startDate = this.tempStartDate
this.endDate = this.tempEndDate
this.selectionState = 'completed'
this.$emit('input', [
this.startDate ? this.formatDate(this.startDate) : null,
this.endDate ? this.formatDate(this.endDate) : null
])
this.handleClose(false)
} else {
uni.showToast({
title: res.msg || '所选日期范围包含不可预约日期,请重新选择',
icon: 'none'
})
}
})
},
handleClose(shouldClear = false) {
if (shouldClear) {
this.clearDates()
this.startDate = null
this.endDate = null
this.$emit('input', [null, null])
} else {
// 恢复到原始状态
this.tempStartDate = this.startDate
this.tempEndDate = this.endDate
if (this.startDate && this.endDate) {
this.selectionState = 'completed'
} else if (this.startDate) {
this.selectionState = 'selecting'
} else {
this.selectionState = 'initial'
}
}
this.$emit('update:show', false)
this.$emit('close')
}
}
}
</script>
<style lang="scss" scoped>
.date-range-picker {
.picker-container {
width: 690rpx;
background: #FFFFFF;
border-radius: 24rpx;
padding: 30rpx;
box-sizing: border-box;
}
.picker-header {
text-align: center;
margin-bottom: 30rpx;
.title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.date-display {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 30rpx;
padding: 20rpx;
background: #F8F8F8;
border-radius: 12rpx;
.date-input {
flex: 1;
.label {
font-size: 24rpx;
color: #999999;
margin-bottom: 8rpx;
display: block;
}
.value {
font-size: 28rpx;
color: #333333;
&.placeholder {
color: #999999;
}
}
}
.separator {
margin: 0 20rpx;
color: #999999;
font-size: 28rpx;
}
}
.calendar {
.calendar-header {
margin-bottom: 20rpx;
.month-nav {
display: flex;
align-items: center;
justify-content: space-evenly;
margin-bottom: 20rpx;
padding: 0 20rpx;
.month-text {
font-size: 28rpx;
color: #333333;
font-weight: bold;
}
.nav-btn {
padding: 10rpx 20rpx;
color: #666666;
font-size: 32rpx;
}
}
.weekdays {
display: flex;
justify-content: space-around;
.weekday {
width: 14.28%;
text-align: center;
font-size: 24rpx;
color: #999999;
}
}
}
.days {
display: flex;
flex-wrap: wrap;
.day {
width: 14.28%;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: #333333;
position: relative;
flex-direction: column;
&:not(.selected):not(.disabled) {
color: #4B97EB;
}
.status-dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
margin-top: 4rpx;
}
&.empty {
pointer-events: none;
}
&.disabled {
color: #CCCCCC;
pointer-events: none;
}
&.selected {
background: #C52733;
color: #FFFFFF;
.status-dot {
background: #FFFFFF;
}
}
&.selecting-start {
background: #4B97EB;
color: #FFFFFF;
border-radius: 8rpx;
position: relative;
&::after {
content: '';
position: absolute;
top: -2rpx;
left: -2rpx;
right: -2rpx;
bottom: -2rpx;
border: 2rpx solid #4B97EB;
border-radius: 10rpx;
animation: pulse 1.5s infinite;
}
.status-dot {
background: #FFFFFF;
}
}
&.in-range {
background: rgba(197, 39, 51, 0.1);
}
&.start-date {
border-top-left-radius: 8rpx;
border-bottom-left-radius: 8rpx;
}
&.end-date {
border-top-right-radius: 8rpx;
border-bottom-right-radius: 8rpx;
}
&.available .status-dot {
background: #4CAF50;
}
&.booked .status-dot {
background: #FF9800;
}
&.unavailable .status-dot {
background: #F44336;
}
}
}
}
.picker-footer {
margin-top: 30rpx;
display: flex;
justify-content: space-between;
padding: 0 20rpx;
.btn {
width: 100%;
height: 80rpx;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
&.btn-clear {
background: #F8F8F8;
color: #999999;
}
&.btn-confirm {
background: #C52733;
color: #FFFFFF;
}
}
}
}
@keyframes pulse {
0% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.7;
transform: scale(1.05);
}
100% {
opacity: 1;
transform: scale(1);
}
}
// Animation Styles
.calendar-body {
position: relative;
height: 480rpx; // 6 rows * 80rpx
overflow: hidden;
width: 100%;
}
.days.absolute {
position: absolute;
top: 0;
left: 0;
width: 100%;
// height: 100%;
z-index: 1;
}
// Keyframes for sliding
@keyframes slide-next-enter {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes slide-next-leave {
from { transform: translateX(0); }
to { transform: translateX(-100%); }
}
@keyframes slide-prev-enter {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
@keyframes slide-prev-leave {
from { transform: translateX(0); }
to { transform: translateX(100%); }
}
.next-enter { animation: slide-next-enter 0.3s forwards; }
.next-leave { animation: slide-next-leave 0.3s forwards; }
.prev-enter { animation: slide-prev-enter 0.3s forwards; }
.prev-leave { animation: slide-prev-leave 0.3s forwards; }
</style>
-224
View File
@@ -1,224 +0,0 @@
<template>
<view v-if="show" class="guide-remark white" @touchmove.stop.prevent="" @click="next">
<view class="guid-wrap">
<image
v-for="(img, index) in functionGuideData.imgs"
:key="index"
:style="[img.style]"
:src="img.url"
@click.stop="handleImg(img)"
mode="aspectFit|aspectFill|widthFix"
lazy-load="true" >
</image>
<view class="box" :style="[functionGuideData.position]">
<!-- <view class="tips flex" :style="{top: functionGuideData.tipsPosition || '-110rpx'}">
{{ functionGuideData.tips }}
</view> -->
</view>
<!-- <view class="btn-wrap flex_center" :style="[functionGuideData.btnGroupPosition]">
<view class="btn flex_center" @click="jump">跳过</view>
<view class="next-btn v12-primary flex_center" @click="next">{{ functionGuideData.step==maxStep ? '知道了' : '下一步' }}</view>
</view> -->
</view>
</view>
</template>
<script>
let timer = null
let flag = false
export default {
props: {
maxStep: {
type: Number,
default: 3
},
guideData: {
type: Object,
default: ()=> {
return {
step: 1,
tips: '', // 介绍
tipsPosition: '', // 介绍 显示位置
btnGroupPosition: '', // 按钮组显示位置
position: {}
}
}
}
},
data() {
return {
show: false,
functionGuideData: {}
}
},
watch: {
guideData: {
deep: true,
immediate: false,
handler(data) {
this.functionGuideData = data
}
}
},
methods: {
handleImg(img) {
if(!img.isBtn) return
if(img.isBtn === 'next') {
this.next()
return
}
if(img.isBtn === 'jump') {
this.jump()
return
}
},
init() {
if (this.show) return
setTimeout(() => {
// const show = uni.getStorageSync('showGuide')
const show = false
if (!show) {
this.show = true
this.$parent.setFunctionGuideData({ step: 1 })
}
}, 1000)
},
jump() {
this.$parent.setFunctionGuideData({ step: 'jump' })
this.setFunctionGuideState()
// 标记状态,只有首次访问小程序时显示指引
uni.setStorageSync('showGuide', 1)
},
next() {
this.throttle(() => {
if (this.functionGuideData.step == this.maxStep) {
this.jump()
return
}
let step = this.functionGuideData.step
this.$parent.setFunctionGuideData({ step: step + 1 })
}, 800)
},
setFunctionGuideState() {
this.show = false
this.$emit('hide')
},
/* 节流 */
throttle(fn) {
if (!flag) {
flag = true
typeof fn === 'function' && fn()
timer = setTimeout(() => {
flag = false
}, 800)
}
}
}
}
</script>
<style lang="scss" scoped>
.btn-wrap{
position: absolute;
z-index: 99;
}
.guid-wrap{
position: relative;
height: inherit;
width: inherit;
}
.next-btn {
color: #fff;
padding: 2rpx 10rpx;
}
.plus {
width: 140rpx;
height: 2rpx;
position: relative;
.in-border {
border: 2rpx dashed #fff;
width: 110rpx;
height: 110rpx;
border-radius: 50%;
position: absolute;
left: 10rpx;
top: -55rpx;
}
.plus-icon {
background: #fff;
border-radius: 50%;
overflow: hidden;
width: 92rpx;
height: 92rpx;
}
}
.guide-remark {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 20230828;
.box {
position: absolute;
z-index: 10;
width: 686rpx;
border-radius: 24rpx;
left: 32rpx;
box-shadow: 0 0 0 120vh rgba(0, 0, 0, .6);
transition: all 0.3s ease;
.tips {
width: 100%;
background: #bee9ff;
border-radius: 24rpx;
padding: 20rpx 50rpx;
box-sizing: border-box;
position: absolute;
left: 0;
top: -110rpx;
z-index: 2;
font-size: 28rpx;
transition: top 0.3s ease;
}
.btn-group {
width: 100%;
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 32rpx;
z-index: 2;
transition: bottom 0.3s ease;
.btn {
width: 240rpx;
height: 84rpx;
border-radius: 52rpx;
border: 2rpx solid #FFFFFF;
background: #fff;
margin: 0 30rpx;
white-space: nowrap;
}
}
}
}
.flex {
display: flex;
align-items: center;
}
.flex_center {
@extend .flex;
justify-content: center;
}
</style>
+1 -1
View File
@@ -82,7 +82,7 @@ export default {
methods: { methods: {
routerGo(cart) { routerGo(cart) {
this.$yrouter.push({ this.$yrouter.push({
path: "/pagesShop/shop/GoodsEvaluate/index", path: "/pages/shop/GoodsEvaluate/index",
query: { id: cart.unique } query: { id: cart.unique }
}); });
} }
+3 -3
View File
@@ -1,10 +1,10 @@
<template> <template>
<view class="slider-banner product-bg"> <view class="slider-banner product-bg">
<swiper autoplay circular interval="2000" class="swiper-wrapper" @change="handleChange" v-if="imgUrls.length > 0" :indicator-dots='true' indicator-color="rgba(255, 255, 255, .3)" indicator-active-color="#ffffff"> <swiper class="swiper-wrapper" @change="handleChange" v-if="imgUrls.length > 0" :indicator-dots='true' indicator-color="rgba(255, 255, 255, .3)" indicator-active-color="#ffffff">
<block v-for="(item, imgUrlsIndex) in imgUrls" :key="imgUrlsIndex"> <block v-for="(item, imgUrlsIndex) in imgUrls" :key="imgUrlsIndex">
<swiper-item> <swiper-item>
<image v-if="!checkIfVideo(item)" :src="item" class="slide-image" /> <image v-if="!checkIfVideo(item)" :src="item" class="slide-image" />
<video v-else class="slide-image" @play="storePlayObj" :show-fullscreen-btn="false" :src="item" :id="buildId(imgUrlsIndex)" autoplay controls></video> <video v-else class="slide-image" @play="storePlayObj" :show-fullscreen-btn="false" :src="item" :id="buildId(imgUrlsIndex)" autoplay controls></video>
</swiper-item> </swiper-item>
</block> </block>
</swiper> </swiper>
@@ -38,7 +38,7 @@ export default {
currentVideo:null, currentVideo:null,
ProductConSwiper: { ProductConSwiper: {
autoplay: { autoplay: {
disableOnInteraction: true, disableOnInteraction: false,
delay: 2000 delay: 2000
}, },
loop: true, loop: true,
+8 -122
View File
@@ -1,16 +1,12 @@
<template> <template>
<view> <view>
<view <view class="product-window" :class="attr.cartAttr === true ? 'on' : ''">
:class="[{ on: attr.cartAttr === true }, className]"
:style="{ paddingBottom: paddingBottom }"
class="product-window"
>
<view class="textpic acea-row row-between-wrapper"> <view class="textpic acea-row row-between-wrapper">
<view class="pictrue" @click="previewImg(attrObj.productSelect.image)"> <view class="pictrue" @click="previewImg(attrObj.productSelect.image)">
<image :src="attrObj.productSelect.image" class="image" /> <image :src="attrObj.productSelect.image" class="image" />
</view> </view>
<view class="text"> <view class="text">
<view v-if="!isNegotiable" class="money font-color-lightred v12-font-"> <view class="money font-color-lightred v12-font-">
<text class="num v12-font-40">{{ attrObj.productSelect.price }}</text> <text class="num v12-font-40">{{ attrObj.productSelect.price }}</text>
<text class="v12-ml-2 v12-font-weight-300 v12-font-22" style="color: #BBBBBB; text-decoration: line-through;"></text> <text class="v12-ml-2 v12-font-weight-300 v12-font-22" style="color: #BBBBBB; text-decoration: line-through;"></text>
@@ -18,7 +14,6 @@
<text class="v12-white-text v12-red v12-font-22 v12-radius-40 v12-px-1 v12-font-weight-400">会员价</text> <text class="v12-white-text v12-red v12-font-22 v12-radius-40 v12-px-1 v12-font-weight-400">会员价</text>
<!-- <text class="stock">库存: {{ attrObj.productSelect.stock }}</text> --> <!-- <text class="stock">库存: {{ attrObj.productSelect.stock }}</text> -->
</view> </view>
<view class="v12-primary-text" v-else>价格面议</view>
<view class="more-t">{{ attrObj.productSelect.store_name }}</view> <view class="more-t">{{ attrObj.productSelect.store_name }}</view>
</view> </view>
<view class="iconfont icon-guanbi" @click="closeAttr"></view> <view class="iconfont icon-guanbi" @click="closeAttr"></view>
@@ -49,16 +44,9 @@
</view> </view>
<view class="cart v12-justify-between v12-align-center"> <view class="cart v12-justify-between v12-align-center">
<view class="titlev12-dark-text f12-font-32">购买数量</view> <view class="titlev12-dark-text f12-font-32">购买数量</view>
<view v-if="!hideQuantityControls" class="carnum acea-row row-left"> <view class="carnum acea-row row-left">
<view style="border-radius: 40rpx 0rpx 0rpx 40rpx" class="cart-btn item reduce v12-font-36 v12-font-bold v12-white-text v12-dark1 v12-dark1-border" :class="cartNum <= 1 ? 'on' : ''" @click="CartNumDes">-</view> <view style="border-radius: 40rpx 0rpx 0rpx 40rpx" class="cart-btn item reduce v12-font-36 v12-font-bold v12-white-text v12-dark1 v12-dark1-border" :class="cartNum <= 1 ? 'on' : ''" @click="CartNumDes">-</view>
<input <view class="item v12-font-36 v12-font-bold v12-dark-text cart-btn">{{ cartNum }}</view>
type="number"
:min="1"
:max="attrObj.productSelect.stock"
@blur="inputNumer(cartNumber)"
v-model="cartNumber"
style="height: 55rpx !important; width:80rpx !important"
class="item v12-font-36 v12-font-bold v12-dark-text cart-btn" />
<view <view
style="border-radius:0 40rpx 40rpx 0" style="border-radius:0 40rpx 40rpx 0"
class="item plus v12-font-bold v12-white-text v12-primary v12-primary-border v12-font-36 cart-btn" class="item plus v12-font-bold v12-white-text v12-primary v12-primary-border v12-font-36 cart-btn"
@@ -70,54 +58,15 @@
@click="CartNumAdd" @click="CartNumAdd"
>+</view> >+</view>
</view> </view>
<view v-else class="v12-font-28 v12-dark-text">x1</view>
</view>
<view class="v12-px-2 v12-mt-3" v-if="showOk">
<u-button
shape="circle"
:color="(attr.productSelect.stock === 0 && attr.cartAttr) ? '#9D9D9D' : '#C52733'"
@click="$emit('ok')"
:disabled="(attr.productSelect.stock === 0 && attr.cartAttr)"
>{{ okText }}</u-button>
</view>
<view class="v12-px-2 v12-mt-3" v-if="isGift">
<u-button
shape="circle"
:color="(attr.productSelect.stock === 0 && attr.cartAttr) ? '#9D9D9D' : '#C52733'"
@click="$emit('gift')"
:disabled="(attr.productSelect.stock === 0 && attr.cartAttr)"
>送给朋友</u-button>
</view> </view>
</view> </view>
<view <view class="mask" @touchmove.prevent :hidden="attr.cartAttr === false" @click="closeAttr"></view>
:hidden="attr.cartAttr === false"
:class="className"
class="mask"
@touchmove.prevent
@click="closeAttr"
></view>
</view> </view>
</template> </template>
<script> <script>
export default { export default {
name: "ProductWindow", name: "ProductWindow",
props: { props: {
isNegotiable: {
type: Boolean,
default: false
},
isGift: {
type: Boolean,
default: false
},
paddingBottom: {
type: String,
default: '160rpx'
},
showOk: {
type: Boolean,
default: false
},
attr: { attr: {
type: Object, type: Object,
default: () => { default: () => {
@@ -129,69 +78,21 @@ export default {
cartNum: { cartNum: {
type: Number, type: Number,
default: () => 1 default: () => 1
},
okText: {
type: String,
default: '加入购物车'
},
className: {
type: String,
default: ''
},
hideQuantityControls: {
type: Boolean,
default: false
} }
}, },
data() { data() {
return { return {
cartNumber: this.cartNum,
attrObj: { attrObj: {
productSelect: {}, productSelect: {},
productAttr: [] productAttr: []
} }
} }
}, },
watch: {
'attr.cartAttr': {
handler(val) {
console.log(val);
if(!val) {
this.cartNumber = 1
}
},
deep: true,
immediate: true
},
cartNum: {
handler(val) {
this.cartNumber = val || 1
},
deep: true,
immediate: true
},
cartNumber(val) {
if (val > this.attrObj.productSelect.stock) {
val = this.attrObj.productSelect.stock
}
this.$emit('input', +val)
this.$emit("changeFun", { action: "ChangeCartNum", value: +val })
}
},
created() { created() {
this.$set(this, 'attrObj', JSON.parse(JSON.stringify(this.attr))) this.$set(this, 'attrObj', JSON.parse(JSON.stringify(this.attr)))
console.log(this.attrObj)
}, },
methods: { methods: {
inputNumer(e) {
if(e === '') {
this.cartNumber = 1
this.$forceUpdate()
}
if(+e > this.attrObj.productSelect.stock) {
this.cartNumber = this.attrObj.productSelect.stock
this.$forceUpdate()
}
},
reRender(data) { reRender(data) {
this.$set(this, 'attrObj', JSON.parse(JSON.stringify(data))) this.$set(this, 'attrObj', JSON.parse(JSON.stringify(data)))
// console.log(this.attrObj.productAttr) // console.log(this.attrObj.productAttr)
@@ -206,15 +107,10 @@ export default {
this.$emit("changeFun", { action: "changeattr", value: false }) this.$emit("changeFun", { action: "changeattr", value: false })
}, },
CartNumDes() { CartNumDes() {
if(this.cartNumber <= 1) return this.$emit("changeFun", { action: "ChangeCartNum", value: false })
console.log(this.cartNumber, 'cartNumber');
this.cartNumber--
this.$emit("changeFun", { action: "ChangeCartNum", value: this.cartNumber })
}, },
CartNumAdd() { CartNumAdd() {
if(this.cartNumber >= this.attrObj.productSelect.stock) return this.$emit("changeFun", { action: "ChangeCartNum", value: 1 })
this.cartNumber++
this.$emit("changeFun", { action: "ChangeCartNum", value: this.cartNumber })
}, },
tapAttr(index, subIndex, subItem) { tapAttr(index, subIndex, subItem) {
// 缺货的点击了没效果 // 缺货的点击了没效果
@@ -228,7 +124,6 @@ export default {
} }
}) })
const value = this.getCheckedValue().sort().join(",") const value = this.getCheckedValue().sort().join(",")
this.cartNumber = 1
this.$emit("changeFun", { this.$emit("changeFun", {
action: "ChangeAttr", action: "ChangeAttr",
value: { value: {
@@ -255,15 +150,6 @@ export default {
} }
</script> </script>
<style scope> <style scope>
.btn-car-disabled {
border: 2rpx solid #9D9D9D !important;
color: #9D9D9D !important;
}
.btn-buy-disabled {
background: #9D9D9D !important;
color: #FFFFFF !important;
}
.itemn{ .itemn{
margin: 28rpx 0 0 34rpx !important; margin: 28rpx 0 0 34rpx !important;
width: auto; width: auto;
+1 -1
View File
@@ -80,7 +80,7 @@ export default {
overscroll-behavior: contain; overscroll-behavior: contain;
} }
.poster-pop { .poster-pop {
width: 6 * 100rpx; width: 4.5 * 100rpx;
height: 8 * 100rpx; height: 8 * 100rpx;
position: fixed; position: fixed;
left: 50%; left: 50%;
+20 -180
View File
@@ -3,74 +3,47 @@
<view <view
v-for="(item, evaluateWtapperIndex) in reply" v-for="(item, evaluateWtapperIndex) in reply"
:key="evaluateWtapperIndex" :key="evaluateWtapperIndex"
class="evaluateItem v12-pt-3" class="evaluateItem"
> >
<!-- 用户信息头部 --> <view class="pic-text acea-row row-middle">
<view class="user-header v12-px-4"> <view class="pictrue">
<view class="avatar-box"> <image :src="item.avatar" class="image" />
<image :src="item.avatar" class="avatar" mode="aspectFill" />
</view> </view>
<view class="user-info"> <view class="acea-row row-middle">
<view class="name line1">{{ item.nickname }}</view> <view class="name line1">{{ item.nickname }}</view>
<view class="time">{{ item.createTime }}</view>
</view> </view>
</view> </view>
<view class="v12-px-4"> <view class="v12-px-4">
<view class="v12-secondary-dark-text v12-font-24 attr-bg"> {{ item.sku }}</view> <view class="v12-secondary-dark-text v12-font-24 attr-bg"> {{ item.sku }}</view>
<view class="start" :class="'star' + item.star"></view> <view class="start" :class="'star' + item.star"></view>
</view> </view>
<!-- <view class="time">{{ item.createTime }} {{ item.sku||'' }}</view> -->
<!-- 评论内容 --> <view class="evaluate-infor v12-font-24">{{ item.comment }}</view>
<view class="evaluate-infor">{{ item.comment || '此用户没有填写评价'}}</view> <view class="imgList acea-row">
<!-- 图片/视频列表 -->
<view class="imgList">
<!-- 视频 -->
<view v-if="item.video" class="pictrue"> <view v-if="item.video" class="pictrue">
<view
@click="pauseOtherVideo('video' + evaluateWtapperIndex)"
v-if="activeVideo !== 'video' + evaluateWtapperIndex"
class="play-icon"
>
<u-icon name="play-right-fill" color="#fff" size="48"></u-icon>
</view>
<image
v-if="activeVideo !== 'video' + evaluateWtapperIndex"
:src="item.video + '?vframe/jpg/offset/1'"
class="image"
mode="aspectFill"
@click="pauseOtherVideo('video' + evaluateWtapperIndex)"
/>
<video <video
v-else
:src="item.video" :src="item.video"
:poster="item.video + '?vframe/jpg/offset/1'" :poster="item.video + '?vframe/jpg/offset/1'"
controls controls
autoplay play-btn-position="center"
class="image" class="image"
:id="'video' + evaluateWtapperIndex"
@play="pauseOtherVideo('video' + evaluateWtapperIndex)"
/> />
</view> </view>
<!-- 图片 -->
<view <view
v-for="(pic, idx) in item.picturesArr" v-for="(itemn, eq) in item.picturesArr"
:key="idx" :key="eq"
class="pictrue" class="pictrue"
> >
<image :src="pic" class="image" mode="aspectFill" @click="previewImage(item.picturesArr, idx)" /> <image :src="itemn" class="image" @click="previewImage(item.picturesArr, eq)" />
</view> </view>
</view> </view>
<!-- 商家回复 -->
<view class="reply" v-if="item.merchantReplyContent"> <view class="reply" v-if="item.merchantReplyContent">
<text class="font-color-red">店小二</text> <span class="font-color-red">店小二</span>
{{item.merchantReplyContent}} {{item.merchantReplyContent}}
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import { dataFormat } from "@/utils"; import { dataFormat } from "@/utils";
@@ -83,154 +56,21 @@ export default {
} }
}, },
data: function() { data: function() {
return { return {};
videoPlayers: [],
activeVideo: null,
};
}, },
mounted: function() {}, mounted: function() {},
methods: { methods: {
dataFormat, dataFormat,
previewImage(imgs,index){ previewImage(imgs,index){
uni.previewImage({ uni.previewImage({
current:imgs[index], current:imgs[index],
urls:imgs urls:imgs
}) })
}, }
// 播放视频时暂停其他视频
pauseOtherVideo(video) {
this.activeVideo = video;
if(this.videoPlayers.includes(video)) {
this.videoPlayers.forEach((item) => {
if(item !== video) {
uni.createVideoContext(item, this).pause();
}
})
} else {
this.videoPlayers.push(video);
}
}
} }
}; };
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.evaluateWtapper {
.evaluateItem {
margin-bottom: 30rpx;
border-bottom: 1px solid #f5f5f5;
padding-bottom: 30rpx;
&:last-child {
border-bottom: none;
}
}
}
.user-header {
display: flex;
align-items: center;
margin-bottom: 12rpx;
.avatar-box {
margin-right: 20rpx;
.avatar {
width: 70rpx;
height: 70rpx;
border-radius: 50%;
}
}
.user-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
.name {
font-size: 28rpx;
color: #333;
font-weight: bold;
margin-bottom: 4rpx;
}
.time {
font-size: 22rpx;
color: #999;
}
}
}
.tag-row {
margin-bottom: 12rpx;
.default-tag {
display: inline-block;
background: #FFF0F1;
color: #FE5261;
font-size: 20rpx;
padding: 4rpx 12rpx;
border-radius: 6rpx;
}
}
.star-row {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.star-icon {
margin-right: 4rpx;
}
}
.evaluate-infor {
font-size: 28rpx;
color: #333;
line-height: 1.6;
margin-bottom: 20rpx;
text-align: justify;
}
.imgList {
display: flex;
flex-wrap: wrap;
.pictrue {
width: 220rpx;
height: 220rpx;
margin-right: 15rpx;
margin-bottom: 15rpx;
border-radius: 12rpx;
overflow: hidden;
position: relative;
background: #f5f5f5;
&:nth-child(3n) {
margin-right: 0;
}
.image {
width: 100%;
height: 100%;
}
.play-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
}
}
.reply {
background: #F5F5F5;
border-radius: 12rpx;
padding: 20rpx;
margin-top: 10rpx;
font-size: 24rpx;
color: #666;
line-height: 1.5;
}
.attr-bg{ .attr-bg{
background: rgba(197,39,51,0.1); background: rgba(197,39,51,0.1);
padding: 7rpx 5px; padding: 7rpx 5px;
-84
View File
@@ -1,84 +0,0 @@
<template>
<view v-if="showImg" class="ai-entrance">
<image
:src="settingInfo.mainImage"
mode="widthFix"
class="img"
@click="enterAiChat()"
/>
</view>
</template>
<script>
import {
getAiSystemInfoSetting
} from '@/api/public'
import {
getCountyAiDetail
} from '@/api/chat/index'
export default {
name: 'AiEntrance',
props: {
cityName: {
type: String,
default: ''
},
countyId: {
type: String,
default: ''
}
},
data() {
return {
showImg: false,
settingInfo: {},
localCityName: uni.getStorageSync('locationCityName') || ''
}
},
created() {
this.init()
},
methods: {
init() {
if (this.countyId) {
getCountyAiDetail({
countyId: this.countyId
}).then(res => {
const { success, data } = res
if (success) {
const aiImage = data.aiImage || ''
this.settingInfo.mainImage = aiImage
this.showImg = !!aiImage
}
})
return
}
getAiSystemInfoSetting().then(res => {
const { success, data } = res
if (success) {
this.settingInfo = data
this.showImg = data.showOnAppIndex === 1
}
})
},
enterAiChat() {
uni.navigateTo({
url: '/aiChat/views/index?click=1&cityName=' + (this.cityName || this.localCityName) + '&countyId=' + (this.countyId || '')
})
}
}
}
</script>
<style scoped lang="less">
.ai-entrance {
position: fixed;
right: 0;
top: 50%;
z-index: 5;
transform: translateY(-50%);
.img {
width: 88rpx;
}
}
</style>
-485
View File
@@ -1,485 +0,0 @@
<template>
<view>
<view class="c_total">资讯评论</view>
<template v-if="dataList && dataList.length">
<view class="c_comment" v-for="(item1, index1) in dataList" :key="item1.id">
<!-- 一级评论 -->
<CommonComp
:data="item1"
@likeClick="() => likeClick({ item1, index1 })"
@replyClick="() => replyClick({ item1, index1 })"
@deleteClick="() => deleteClick({ item1, index1 })"
/>
<view class="children_item" v-if="item1.children && item1.children.length">
<!-- 二级评论 -->
<CommonComp
v-for="(item2, index2) in item1.childrenShow"
:key="item2.id"
:data="item2"
:pData="item1"
@likeClick="() => likeClick({ item1, index1, item2, index2 })"
@replyClick="() => replyClick({ item1, index1, item2, index2 })"
@deleteClick="() => deleteClick({ item1, index1, item2, index2 })"
/>
<!-- 展开二级评论 -->
<view
class="expand_reply"
v-if="expandTxtShow({ item1, index1 })"
@tap="() => expandReplyFun({ item1, index1 })"
>
<span class="txt"> 展开{{ item1.children.length - item1.childrenShow.length }}条回复 </span>
<uni-icons type="down" size="24" color="#007aff"></uni-icons>
</view>
<!-- 折叠二级评论 -->
<view
class="shrink_reply"
v-if="shrinkTxtShow({ item1, index1 })"
@tap="() => shrinkReplyFun({ item1, index1 })"
>
<span class="txt"> 收起回复内容 </span>
<uni-icons type="up" size="24" color="#007aff"></uni-icons>
</view>
</view>
</view>
</template>
<!-- 空盒子 -->
<view class="empty_box" v-else>
<uni-icons type="chatboxes" size="36" color="#c0c0c0"></uni-icons>
<view>
<span class="txt"> 这里是一片荒草地, </span>
<span class="txt click" @click="() => newCommentFun()">说点什么...</span>
</view>
</view>
<!-- 评论弹窗 -->
<uni-popup ref="cPopupRef" type="bottom" @change="popChange">
<view class="c_popup_box">
<view class="reply_text">
<template v-if="Object.keys(replyTemp).length">
<span class="text_aid">回复给</span>
<img
class="user_avatar"
:src="replyTemp.item2 ? replyTemp.item2.user_avatar : replyTemp.item1.user_avatar"
/>
<span class="text_main">{{ replyTemp.item2 ? replyTemp.item2.user_name : replyTemp.item1.user_name }}</span>
</template>
<span v-else class="text_main">发表新评论</span>
</view>
<view class="content">
<view class="text_area">
<uni-easyinput
class="text_area"
type="textarea"
v-model="commentValue"
:placeholder="commentPlaceholder"
:focus="focus"
trim
autoHeight
maxlength="300"
></uni-easyinput>
</view>
<view class="send_btn" @tap="() => sendClick()">发送</view>
</view>
</view>
</uni-popup>
<!-- 删除弹窗 -->
<uni-popup ref="delPopupRef" type="dialog">
<uni-popup-dialog
mode="base"
title=""
content="确定删除这条评论吗?"
:before-close="true"
@close="delCloseFun"
@confirm="delConfirmFun"
></uni-popup-dialog>
</uni-popup>
</view>
</template>
<script>
import CommonComp from "./componets/common";
export default {
components: { CommonComp },
props: {
/** 登陆用户信息
* id: number // 登陆用户id
* user_name: number // 登陆用户名
* user_avatar: string // 登陆用户头像地址
*/
myInfo: {
type: Object,
default: () => {},
},
/** 文章作者信息
* id: number // 文章作者id
* user_name: number // 文章作者名
* user_avatar: string // 文章作者头像地址
*/
userInfo: {
type: Object,
default: () => {},
},
/** 评论列表
* id: number // 评论id
* parent_id: number // 父级评论id
* reply_id: number // 被回复人评论id
* reply_name: string // 被回复人名称
* user_name: string // 用户名
* user_avatar: string // 评论者头像地址
* user_content: string // 评论内容
* is_like: boolean // 是否点赞
* like_count: number // 点赞数统计
* create_time: string // 创建时间
*/
tableData: {
type: Array,
default: () => [],
},
// 评论总数
tableTotal: {
type: Number,
default: 0,
},
// 评论删除模式
// bind - 当被删除的一级评论存在回复评论, 那么该评论内容变更显示为[当前评论内容已被移除]
// only - 仅删除当前评论(后端删除相关联的回复评论, 否则总数显示不对)
// all - 删除所有评论包括回复评论
deleteMode: {
type: String,
default: "all",
},
},
data() {
return {
dataList: [], // 渲染数据(前端的格式)
replyTemp: {}, // 回复临时数据
isNewComment: false, // 是否为新评论
focus: false, // 评论弹窗
commentValue: "", // 输入框值
commentPlaceholder: "说点什么...", // 输入框占位符
delTemp: {}, // 删除临时数据
};
},
watch: {
tableData: {
handler(newVal) {
if (newVal.length !== this.dataList.length) {
this.dataList = this.treeTransForm(newVal);
}
},
deep: true,
immediate: true,
},
},
mounted() {},
methods: {
// 数据转换
treeTransForm(data) {
let newData = JSON.parse(JSON.stringify(data));
let result = [];
let map = {};
newData.forEach((item, i) => {
item.owner = item.user_id === this.myInfo.user_id; // 是否为当前登陆用户 可以对自己的评论进行删除 不能回复
item.author = item.user_id === this.userInfo.user_id; // 是否为作者 显示标记
map[item.id] = item;
});
newData.forEach((item) => {
let parent = map[item.parent_id];
if (parent) {
(parent.children || (parent.children = [])).push(item); // 所有回复
if (parent.children.length === 1) {
(parent.childrenShow = []).push(item); // 显示的回复
}
} else {
result.push(item);
}
});
return result;
},
// 点赞
setLike(item) {
item.is_like = !item.is_like;
item.like_count = item.is_like ? item.like_count + 1 : item.like_count - 1;
},
likeClick({ item1, index1, item2, index2 }) {
let item = item2 || item1;
this.setLike(item);
this.$emit("likeFun", { params: item }, (res) => {
// 请求后端失败, 重置点赞
setLike(item);
});
},
// 回复
replyClick({ item1, index1, item2, index2 }) {
this.replyTemp = JSON.parse(JSON.stringify({ item1, index1, item2, index2 }));
this.$refs["cPopupRef"].open();
},
// 发起新评论
newCommentFun() {
this.isNewComment = true;
this.$refs["cPopupRef"].open();
},
// 评论弹窗
popChange(e) {
// 关闭弹窗
if (!e.show) {
this.commentValue = ""; // 清空输入框值
this.replyTemp = {}; // 清空被回复人信息
this.isNewComment = false; // 恢复是否为新评论默认值
}
this.focus = e.show;
},
// 发送评论
sendClick({ item1, index1, item2, index2 } = this.replyTemp) {
let item = item2 || item1;
let params = {};
// 新评论
if (this.isNewComment) {
params = {
id: Math.random(), // 评论id
parent_id: null, // 父级评论id
reply_id: null, // 被回复评论id
reply_name: null, // 被回复人名称
};
} else {
// 回复评论
params = {
id: Math.random(), // 评论id
parent_id: item?.parent_id ?? item.id, // 父级评论id
reply_id: item.id, // 被回复评论id
reply_name: item.user_name, // 被回复人名称
};
}
params = {
...params,
user_id: this.myInfo.user_id, // 用户id
user_name: this.myInfo.user_name, // 用户名
user_avatar: this.myInfo.user_avatar, // 用户头像地址
user_content: this.commentValue, // 用户评论内容
is_like: false, // 是否点赞
like_count: 0, // 点赞数统计
create_time: "刚刚", // 创建时间
owner: true, // 是否为所有者 所有者可以进行删除 管理员默认true
};
uni.showLoading({
title: "正在发送",
mask: true,
});
this.$emit("replyFun", { params }, (res) => {
uni.hideLoading();
// 拿到后端返回的id赋值, 因为删除要用到id
params = { ...params, id: res.id };
// 新评论
if (this.isNewComment) {
this.dataList.push(params);
} else {
// 回复
let c_data = this.dataList[index1];
(c_data.children || (c_data.children = [])).push(params);
// 如果已展开所有回复, 那么此时插入children长度会大于childrenShow长度1, 所以就直接展开显示即可
if (c_data.children.length === (c_data.childrenShow || (c_data.childrenShow = [])).length + 1) {
c_data.childrenShow.push(params);
}
}
this.$emit("update:tableTotal", this.tableTotal + 1);
this.$refs["cPopupRef"].close();
});
},
//删除
deleteClick({ item1, index1, item2, index2 }) {
this.delTemp = JSON.parse(JSON.stringify({ item1, index1, item2, index2 }));
this.$refs["delPopupRef"].open();
},
// 关闭删除弹窗
delCloseFun() {
this.delTemp = {};
this.$refs["delPopupRef"].close();
},
// 确定删除
delConfirmFun({ item1, index1, item2, index2 } = this.delTemp) {
const deleteMode = this.deleteMode;
let c_data = this.dataList[index1];
uni.showLoading({
title: "正在删除",
mask: true,
});
// 删除二级评论
if (index2 >= 0) {
this.$emit("deleteFun", { params: [c_data.children[index2].id], mode: deleteMode }, (res) => {
uni.hideLoading();
this.$emit("update:tableTotal", this.tableTotal - 1);
c_data.children.splice(index2, 1);
c_data.childrenShow.splice(index2, 1);
});
} else {
// 删除一级评论
if (c_data?.children?.length) {
// 如果一级评论包含回复评论
switch (deleteMode) {
case "bind":
// 一级评论内容展示修改为: 当前评论内容已被移除
this.$emit(
"deleteFun",
{
params: [c_data.id],
mode: deleteMode,
},
(res) => {
uni.hideLoading();
c_data.user_content = "当前评论内容已被移除";
}
);
break;
case "only":
// 后端自行根据删除的一级评论id, 查找关联的子评论进行删除
this.$emit(
"deleteFun",
{
params: [c_data.id],
mode: deleteMode,
},
(res) => {
uni.hideLoading();
this.$emit("update:tableTotal", this.tableTotal - c_data.children.length + 1);
this.dataList.splice(index1, 1);
}
);
break;
default:
// all
// 收集子评论id, 提交给后端统一删除
let delIdArr = [c_data.id];
c_data.children.forEach((_, i) => {
delIdArr.push(_.id);
});
this.$emit("deleteFun", { params: delIdArr, mode: deleteMode }, (res) => {
uni.hideLoading();
this.$emit("update:tableTotal", this.tableTotal - c_data.children.length + 1);
this.dataList.splice(index1, 1);
});
break;
}
} else {
// 一级评论无回复, 直接删除
this.$emit("deleteFun", { params: [c_data.id], mode: deleteMode }, (res) => {
uni.hideLoading();
this.$emit("update:tableTotal", this.tableTotal - 1);
this.dataList.splice(index1, 1);
});
}
}
this.delCloseFun();
},
// 展开评论if
expandTxtShow({ item1, index1 }) {
return item1.childrenShow?.length && item1.children.length - item1.childrenShow.length;
},
// 展开更多评论
expandReplyFun({ item1, index1 }) {
let csLen = this.dataList[index1].childrenShow.length;
this.dataList[index1].childrenShow.push(
...this.dataList[index1].children.slice(csLen, csLen + 6) // 截取5条评论
);
},
// 收起评论if
shrinkTxtShow({ item1, index1 }) {
return item1.childrenShow?.length >= 2 && item1.children.length - item1.childrenShow.length === 0;
},
// 收起更多评论
shrinkReplyFun({ item1, index1 }) {
this.dataList[index1].childrenShow = [];
this.dataList[index1].childrenShow.push(
...this.dataList[index1].children.slice(0, 1) // 截取1条评论
);
},
},
};
</script>
<style lang="scss" scoped>
////////////////////////
.center {
display: flex;
align-items: center;
}
////////////////////////
.c_total {
padding: 20rpx 30rpx 0 30rpx;
font-size: 28rpx;
}
.empty_box {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
padding: 150rpx 10rpx;
font-size: 28rpx;
.txt {
color: $uni-text-color-disable;
}
.click {
color: $uni-color-primary;
}
}
.c_comment {
padding: 20rpx 30rpx;
font-size: 28rpx;
.children_item {
padding: 20rpx 30rpx;
margin-top: 10rpx;
margin-left: 80rpx;
background-color: $uni-bg-color-grey;
.expand_reply,
.shrink_reply {
margin-top: 10rpx;
margin-left: 80rpx;
.txt {
font-weight: 600;
color: $uni-color-primary;
}
}
}
}
.c_popup_box {
background-color: #fff;
.reply_text {
@extend .center;
padding: 20rpx 20rpx 0 20rpx;
font-size: 26rpx;
.text_aid {
color: $uni-text-color-grey;
margin-right: 5rpx;
}
.user_avatar {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
margin-right: 6rpx;
margin-left: 12rpx;
}
.text_main {
}
}
.content {
@extend .center;
.text_area {
flex: 1;
padding: 20rpx;
}
.send_btn {
@extend .center;
justify-content: center;
width: 120rpx;
height: 60rpx;
border-radius: 20rpx;
font-size: 28rpx;
color: #fff;
background-color: $uni-color-primary;
margin-right: 20rpx;
margin-left: 5rpx;
}
}
}
</style>
-182
View File
@@ -1,182 +0,0 @@
<template>
<view class="comment_item">
<view class="top">
<view class="top_left">
<img class="user_avatar" :src="data.user_avatar" />
<uni-tag v-if="data.author" class="tag" type="primary" :inverted="false" text="作者" size="mini" circle />
<span class="user_name">{{ data.user_name }}</span>
<span class="user_name">{{ cReplyName }}</span>
</view>
<view class="top_right" @click="likeClick(data)">
<span :class="[data.is_like ? 'active' : '', 'like_count']">{{ cLikeCount }}</span>
<uni-icons v-show="data.is_like" type="hand-up-filled" size="24" color="#007aff"></uni-icons>
<uni-icons v-show="!data.is_like" type="hand-up" size="24" color="#999"></uni-icons>
</view>
</view>
<view class="content" @click="replyClick(data)">
{{ c_content }}
<span class="shrink" v-if="isShrink" @click.stop="expandContentFun(data.user_content)">...展开</span>
<span
class="shrink"
v-if="!isShrink && user_content.length > contentShowLength"
@click.stop="shrinkContentFun(data.user_content)"
>
收起</span
>
</view>
<view class="bottom">
<span class="create_time">{{ data.create_time }}</span>
<span v-if="data.owner" class="delete" @click="deleteClick(data)">删除</span>
<!-- <span v-else class="reply" @click="replyClick(props.data)"
>回复</span
> -->
</view>
</view>
</template>
<script>
export default {
props: {
// 评论数据
data: {
type: Object,
default: () => {},
},
},
data() {
return {
// 评论过长处理
contentShowLength: 70, // 默认显示评论字符
user_content: "",
isShrink: false, // 是否收缩评论
c_content: "",
};
},
computed: {
// 被回复人名称
cReplyName: function () {
return this.data?.reply_name ? `` + this.data?.reply_name : "";
},
// 点赞数显示
cLikeCount: function () {
return this.data.like_count === 0 ? "" : this.$formatCount(this.data.like_count);
},
},
watch: {
// 删除变更显示定制
"data.user_content": function (newVal, oldVal) {
if (newVal !== oldVal) {
this.c_content = newVal;
}
},
// 监听isShrink变化,更新c_content
isShrink: function (newVal) {
this.c_content = newVal ? this.user_content.slice(0, this.contentShowLength + 1) : this.user_content;
},
},
methods: {
// 展开文字
expandContentFun() {
this.isShrink = false;
},
// 收起文字
shrinkContentFun() {
this.isShrink = true;
},
// 点赞
likeClick(item) {
this.$emit("likeClick", item);
},
// 回复
replyClick(item) {
// 自己不能回复自己
if (item.owner) return;
this.$emit("replyClick", item);
},
// 删除
deleteClick(item) {
this.$emit("deleteClick", item);
},
},
mounted() {
this.user_content = this.data.user_content;
this.isShrink = this.user_content.length > this.contentShowLength;
this.c_content = this.isShrink ? this.user_content.slice(0, this.contentShowLength + 1) : this.user_content;
},
};
</script>
<style lang="scss" scoped>
////////////////////
.center {
display: flex;
align-items: center;
}
.ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
////////////////////
.comment_item {
font-size: 28rpx;
.top {
@extend .center;
justify-content: space-between;
.top_left {
display: flex;
align-items: center;
overflow: hidden;
.user_avatar {
width: 68rpx;
height: 68rpx;
border-radius: 50%;
margin-right: 12rpx;
}
.tag {
margin-right: 6rpx;
}
.user_name {
@extend .ellipsis;
max-width: 180rpx;
color: #8c8c8c;
}
}
.top_right {
@extend .center;
.like_count {
color: #8c8c8c;
&.active {
color: #007aff;
}
}
}
}
.content {
padding: 10rpx;
margin-left: 70rpx;
color: #333;
&:active {
background-color: #f2f2f2;
}
.shrink {
padding: 20rpx 20rpx 20rpx 0rpx;
color: #007aff;
}
}
.bottom {
padding-left: 80rpx;
font-size: 24rpx;
.create_time {
color: #8c8c8c;
}
.delete {
padding: 20rpx 20rpx 0 20rpx;
color: #c0c0c0;
}
.reply {
color: #007aff;
}
}
}
</style>
+343
View File
@@ -0,0 +1,343 @@
<template>
<view>
<view class="upload">
<block v-for="(upload,index) in uploads" :key="index">
<view class="uplode-file">
<image v-if="types == 'image'" class="uploade-img" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'" :src="upload" :data-src="upload" @tap="previewImage"></image>
<image v-if="types == 'image'" class="clear-one-icon" :src="clearIcon" @tap="delImage(index)"></image>
<video v-if="types == 'video'" class="uploade-img" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'" :src="upload" controls>
<cover-image v-if="types == 'video'" class="clear-one-icon" :src="clearIcon" @tap="delImage(index)"></cover-image>
</video>
</view>
</block>
<view v-if="uploads.length < uploadCount" :class="uploadIcon ? 'uploader-icon' : 'uploader-input-box'" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'" >
<view v-if="!uploadIcon" class="uploader-input" @tap="chooseUploads"></view>
<image v-else class="image-cion" :src="uploadIcon" @tap="chooseUploads"></image>
</view>
</view>
<!-- <button type="primary" v-if="types == 'image' && !autoUpload" @tap="unifiedUpload">上传</button> -->
</view>
</template>
<script>
export default{
props: {
header:{
type:Object,
default:{}
},
types: {
type: String,
default: 'image'
},
dataList: {
type: Array,
default: function() {
return []
}
},
clearIcon: {
type: String,
default: 'http://img1.imgtn.bdimg.com/it/u=451604666,2295832001&fm=26&gp=0.jpg'
},
uploadIcon: {
type: String,
default: ''
},
uploadUrl: {
type: String,
default: ''
},
deleteUrl: {
type: String,
default: ''
},
uploadCount: {
type: Number,
default: 1
},
//上传图片大小 默认3M
upload_max: {
type: Number,
default: 3
},
//上传视频大小 默认30M
upload_video_max: {
type: Number,
default: 50
},
// 图片/选择宽高
upload_img_wh: {
type: Number,
default: 210
},
autoUpload: {
type: Boolean,
default: false
}
},
data(){
return {
//上传的图片地址
uploadImages: [],
//展示的图片地址
uploads: [],
// 超出限制数组
exceeded_list: [],
}
},
watch:{
dataList:{
handler(val){
this.uploads = val;
},
immediate: true
}
},
methods:{
previewImage (e) {
var current = e.target.dataset.src
uni.previewImage({
current: current,
urls: this.dataList
})
},
chooseUploads(){
switch (this.types){
case 'image':
uni.chooseImage({
count: this.uploadCount - this.uploads.length, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], //从相册选择
success: (res) => {
for(let i = 0; i< res.tempFiles.length; i++){
if(Math.ceil(res.tempFiles[i].size / 1024) < this.upload_max * 1024){
this.uploads.push(res.tempFiles[i].path)
console.log(this.uploads);
if(this.autoUpload){
this.uploadFile(res.tempFiles[i].path)
}else{
this.uploadImages.push(res.tempFiles[i].path);
}
}else {
this.exceeded_list.push(i === 0 ? 1 : i + 1);
uni.showModal({
title: '提示',
content: `${[...new Set(this.exceeded_list)].join(',')}张图片超出限制${this.upload_max}MB,已过滤`
});
}
}
},
fail: (err) => {
uni.showModal({
content: JSON.stringify(err)
});
}
});
break;
case 'video' :
uni.chooseVideo({
sourceType: ['camera', 'album'],
success: (res) => {
if(Math.ceil(res.size / 1024) < this.upload_video_max * 1024){
this.uploads.push(res.tempFilePath)
uni.uploadFile({
url: this.uploadUrl, //仅为示例,非真实的接口地址
filePath: res.tempFilePath,
name: 'file',
//请求参数
formData: {
'user': 'test'
},
success: (uploadFileRes) => {
this.$emit('successVideo',uploadFileRes)
}
});
}else {
uni.showModal({
title: '提示',
content: `${[...new Set(this.exceeded_list)].join(',')}张视频超出限制${this.upload_max}MB,已过滤`
});
}
},
fail: (err) => {
uni.showModal({
content: JSON.stringify(err)
});
}
});
break;
}
},
delImage(index){
this.uploads.splice(index,1)
//如果不自动上传
if(!this.autoUpload){
this.uploadImages.splice(index,1)
}
// //第一个是判断app或者h5的 第二个是判断小程序的
// if(this.uploads[index].substring(0,4) !== 'http' || this.uploads[index].substring(0,11) == 'http://tmp/'){
// this.uploads.splice(index,1)
// //如果不自动上传
// if(!this.autoUpload){
// this.uploadImages.splice(index,1)
// }
// return;
// };
// if(!this.deleteUrl) {
// uni.showModal({
// content: '请填写删除接口'
// });
// return;
// };
// uni.request({
// url: this.deleteUrl,
// method: 'DELETE',
// data: {
// image: this.dataList[index]
// },
// success: res => {
// if(res.data.status == 1) {
// uni.showToast({
// title: '删除成功'
// })
// this.uploads.splice(index,1)
// }
// },
// });
},
uploadFile(path){
// uni.uploadFile({
// url: this.uploadUrl, //仅为示例,非真实的接口地址
// filePath: path,
// name: 'file',
// //自定义请求参数
// formData: {
// 'user': 'test'
// },
// success: (uploadFileRes) => {
// this.$emit('successImage',uploadFileRes)
// }
// });
uni.uploadFile({
url: this.uploadUrl,
filePath: path,
header: this.header,
name: "file",
success: res => {
console.log(res);
this.$emit('successImage',uploadFileRes)
},
fail: err => {
console.log(err);
},
complete: res => {
}
});
},
unifiedUpload(){
if(!this.uploadUrl) {
uni.showModal({
content: '请填写上传接口'
});
return;
};
for (let i of this.uploadImages) {
this.uploadFile(i)
}
}
}
}
</script>
<style scoped>
.upload {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.uplode-file {
margin: 10rpx;
/* width: 210upx;
height: 210upx; */
position: relative;
}
.uploade-img {
display: block;
/* width: 210upx;
height: 210upx; */
}
.clear-one{
position: absolute;
top: -10rpx;
right: 0;
}
.clear-one-icon{
position: absolute;
width: 20px;
height: 20px;
top: 0;
right: 0;
z-index: 9;
}
.uploader-input-box {
position: relative;
margin:10upx;
/* width: 208upx;
height: 208upx; */
border: 2upx solid #D9D9D9;
box-sizing: border-box;
}
.uploader-input-box:before,
.uploader-input-box:after {
content: " ";
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
background-color: #D9D9D9;
}
.uploader-input-box:before {
width: 4upx;
height: 79upx;
}
.uploader-input-box:after {
width: 79upx;
height: 4upx;
}
.uploader-input-box:active {
border-color: #999999;
}
.uploader-input-box:active:before,
.uploader-input-box:active:after {
background-color: #999999;
}
.uploader-input {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
.uploader-icon{
position: relative;
margin:10upx;
/* width: 208upx;
height: 208upx; */
}
.uploader-icon .image-cion{
width: 100%;
height: 100%;
}
</style>
+51
View File
@@ -0,0 +1,51 @@
### easy-upload 组件
使用方法
```js
<easy-upload
:dataList="dataList"
uploadUrl="http://localhost:3000/upload"
deleteUrl='http://localhost:3000/upload'
:types="types"
@successImage="successImage"
@successVideo="successvideo"
/>
//使用 hbuilderX (easycom) 可以直接使用 或
import easyUpload from '@/components/easy-upload/easy-upload.vue'
export default {
//用easycom 则省略注册组件
components:{
easyUpload
},
data() {
return {
dataList: [],
types: 'image'
}
}
}
```
| 参数 | 类型 | 是否必填 | 参数描述
| ---- | ---- | ---- | ----
| types | String | 否 | 上传类型 image/video
| autoUpload | Boolean | 否 | 自动上传 默认false
| dataList | Array | 否 | 图片/视频数据展示
| clearIcon | String | 否 | 删除图标(可以换成自己的图片)
| uploadIcon | String | 否 | 上传图标(可以换成自己的图片)
| uploadUrl | String | 否 | 上传的接口
| deleteUrl | String | 否 | 删除的接口
| uploadCount | Number | 否 | 上传图片最大个数(默认为一张)
| upload_max | Number | 否 | 上传大小(默认为3M)
| upload_max | Number | 否 | 上传大小(默认为3M)
| upload_max | Number | 否 | 上传大小(默认为3M)
| 事件 | 是否必填 | 参数描述
| ---- | ---- | ----
| successImage | 否 | 上传图片成功事件
| successVideo | 否 | 上传视频成功回调
示例项目中有简单的服务端代码 /server (node.js)
如果本地测试可以先运行一下服务端的代码
-128
View File
@@ -1,128 +0,0 @@
<template>
<u-popup
:show="showShare"
mode="center"
bgColor="transparent"
closeable
@close="closeShare"
>
<view class="box-share">
<view class="box-img">
<image :src="posterUrl" class="main-img" mode="widthFix" />
</view>
<image
:src="webUrl + '/20230608112210135038.png'"
mode="widthFix"
class="btn"
@click="saveImg"
/>
</view>
</u-popup>
</template>
<script>
export default {
data() {
return {
webUrl: this.$VUE_APP_RESOURCES_URL,
posterUrl: '',
showShare: false
}
},
methods: {
closeShare() {
this.showShare = false
},
showView(url) {
this.posterUrl = url
this.showShare = true
},
saveImg() {
const _this = this
uni.getSetting({
success: getRes => {
if (getRes.authSetting["scope.writePhotosAlbum"]) {
_this.downloadImage()
} else {
uni.authorize({
scope: "scope.writePhotosAlbum",
success: () => {
_this.downloadImage()
},
fail: () => {
uni.openSetting({
success: openRes => {
console.log(typeof openRes, openRes)
},
fail: () => {
uni.showToast({
title: "请在设置中打开对应权限",
icon: "none"
})
}
})
}
})
}
},
fail: (err) => {
console.log(err, 2)
}
})
},
downloadImage() {
const _this = this
const randomID = () => Math.random().toString(36).substring(2)
uni.downloadFile({
url: this.posterUrl, // 网络图片的地址
filePath: wx.env.USER_DATA_PATH + "/share_" + randomID() + ".png", // 指定的本地文件路径
success: downRes => {
uni.saveImageToPhotosAlbum({
filePath: downRes.filePath, // 临时文件地址
success: function () {
uni.showToast({
title: "保存成功",
icon: "success",
success() {
_this.showShare = false
}
})
},
fail: function (err) {
uni.showToast({
title: err,
icon: "none"
})
}
})
},
fail: function (err) {
uni.showToast({
title: err.errMsg,
icon: "error"
})
}
})
}
}
}
</script>
<style lang="less" scoped>
.box-share {
width: 600rpx;
border-radius: 20rpx;
overflow: hidden;
}
.box-img {
display: flex;
align-items: center;
justify-content: center;
}
.btn {
width: 100%;
height: 80rpx;
line-height: 80rpx;
margin-top: 40rpx;
}
</style>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,143 @@
/* eslint-disable */
var provinceData = [{
"label": "北京市",
"value": "11"
},
{
"label": "天津市",
"value": "12"
},
{
"label": "河北省",
"value": "13"
},
{
"label": "山西省",
"value": "14"
},
{
"label": "内蒙古自治区",
"value": "15"
},
{
"label": "辽宁省",
"value": "21"
},
{
"label": "吉林省",
"value": "22"
},
{
"label": "黑龙江省",
"value": "23"
},
{
"label": "上海市",
"value": "31"
},
{
"label": "江苏省",
"value": "32"
},
{
"label": "浙江省",
"value": "33"
},
{
"label": "安徽省",
"value": "34"
},
{
"label": "福建省",
"value": "35"
},
{
"label": "江西省",
"value": "36"
},
{
"label": "山东省",
"value": "37"
},
{
"label": "河南省",
"value": "41"
},
{
"label": "湖北省",
"value": "42"
},
{
"label": "湖南省",
"value": "43"
},
{
"label": "广东省",
"value": "44"
},
{
"label": "广西壮族自治区",
"value": "45"
},
{
"label": "海南省",
"value": "46"
},
{
"label": "重庆市",
"value": "50"
},
{
"label": "四川省",
"value": "51"
},
{
"label": "贵州省",
"value": "52"
},
{
"label": "云南省",
"value": "53"
},
{
"label": "西藏自治区",
"value": "54"
},
{
"label": "陕西省",
"value": "61"
},
{
"label": "甘肃省",
"value": "62"
},
{
"label": "青海省",
"value": "63"
},
{
"label": "宁夏回族自治区",
"value": "64"
},
{
"label": "新疆维吾尔自治区",
"value": "65"
},
{
"label": "台湾",
"value": "66"
},
{
"label": "香港",
"value": "67"
},
{
"label": "澳门",
"value": "68"
},
{
"label": "钓鱼岛",
"value": "69"
}
]
export default provinceData;
@@ -0,0 +1,381 @@
<template>
<view class="simple-address" v-if="showPopup" @touchmove.stop.prevent="clear">
<!-- 遮罩层 -->
<view
class="simple-address-mask"
@touchmove.stop.prevent="clear"
v-if="maskClick"
:class="[ani + '-mask', animation ? 'mask-ani' : '']"
:style="{
'background-color': maskBgColor
}"
@tap="hideMask(true)"
></view>
<view class="simple-address-content simple-address--fixed" :class="[type, ani + '-content', animation ? 'content-ani' : '']">
<view class="simple-address__header">
<view class="simple-address__header-btn-box" @click="pickerCancel"><text class="simple-address__header-text">取消</text></view>
<view class="simple-address__header-btn-box" @click="pickerConfirm"><text class="simple-address__header-text" :style="{ color: themeColor }">确定</text></view>
</view>
<view class="simple-address__box">
<picker-view indicator-style="height: 70rpx;" class="simple-address-view" :value="pickerValue" @change="pickerChange">
<picker-view-column>
<!-- #ifndef APP-NVUE -->
<view class="picker-item" v-for="(item, index) in provinceDataList" :key="index">{{ item.label }}</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<text class="picker-item" v-for="(item, index) in provinceDataList" :key="index">{{ item.label }}</text>
<!-- #endif -->
</picker-view-column>
<picker-view-column>
<!-- #ifndef APP-NVUE -->
<view class="picker-item" v-for="(item, index) in cityDataList" :key="index">{{ item.label }}</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<text class="picker-item" v-for="(item, index) in cityDataList" :key="index">{{ item.label }}</text>
<!-- #endif -->
</picker-view-column>
<picker-view-column>
<!-- #ifndef APP-NVUE -->
<view class="picker-item" v-for="(item, index) in areaDataList" :key="index">{{ item.label }}</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<text class="picker-item" v-for="(item, index) in areaDataList" :key="index">{{ item.label }}</text>
<!-- #endif -->
</picker-view-column>
</picker-view>
</view>
</view>
</view>
</template>
<script>
import provinceData from './city-data/province.js';
import cityData from './city-data/city.js';
import areaData from './city-data/area.js';
export default {
name: 'simpleAddress',
props: {
mode: {
// 地址类型
// default 则代表老版本根据index索引获取数据
//
type: String,
default: 'default'
},
// 开启动画
animation: {
type: Boolean,
default: true
},
/* 弹出层类型,可选值;
bottom:底部弹出层
*/
type: {
type: String,
default: 'bottom'
},
// maskClick
maskClick: {
type: Boolean,
default: true
},
show: {
type: Boolean,
default: true
},
maskBgColor: {
type: String,
default: 'rgba(0, 0, 0, 0.4)' //背景颜色 rgba(0, 0, 0, 0.4) 为空则调用 uni.scss
},
themeColor: {
type: String,
default: '' // 主题色
},
/* 默认值 */
pickerValueDefault: {
type: Array,
default() {
return [0, 0, 0];
}
}
},
data() {
return {
ani: '',
showPopup: false,
pickerValue: [0, 0, 0],
provinceDataList: [],
cityDataList: [],
areaDataList: []
};
},
watch: {
show(newValue) {
if (newValue) {
this.open();
} else {
this.close();
}
},
pickerValueDefault() {
this.init();
}
},
created() {
this.init();
},
methods: {
init() {
this.handPickValueDefault(); // 对 pickerValueDefault 做兼容处理
this.provinceDataList = provinceData;
this.cityDataList = cityData[this.pickerValueDefault[0]];
this.areaDataList = areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]];
this.pickerValue = this.pickerValueDefault;
},
handPickValueDefault() {
if (this.pickerValueDefault !== [0, 0, 0]) {
if (this.pickerValueDefault[0] > provinceData.length - 1) {
this.pickerValueDefault[0] = provinceData.length - 1;
}
if (this.pickerValueDefault[1] > cityData[this.pickerValueDefault[0]].length - 1) {
this.pickerValueDefault[1] = cityData[this.pickerValueDefault[0]].length - 1;
}
if (this.pickerValueDefault[2] > areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]].length - 1) {
this.pickerValueDefault[2] = areaData[this.pickerValueDefault[0]][this.pickerValueDefault[1]].length - 1;
}
}
},
pickerChange(e) {
let changePickerValue = e.detail.value;
if (this.pickerValue[0] !== changePickerValue[0]) {
// 第一级发生滚动
this.cityDataList = cityData[changePickerValue[0]];
this.areaDataList = areaData[changePickerValue[0]][0];
changePickerValue[1] = 0;
changePickerValue[2] = 0;
} else if (this.pickerValue[1] !== changePickerValue[1]) {
// 第二级滚动
this.areaDataList = areaData[changePickerValue[0]][changePickerValue[1]];
changePickerValue[2] = 0;
}
this.pickerValue = changePickerValue;
this._$emit('onChange');
},
_$emit(emitName) {
let pickObj = {
label: this._getLabel(),
value: this.pickerValue,
cityCode: this._getCityCode(),
areaCode: this._getAreaCode(),
provinceCode: this._getProvinceCode(),
labelArr:this._getLabel().split('-')
};
console.log(this._getLabel().split('-'));
this.$emit(emitName, pickObj);
},
_getLabel() {
let pcikerLabel =
this.provinceDataList[this.pickerValue[0]].label + '-' + this.cityDataList[this.pickerValue[1]].label + '-' + this.areaDataList[this.pickerValue[2]].label;
return pcikerLabel;
},
_getCityCode() {
return this.cityDataList[this.pickerValue[1]].value;
},
_getProvinceCode() {
return this.provinceDataList[this.pickerValue[0]].value;
},
_getAreaCode() {
return this.areaDataList[this.pickerValue[2]].value;
},
queryIndex(params = [], type = 'value') {
// params = [ 11 ,1101,110101 ];
// 1.获取省份的index
let provinceIndex = provinceData.findIndex(res => res[type] == params[0]);
let cityIndex = cityData[provinceIndex].findIndex(res => res[type] == params[1]);
let areaIndex = areaData[provinceIndex][cityIndex].findIndex(res => res[type] == params[2]);
return {
index: [provinceIndex, cityIndex, areaIndex],
data: {
province: provinceData[provinceIndex],
city: cityData[provinceIndex][cityIndex],
area: areaData[cityIndex][0][areaIndex]
}
};
},
clear() {},
hideMask() {
this._$emit('onCancel');
this.close();
},
pickerCancel() {
this._$emit('onCancel');
this.close();
},
pickerConfirm() {
this._$emit('onConfirm');
this.close();
},
open() {
this.showPopup = true;
this.$nextTick(() => {
setTimeout(() => {
this.ani = 'simple-' + this.type;
}, 100);
});
},
close(type) {
if (!this.maskClick && type) return;
this.ani = '';
this.$nextTick(() => {
setTimeout(() => {
this.showPopup = false;
}, 300);
});
}
}
};
</script>
<style lang="scss" scoped>
.simple-address {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.simple-address-mask {
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
transition-property: opacity;
transition-duration: 0.3s;
opacity: 0;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.mask-ani {
transition-property: opacity;
transition-duration: 0.2s;
}
.simple-bottom-mask {
opacity: 1;
}
.simple-center-mask {
opacity: 1;
}
.simple-address--fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
transition-property: transform;
transition-duration: 0.3s;
transform: translateY(460rpx);
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.simple-address-content {
background-color: #ffffff;
}
.simple-content-bottom {
bottom: 0;
left: 0;
right: 0;
transform: translateY(500rpx);
}
.content-ani {
transition-property: transform, opacity;
transition-duration: 0.2s;
}
.simple-bottom-content {
transform: translateY(0);
}
.simple-center-content {
transform: scale(1);
opacity: 1;
}
.simple-address__header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
border-bottom-color: #f2f2f2;
border-bottom-style: solid;
border-bottom-width: 1rpx;
}
.simple-address--fixed-top {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 1rpx;
}
.simple-address__header-btn-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 70rpx;
}
.simple-address__header-text {
text-align: center;
font-size: $uni-font-size-base;
color: #1aad19;
line-height: 70rpx;
padding-left: 40rpx;
padding-right: 40rpx;
}
.simple-address__box {
position: relative;
}
.simple-address-view {
position: relative;
bottom: 0;
left: 0;
/* #ifndef APP-NVUE */
width: 100%;
/* #endif */
/* #ifdef APP-NVUE */
width: 750rpx;
/* #endif */
height: 408rpx;
background-color: rgba(255, 255, 255, 1);
}
.picker-item {
text-align: center;
line-height: 70rpx;
text-overflow: ellipsis;
font-size: 28rpx;
}
</style>
-87
View File
@@ -1,87 +0,0 @@
### 使用组件
```html
<time-picker-popup ref="TimePickerPopupRef" :value="value" @confirm="confirm"></time-picker-popup>
```
### 引入组件
```javascript
import TimePickerPopup from '@/components/time-picker-popup/time-picker-popup.vue';
```
### 注册组件
```javascript
export default {
components: { TimePickerPopup },
data() {
return {
value: ['00', '00', '00', '00']
}
},
onReady() {
this.open();
},
methods: {
confirm(data) {
uni.showToast({
title: `${data[0]}:${data[1]}-${data[2]}:${data[3]}`
})
},
open() {
this.$refs.TimePickerPopupRef.open();
}
}
}
```
### 参数
```javascript
// 当前选中的值
value: {
type: Array,
default: () => (['00', '00', '00', '00'])
},
// 标题
title: {
type: String,
default: '时间'
},
// 取消按钮文字
cancelText: {
type: String,
default: '取消'
},
// 取消按钮颜色
canceColor: {
type: String,
default: '#666666'
},
// 确定按钮文字
confirmText: {
type: String,
default: '确定'
},
// 确定按钮颜色
confirmColor: {
type: String,
default: '#2bb781'
},
// 分割符
segmentation: {
type: String,
default: '-'
},
// 设置选择器中间选中框的类名 注意页面或组件的style中写了scoped时,需要在类名前写/deep/
indicatorClass: {
type: String,
default: 'picker-view__indicator'
},
// 设置选择器中间选中框的样式
indicatorStyle: {
type: String,
default: ''
},
```
@@ -1,159 +0,0 @@
<template>
<!-- 时间选择器弹窗 -->
<uni-popup ref="popup" type="bottom" :safe-area="false">
<view class="custom-picker">
<view class="custom-picker__header">
<view class="cancel" :style="{ color: canceColor }" @tap="onCancel">{{ cancelText }}</view>
<view class="title">{{ title }}</view>
<view class="confirm" :style="{ color: confirmColor }" @tap="onConfirm">{{ confirmText }}</view>
</view>
<picker-view :indicator-class="indicatorClass" :indicator-style="indicatorStyle" class="picker-view"
:value="value" @change="bindChange" @pickstart="pickstart" @pickend="pickend">
<picker-view-column>
<view class="picker-view__item" v-for="(item,index) in rangeList[0]" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-view__item" v-for="(item,index) in rangeList[1]" :key="index">{{item}}</view>
</picker-view-column>
<view class="picker-view__segmentation">{{ segmentation }}</view>
<picker-view-column>
<view class="picker-view__item" v-for="(item,index) in rangeList[2]" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-view__item" v-for="(item,index) in rangeList[3]" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
</view>
</uni-popup>
</template>
<script>
import utils, {
props,
range
} from './utils.js';
export default {
name: 'TimePickerPopup',
props: props,
data() {
return {
rangeList: utils.range,
pickerValue: [0, 0, 0, 0],
isScoll: false, // 是否正在滚动
}
},
methods: {
/**
* 开启弹窗
*/
open() {
// 判断是否传入props -> value
if (Array.isArray(this.value) && this.value.length) {
this.pickerValue = this.value.map((item, index) => this.rangeList[index].findIndex(child =>
child == this.value[index]));
} else {
this.pickerValue = [0, 0, 0, 0];
}
this.$refs.popup.open();
},
/**
* 关闭弹窗
*/
close() {
this.$refs.popup.close();
// 重置选中数据
this.pickerValue = [0, 0, 0, 0];
},
/**
* 点击确定
*/
onConfirm() {
if (!this.isScoll) {
let data = this.value || ['00', '00', '00', '00'];
if (this.pickerValue && this.pickerValue.length) {
data = this.pickerValue.map((item, index) => String(this.rangeList[index][item]));
}
this.$emit('confirm', data);
this.close();
}
},
/**
* 点击取消
*/
onCancel() {
this.close();
},
/**
* 滚动开始
*/
pickstart() {
this.isScoll = true;
},
/**
* 滚动结束
*/
pickend() {
this.isScoll = false;
},
/**
* 选择器改变
* @param {Object} e
*/
bindChange(e) {
this.pickerValue = e.detail.value;
},
}
}
</script>
<style lang="scss" scoped>
.custom-picker {
width: 100%;
height: 620rpx;
background-color: #fff;
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
&__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx 40rpx;
.cancel {
color: #666;
}
.title {
font-size: 32rpx;
color: #333;
}
.confirm {
color: #2bb781;
}
}
}
.picker-view {
width: 100%;
height: 100%;
margin-top: 20rpx;
&__item {
line-height: 100rpx;
text-align: center;
}
/deep/ &__indicator {
height: 100rpx;
color: #2bb781;
}
&__segmentation {
display: flex;
align-items: center;
}
}
</style>
-69
View File
@@ -1,69 +0,0 @@
// 组件props
const props = {
// 当前选中的值
value: {
type: Array,
default: () => (['00', '00', '00', '00'])
},
// 标题
title: {
type: String,
default: '时间'
},
// 取消按钮文字
cancelText: {
type: String,
default: '取消'
},
// 取消按钮颜色
canceColor: {
type: String,
default: '#666666'
},
// 确定按钮文字
confirmText: {
type: String,
default: '确定'
},
// 确定按钮颜色
confirmColor: {
type: String,
default: '#2bb781'
},
// 分割符
segmentation: {
type: String,
default: '-'
},
// 设置选择器中间选中框的类名 注意页面或组件的style中写了scoped时,需要在类名前写/deep/
indicatorClass: {
type: String,
default: 'picker-view__indicator'
},
// 设置选择器中间选中框的样式
indicatorStyle: {
type: String,
default: ''
},
}
// 滚动数据
let range = [
[],
[],
[],
[]
];
for (let i = 0; i < 24; i++) {
range[0].push(i >= 10 ? String(i) : `0${i}`);
range[2].push(i >= 10 ? String(i) : `0${i}`);
}
for (let i = 0; i < 60; i++) {
range[1].push(i >= 10 ? String(i) : `0${i}`);
range[3].push(i >= 10 ? String(i) : `0${i}`);
}
export default {
props,
range
}
+7 -15
View File
@@ -7,11 +7,11 @@
class="sunui-uploader-file" class="sunui-uploader-file"
/> />
<block v-for="(item, index) in upload_before_list" :key="index"> <block v-for="(item, index) in upload_before_list" :key="index">
<view class="sunui-uploader-file" :class="[item.upload_percent < 100 ? '' : '']" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'"> <view class="sunui-uploader-file" :class="[item.upload_percent < 100 ? 'sunui-uploader-file-status' : '']" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'">
<image class="sunui-uploader-img" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'" :src="item.path" mode="aspectFill" @tap="preview(index)" v-if="type === 'image'" /> <image class="sunui-uploader-img" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'" :src="item.path" mode="aspectFill" @tap="preview(index)" v-if="type === 'image'" />
<video :id="`myVideo_${index}`" :src="item.path" :data-index="index" @play="videoPlay" @error="videoError" controls :enable-play-gesture="true" objectFit="contain" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'" v-if="type === 'video'"></video> <video :id="`myVideo_${index}`" :src="item.path" :data-index="index" @play="videoPlay" @error="videoError" controls :enable-play-gesture="true" objectFit="contain" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'" v-if="type === 'video'"></video>
<view class="sunui-img-removeicon right" @tap.stop="remove(index)" v-show="upimg_move">x</view> <view class="sunui-img-removeicon right" @tap.stop="remove(index)" v-show="upimg_move">x</view>
<!-- <view class="sunui-loader-filecontent" v-if="item.upload_percent < 100">{{item.upload_percent}}%</view> --> <view class="sunui-loader-filecontent" v-if="item.upload_percent < 100">{{item.upload_percent}}%</view>
</view> </view>
</block> </block>
<view v-show="upload_before_list.length < upload_count" hover-class="sunui-uploader-hover" class="sunui-uploader-inputbox" @tap="choose" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'"> <view v-show="upload_before_list.length < upload_count" hover-class="sunui-uploader-hover" class="sunui-uploader-inputbox" @tap="choose" :style="'width:' + upload_img_wh + 'rpx; height:' + upload_img_wh + 'rpx;'">
@@ -139,10 +139,10 @@ export default {
} }
}, },
videoError(e) { videoError(e) {
// uni.showModal({ uni.showModal({
// content: '网络错误,请稍后重试!', content: '网络错误,请稍后重试!',
// showCancel: false showCancel: false
// }); });
}, },
uploadFile(paths) { uploadFile(paths) {
const promises = paths.map((path) => { const promises = paths.map((path) => {
@@ -185,7 +185,6 @@ export default {
if (Math.ceil(res.size / 1024) < this.upload_video_max * 1024) { if (Math.ceil(res.size / 1024) < this.upload_video_max * 1024) {
await this.upload_img_size.push(Math.ceil(res.size / 1024)); await this.upload_img_size.push(Math.ceil(res.size / 1024));
await this.upload_before_list.push(res); await this.upload_before_list.push(res);
this.$forceUpdate()
} else { } else {
this.upload_exceeded_list.push(1); this.upload_exceeded_list.push(1);
@@ -220,7 +219,6 @@ export default {
if (Math.ceil(res.tempFiles[i].size / 1024) < this.upload_max * 1024) { if (Math.ceil(res.tempFiles[i].size / 1024) < this.upload_max * 1024) {
await this.upload_img_size.push(Math.ceil(res.tempFiles[i].size / 1024)); await this.upload_img_size.push(Math.ceil(res.tempFiles[i].size / 1024));
await this.upload_before_list.push(res.tempFiles[i]); await this.upload_before_list.push(res.tempFiles[i]);
this.$forceUpdate()
// TODO v3.1增加图片格式限制 // TODO v3.1增加图片格式限制
} else { } else {
res.tempFilePaths.splice(i, 1); res.tempFilePaths.splice(i, 1);
@@ -241,7 +239,6 @@ export default {
} }
this.upload_cache = await res.tempFilePaths; this.upload_cache = await res.tempFilePaths;
this.upload(this.upload_auto); this.upload(this.upload_auto);
this.$forceUpdate()
}, },
fail: (err) => { fail: (err) => {
console.log(err); console.log(err);
@@ -341,12 +338,7 @@ export default {
uploadTask.onProgressUpdate(async (res) => { uploadTask.onProgressUpdate(async (res) => {
// this.upload_before_list[this.upload_before_list.length-1].upload_percent = await res.progress; // this.upload_before_list[this.upload_before_list.length-1].upload_percent = await res.progress;
for (let i in this.upload_before_list) { for(let i in this.upload_before_list) { if(this.upload_before_list[i].upload_percent != 100) { this.upload_before_list[i].upload_percent = await res.progress; break; } };
if (this.upload_before_list[i].upload_percent != 100) {
console.log(res.progress, '-----------res.progress-----------');
this.upload_before_list[i].upload_percent = await res.progress
}
};
}); });
} }
} }
@@ -1,321 +0,0 @@
<template>
<u-popup :closeOnClickOverlay="true" :show="show" ref="popup" type="bottom">
<view class="tpf-time-range-section">
<view class="tpf-time-range-title-section flex flex-align-center flex-pack-justify">
<text class="tpf-time-range-title-txt tpf-time-range-cancel" @tap="closePopup('cancel')">取消</text>
<text class="tpf-time-range-title-txt tpf-time-range-title">营业时间</text>
<text class="tpf-time-range-title-txt tpf-time-range-sure" @tap="closePopup('sure')">确定</text>
</view>
<view class="tpf-time-range-main flex flex-l flex-align-center flex-pack-justify">
<view class="tpf-time-range-item flex flex-v flex-align-center">
<picker-view class="flex-1 tpf-picker-view" :value="startDefaultTimeArr" indicator-style="height: 50px;" @change="startTimeChange">
<picker-view-column>
<view class="tpf-time-range-picker-item flex flex-align-center flex-pack-center" v-for="(item,index) in createTimeRange.hours" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="tpf-time-range-picker-item flex flex-align-center flex-pack-center" v-for="(item,index) in createTimeRange.startMinutes" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
</view>
<text class="tpf-time-divide"> - </text>
<view class="tpf-time-range-item flex flex-v flex-align-center">
<picker-view class="flex-1 tpf-picker-view" :value="endDefaultTimeArr" indicator-style="height: 50px;" @change="endTimeChange">
<picker-view-column>
<view class="tpf-time-range-picker-item flex flex-align-center flex-pack-center" v-for="(item,index) in createTimeRange.hours" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="tpf-time-range-picker-item flex flex-align-center flex-pack-center" v-for="(item,index) in createTimeRange.endMinutes" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
</view>
</view>
</view>
</u-popup>
</template>
<script>
/**
* TimeRange 时间范围选择
* @description 对时间(时、分)区间进行选择,限制选择范围
* @property {string} startTime 定义开始时间
* @property {string} startDefaultTime 定义开始默认时间
* @property {string} endTime 定义结束时间
* @property {string} endDefaultTime 定义结束默认时间
* @event {Function()} name
*/
export default{
name:"TpfTimeRange",
props:{
// 开始时间
startTime:{
type:String,
default:"00:00",
validator:(value)=>{
return /(((2[0-3])|([0-1][0-9])):[0-5][0-9])|24:00/.test(value);
}
},
// 开始默认时间
startDefaultTime:{
type:String,
// #ifdef MP-WEIXIN
default:"00:00",
// #endif
// #ifndef MP-WEIXIN
default(){
return this.startTime;
},
// #endif
validator:(value)=>{
return /(((2[0-3])|([0-1][0-9])):[0-5][0-9])|24:00/.test(value);
}
},
// 结束时间
endTime:{
type:String,
default:"23:59",
validator:(value)=>{
return /(((2[0-3])|([0-1][0-9])):[0-5][0-9])|24:00/.test(value);
}
},
// 结束默认时间
endDefaultTime:{
type:String,
// #ifdef MP-WEIXIN
default:"23:59",
// #endif
// #ifndef MP-WEIXIN
default(){
return this.endTime;
},
// #endif
validator:(value)=>{
return /(((2[0-3])|([0-1][0-9])):[0-5][0-9])|24:00/.test(value);
}
}
},
data(){
return {
startDefaultTimeArr:[0,0],
endDefaultTimeArr:[0,0],
show: false
}
},
methods:{
startTimeChange(e){
this.startDefaultTimeArr = e.detail.value;
if(this.compareTwoTimeRange(e.detail.value,this.endDefaultTimeArr)) this.endDefaultTimeArr = e.detail.value;
},
endTimeChange(e){
this.endDefaultTimeArr = e.detail.value;
if(this.compareTwoTimeRange(this.startDefaultTimeArr,e.detail.value)) this.startDefaultTimeArr = e.detail.value;
},
open(){
this.show = true;
},
closePopup(action=""){
if(action == "cancel"){
this.show = false;
return false;
}
if(this.compareTwoTimeRange(this.startDefaultTimeArr , this.endDefaultTimeArr)){
uni.showToast({
title:"开始时间不能大于结束时间",
icon:'none'
});
return false;
}
let startTime = this.createTimeRange.hours[this.startDefaultTimeArr[0]]+":"+this.createTimeRange.startMinutes[this.startDefaultTimeArr[1]];
let endTime = this.createTimeRange.hours[this.endDefaultTimeArr[0]]+":"+this.createTimeRange.endMinutes[this.endDefaultTimeArr[1]];
this.$emit('timeRange',[
startTime,endTime
]);
this.show = false;
},
compareTwoTimeRange(arr1=[],arr2=[]){
if(arr1[0]>arr2[0] || (arr1[0] == arr2[0] && arr1[1] > arr2[1])) return true;
return false;
},
},
beforeCreate(){
// 初始化小时
let hour = [],minute=[];
for(let h=0;h<=24;h++){
hour.push(h<10?'0'+h:h+'');
}
for(let m=0;m<60;m++){
minute.push(m<10?'0'+m:m+'');
}
this.timeRange = {hour,minute};
},
created() {
},
computed:{
createTimeRange(){
let {startTime,startDefaultTime,endTime,endDefaultTime} = this.timeRangeDateChange;
let startTimeArr = startTime.split(":"),endTimeArr = endTime.split(":");
let hours = this.timeRange.hour.slice(
this.timeRange.hour.findIndex(item=>item == startTimeArr[0]),
this.timeRange.hour.findIndex(item=>item == endTimeArr[0])+1,
);
let startMinutes = null;
if(startTimeArr[0] == endTimeArr[0]){
startMinutes = this.timeRange.minute.slice(
this.timeRange.minute.findIndex(item=>item == startTimeArr[1]),
this.timeRange.minute.findIndex(item=>item == endTimeArr[1])+1,
);
}else{
if(this.startDefaultTimeArr[0] == 0){
startMinutes = this.timeRange.minute.slice(
this.timeRange.minute.findIndex(item=>item == startTimeArr[1])
);
}
else if(this.startDefaultTimeArr[0] == hours.length-1){
startMinutes = this.timeRange.minute.slice(
0,
this.timeRange.minute.findIndex(item=>item == endTimeArr[1])+1
);
}else{
startMinutes = this.timeRange.minute; // 完整数据
}
}
let endMinutes = null;
if(startTimeArr[0] == endTimeArr[0]){
endMinutes = this.timeRange.minute.slice(
this.timeRange.minute.findIndex(item=>item == startTimeArr[1]),
this.timeRange.minute.findIndex(item=>item == endTimeArr[1])+1,
);
}
else{
if(this.endDefaultTimeArr[0] == 0){
endMinutes = this.timeRange.minute.slice(
this.timeRange.minute.findIndex(item=>item == startTimeArr[1])
);
}
else if(this.endDefaultTimeArr[0] == hours.length-1){
endMinutes = this.timeRange.minute.slice(
0,
this.timeRange.minute.findIndex(item=>item == endTimeArr[1])+1
);
}else{
endMinutes = this.timeRange.minute; // 完整数据
}
}
return {
hours,
startMinutes,
endMinutes,
}
},
// 用于监听属性的变化
timeRangeDateChange(){
let {startTime,startDefaultTime,endTime,endDefaultTime} = this;
startTime = startTime<endTime?startTime:endTime;
startDefaultTime = startDefaultTime>=startTime && startDefaultTime<=endTime?startDefaultTime:startTime;
endDefaultTime = endDefaultTime>=startTime && endDefaultTime<=endTime && endDefaultTime>=startDefaultTime?endDefaultTime:startDefaultTime;
return {
startTime,
startDefaultTime,
endTime,
endDefaultTime
}
}
},
watch:{
timeRangeDateChange:{
handler(newVal,oldVal){
let {startTime,startDefaultTime,endTime,endDefaultTime} = newVal;
let startTimeArr = startTime.split(":"),endTimeArr = endTime.split(":");
let startDefaultTimeArr = startDefaultTime.split(":"),endDefaultTimeArr = endDefaultTime.split(":");
let hours = this.timeRange.hour.slice(
this.timeRange.hour.findIndex(item=>item == startTimeArr[0]),
this.timeRange.hour.findIndex(item=>item == endTimeArr[0])+1,
);
this.$set(this.startDefaultTimeArr,0, hours.includes(startDefaultTimeArr[0])?hours.findIndex(item=>item == startDefaultTimeArr[0]):0);
this.$set(this.endDefaultTimeArr,0, hours.includes(endDefaultTimeArr[0])?hours.findIndex(item=>item == endDefaultTimeArr[0]):this.startDefaultTimeArr[0]);
let startMinute = null,endMinute = null;
if(startTimeArr[0] == endTimeArr[0]){
startMinute = endMinute = this.timeRange.minute.slice(
this.timeRange.minute.findIndex(item=>item == startTimeArr[1]),
this.timeRange.minute.findIndex(item=>item == endTimeArr[1])+1,
);
}
else{
if(startDefaultTime.split(":")[0] == startTimeArr[0]){
startMinute = this.timeRange.minute.slice(
this.timeRange.minute.findIndex(item=>item == startTimeArr[1]),
);
}
else if(startDefaultTime.split(":")[0] == endTimeArr[0]){
startMinute = this.timeRange.minute.slice(
0,
this.timeRange.minute.findIndex(item=>item == endTimeArr[1])+1,
);
}else{
startMinute = this.timeRange.minute;
}
if(endDefaultTime.split(":")[0] == startTimeArr[0]){
endMinute = this.timeRange.minute.slice(
this.timeRange.minute.findIndex(item=>item == startTimeArr[1]),
);
}else if(endDefaultTime.split(":")[0] == endTimeArr[0]){
endMinute = this.timeRange.minute.slice(
0,
this.timeRange.minute.findIndex(item=>item == endTimeArr[1])+1,
);
}else{
endMinute = this.timeRange.minute;
}
}
this.$set(this.startDefaultTimeArr,1, startMinute.includes(startDefaultTimeArr[1])?startMinute.findIndex(item=>item == startDefaultTimeArr[1]):0);
this.$set(this.endDefaultTimeArr,1, endMinute.includes(endDefaultTimeArr[1])?endMinute.findIndex(item=>item == endDefaultTimeArr[1]):this.startDefaultTimeArr[1]);
},
deep:true, // 深度监听
immediate:true, // 初始化立即执行
}
}
}
</script>
<style lang="scss">
.flex{display:flex;}
.flex-v{flex-direction:column;}
.flex-wrap{flex-wrap:wrap;}
.flex-row-wrap{flex-flow:row wrap;}
.flex-1{flex:1;}
.flex-align-center{align-items:center;}
.flex-pack-center{justify-content:center;}
.flex-pack-justify{justify-content:space-between;}
.flex-pack-around{justify-content:space-around;}
.tpf-time-range-section{
background-color: #FFF;
}
.tpf-time-range-title-section{
padding: 20rpx;
border-bottom: 1px #f2f2f2 solid;
}
.tpf-time-range-title-txt{
font-size: 28rpx;
}
.tpf-time-range-title{
font-size:32rpx;
}
.tpf-time-range-main{
padding: 0 20rpx 20rpx;
}
.tpf-time-range-item{
height: 400rpx;
width: 300rpx;
}
.tpf-start-time{
padding: 20rpx 0;
}
.tpf-picker-view{
width:280rpx;
}
</style>
@@ -0,0 +1,134 @@
<template>
<view :class="[styleType === 'text'?'segmented-control--text' : 'segmented-control--button' ]" :style="{ borderColor: styleType === 'text' ? '' : activeColor }"
class="segmented-control">
<view v-for="(item, index) in values" :class="[ styleType === 'text'?'segmented-control__item--text': 'segmented-control__item--button' , index === currentIndex&&styleType === 'button'?'segmented-control__item--button--active': '' , index === 0&&styleType === 'button'?'segmented-control__item--button--first': '',index === values.length - 1&&styleType === 'button'?'segmented-control__item--button--last': '' ]"
:key="index" :style="{
backgroundColor: index === currentIndex && styleType === 'button' ? activeColor : '',borderColor: index === currentIndex&&styleType === 'text'||styleType === 'button'?activeColor:'transparent'
}"
class="segmented-control__item" @click="_onClick(index)">
<text :style="{color:
index === currentIndex
? styleType === 'text'
? activeColor
: '#fff'
: styleType === 'text'
? '#000'
: activeColor}"
class="segmented-control__text">{{ item }}</text>
</view>
</view>
</template>
<script>
/**
* SegmentedControl 分段器
* @description 用作不同视图的显示
* @tutorial https://ext.dcloud.net.cn/plugin?id=54
* @property {Number} current 当前选中的tab索引值,从0计数
* @property {String} styleType = [button|text] 分段器样式类型
* @value button 按钮类型
* @value text 文字类型
* @property {String} activeColor 选中的标签背景色与边框颜色
* @property {Array} values 选项数组
* @event {Function} clickItem 组件触发点击事件时触发,e={currentIndex}
*/
export default {
name: 'UniSegmentedControl',
props: {
current: {
type: Number,
default: 0
},
values: {
type: Array,
default () {
return []
}
},
activeColor: {
type: String,
default: '#007aff'
},
styleType: {
type: String,
default: 'button'
}
},
data() {
return {
currentIndex: 0
}
},
watch: {
current(val) {
if (val !== this.currentIndex) {
this.currentIndex = val
}
}
},
created() {
this.currentIndex = this.current
},
methods: {
_onClick(index) {
if (this.currentIndex !== index) {
this.currentIndex = index
this.$emit('clickItem', {
currentIndex: index
})
}
}
}
}
</script>
<style lang="scss" scoped>
.segmented-control {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
height: 50rpx;
overflow: hidden;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.segmented-control__item {
/* #ifndef APP-NVUE */
display: inline-flex;
box-sizing: border-box;
/* #endif */
position: relative;
flex: 1;
justify-content: center;
align-items: center;
padding: 10rpx;
}
.segmented-control__item--button {
border-style: solid;
border-top-width: 1px;
border-bottom-width: 1px;
border-right-width: 1px;
border-left-width: 0;
}
.segmented-control__item--button--first {
border-left-width: 1px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.segmented-control__item--button--last {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.segmented-control__item--text {
border-bottom-style: solid;
border-bottom-width: 3px;
}
.segmented-control__text {
font-size: 28rpx;
line-height: 28rpx;
text-align: center;
}
</style>
+3 -85
View File
@@ -2,71 +2,26 @@
<view class="xdd-product-item" @click="viewHandle(item)"> <view class="xdd-product-item" @click="viewHandle(item)">
<view class="focus-img"> <view class="focus-img">
<image <image
v-if="!item.isFarmerShop"
:src="item[imageKey]" :src="item[imageKey]"
class="img" class="img"
lazy-load
/> />
<image
:src="item.farmerShopCover"
v-if="item.farmerShopCoverType === 1 && item.isFarmerShop"
class="img"
mode="heightFix|widthFix"
lazy-load
/>
<image
:src="item.farmerShopCover + '?vframe/jpg/offset/1'"
mode="heightFix|widthFix"
v-if="item.farmerShopCoverType !== 1 && item.isFarmerShop"
:show-center-play-btn="false"
:show-fullscreen-btn="false"
:show-play-btn="false"
class="img"
:poster="item.farmerShopCover + '?vframe/jpg/offset/1'"
lazy-load
/>
<image <image
v-if="item.isOldBrand" v-if="item.isOldBrand"
:src="webUrl + '/home/old-mark.png'" :src="webUrl + '/home/old-mark.png'"
class="mark-img" class="mark-img"
lazy-load
/>
<image
v-if="item.isGiftCard"
style="left: 0;width: 120rpx;"
:src="webUrl + '/home/gift-tag.png'"
class="mark-img"
lazy-load
/> />
<image <image
v-if="item.isLandmarkGoods" v-if="item.isLandmarkGoods"
:src="webUrl + '/home/mark-land.png'" :src="webUrl + '/home/mark-land.png'"
class="mark-img" class="mark-img"
style="right: 20rpx"
lazy-load
/> />
<image <image
v-if="item.isCountyFamous" v-if="item.isCountyFamous"
:src="webUrl + '/home/qixian-mark.png'" :src="webUrl + '/home/qixian-mark.png'"
class="mark-img" class="mark-img"
lazy-load
/>
<image
v-if="item.isIch"
:src="webUrl + '/home/ich-mark.png'"
class="mark-img"
style="right: 20rpx; width: 70rpx"
/>
<image
v-if="item.isFarmerShop"
:src="webUrl + '/orderIcon/nm.png'"
class="mark-img-nm"
lazy-load
/> />
</view> </view>
<view v-if="item.isFarmerShop" class="more-t v12-pt-2 v12-font-bold v12-font-28 v12-px-2" >{{ item.farmerShopContent }}</view> <view class="info-wrap">
<view class="info-wrap" v-if="!item.isFarmerShop">
<view class="name more-t"> <view class="name more-t">
{{ item[nameKey] }} {{ item[nameKey] }}
</view> </view>
@@ -79,38 +34,16 @@
</view> </view>
<view class="price-wrap"> <view class="price-wrap">
<view class="price"> <view class="price">
<view <text class="price-txt price-red">{{ item[priceKey] }}</text>
v-if="item.isNegotiable === 1"
class="v12-primary-text v12-font-28 v12-font-weight"
>
价格面议
</view>
<text
v-else
class="price-txt price-red">
<text class="v12-font-20">
</text>
{{ item[priceKey] }}
</text>
</view> </view>
<view v-if="item.isNegotiable === 0" class="btn" @click.stop="$emit('add', item)"> <view class="btn">
<image <image
:src="webUrl + '/home/icon-cart.png'" :src="webUrl + '/home/icon-cart.png'"
class="img" class="img"
lazy-load
/> />
</view> </view>
</view> </view>
</view> </view>
<view
v-if="item.isFarmerShop"
class="v12-justify-start v12-align-center v12-pt-2 v12-px-2 v12-pb-2">
<view class="btn v12-mr-2">
<image :src="item.farmerShopLogo" class="nm-img-logo v12-radius-100" lazy-load />
</view>
<view class="one-t v12-font-24 v12-dark1-text" style="width:230rpx">{{ item.farmerShopName }}/{{ item.farmerShopCityName || '-' }}</view>
</view>
</view> </view>
</template> </template>
@@ -156,21 +89,6 @@ export default {
</script> </script>
<style lang="less"> <style lang="less">
.nm-img-logo {
display: block;
width: 48rpx;
height: 48rpx;
}
.mark-img-nm{
position: absolute;
top: 0;
right: 0;
z-index: 3;
display: block;
width: 100%;
height: 100%;
border-radius: 0 25rpx 0 0;
}
.xdd-product-item { .xdd-product-item {
border-radius: 20rpx; border-radius: 20rpx;
background-color: #fff; background-color: #fff;
+9 -123
View File
@@ -5,7 +5,7 @@
}" }"
class="xdd-tabbar-wrap" class="xdd-tabbar-wrap"
> >
<view class="center-img" id="quweiIcon" @click="switchTabFn('/pages/cloud/haveFun')"> <view class="center-img" @click="switchTabFn('/pages/cloud/haveFun')">
<image <image
:src="webUrl + '/home/tabbar-center.png'" :src="webUrl + '/home/tabbar-center.png'"
class="img" class="img"
@@ -13,7 +13,7 @@
<view <view
:class="currIndex === 4 ? 'curr' : ''" :class="currIndex === 4 ? 'curr' : ''"
class="name" class="name"
>吃喝玩乐</view> >寻趣味</view>
</view> </view>
<view class="tabbar-list"> <view class="tabbar-list">
<view <view
@@ -25,11 +25,11 @@
v-for="(item, index) in tabbarItem" v-for="(item, index) in tabbarItem"
:key="index" :key="index"
:class="currIndex === item.index ? 'curr' : ''" :class="currIndex === item.index ? 'curr' : ''"
:id="'icon' + index"
class="item" class="item"
@click="gotoPage(item.url, item.type, item.index)" @click="gotoPage(item.url, item.type, item.index)"
> >
<view class="img-wrap"> <view class="img-wrap">
<!-- 预加载两张图片可以在点击切换的时候不闪屏 -->
<image <image
:src="item.onIcon" :src="item.onIcon"
class="img on" class="img on"
@@ -40,12 +40,6 @@
/> />
</view> </view>
<view class="name">{{ item.name }}</view> <view class="name">{{ item.name }}</view>
<view
v-if="item.name === '消息' && showUnreadBadge"
class="badge"
>
{{ unreadCountText }}
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -53,8 +47,6 @@
</template> </template>
<script> <script>
import store from '@/store'
import { getUnreadMessageCount, getUnreadMessageCountForSeller } from '@/api/rooms'
export default { export default {
name: 'XddTabbar', name: 'XddTabbar',
props: { props: {
@@ -100,104 +92,14 @@ export default {
type: 1, type: 1,
index: 3 index: 3
} }
]], ]]
unreadCount: 0
} }
}, },
computed: {
isLogin() {
return store.getters.isLogin
},
showUnreadBadge() {
return this.isLogin && this.unreadCount > 0
},
unreadCountText() {
if (this.unreadCount > 99) {
return '99+'
}
return this.unreadCount
}
},
watch: {
isLogin(val) {
if (val) {
this.fetchUnreadCount()
} else {
this.unreadCount = 0
uni.$emit('updateUnreadMessageCount', 0)
}
}
},
mounted() {
this.getElementData('#quweiIcon')
this.getIconData('#icon1')
if (this.isLogin) {
this.fetchUnreadCount()
}
uni.$on('updateUnreadMessageCount', this.handleUpdateUnreadMessageCount)
},
beforeDestroy() {
uni.$off('updateUnreadMessageCount', this.handleUpdateUnreadMessageCount)
},
methods: { methods: {
handleUpdateUnreadMessageCount(count) { /**
if (!this.isLogin) { * 跳转至目标页面
this.unreadCount = 0 * type: 1-tabbar页面,2-非tabbar页面
return */
}
if (typeof count === 'number') {
this.unreadCount = count
} else {
this.fetchUnreadCount()
}
},
getElementData(el) {
const query = uni.createSelectorQuery().in(this)
query.select(el).boundingClientRect().exec((res)=> {
if(res[0]) {
this.$emit('getElementData', res[0])
}
})
},
getIconData(el) {
const query = uni.createSelectorQuery().in(this)
query.select(el).boundingClientRect().exec((res)=> {
if(res[0]) {
this.$emit('getIcon', res[0])
}
})
},
fetchUnreadCount() {
uni.request({
url: this.$SERVICE_API_URL + '/unread-num',
method: 'POST',
data: {
uid: store.getters.userInfo.uid
},
success:(res)=>{
if(res.data.status_code === 200) {
const count = res.data.content || 0
getUnreadMessageCount().then(res => {
const { success, data } = res
if (success) {
const _count = data || 0
this.unreadCount = count + _count
uni.$emit('updateUnreadMessageCount', this.unreadCount)
} else {
this.unreadCount = 0
uni.$emit('updateUnreadMessageCount', 0)
}
}).catch(() => {
this.unreadCount = 0
uni.$emit('updateUnreadMessageCount', 0)
})
} else {
this.unreadCount = 0
}
},
})
},
gotoPage(url, type = 1, index) { gotoPage(url, type = 1, index) {
if (this.currIndex === index) return if (this.currIndex === index) return
if (type === 1) { if (type === 1) {
@@ -226,7 +128,7 @@ export default {
background-repeat: no-repeat; background-repeat: no-repeat;
.center-img { .center-img {
position: absolute; position: absolute;
top: -20rpx; top: -16rpx;
left: 50%; left: 50%;
z-index: 5; z-index: 5;
transform: translateX(-50%); transform: translateX(-50%);
@@ -276,7 +178,6 @@ export default {
} }
.item { .item {
width: 140rpx; width: 140rpx;
position: relative;
&.curr { &.curr {
.name { .name {
color: #C52733; color: #C52733;
@@ -289,21 +190,6 @@ export default {
} }
} }
} }
.badge {
position: absolute;
top: -4rpx;
right: 32rpx;
min-width: 28rpx;
padding: 0 6rpx;
height: 28rpx;
line-height: 28rpx;
border-radius: 14rpx;
background-color: #FF564A;
color: #ffffff;
font-size: 20rpx;
text-align: center;
box-sizing: border-box;
}
} }
} }
} }
@@ -248,7 +248,7 @@
background: #EBEBEB; background: #EBEBEB;
display: flex; display: flex;
justify-content: center; justify-content: center;
z-index: 999; z-index: 2;
flex-wrap: wrap; flex-wrap: wrap;
transition:all 0.2s ease-in 0.2s; transition:all 0.2s ease-in 0.2s;
} }
@@ -257,7 +257,7 @@
} }
.keyboard-item { .keyboard-item {
box-sizing: border-box; box-sizing: border-box;
width: 33.333%; width: 250rpx;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
-25
View File
@@ -1,25 +0,0 @@
const baseStr = 'edc_epro_prod:'
const settings = {
storage: {
systemInfo: `${baseStr}systemInfo`,
firstLaunch: `${baseStr}firstLaunch`,
token: `${baseStr}token`,
userInfo: `${baseStr}userInfo`,
webInfo: `${baseStr}webInfo`
},
/* 拦截器超时时长 */
timeout: 120 * 1000,
/* 系统接口前缀,没有统一的填空字符串 */
sysPrefix: '/',
/* 是否收集错误日志 */
collectRequestError: false,
/* 订阅消息模板ID */
SubscribeMessageTmplIds: [
'7O3wKw7_D4t7yfSOlvecKuOQP8QEPY88uBx2FJg43HE',
'TSmTnGibZ8IxWCiRWOvLxha6-0u7tE-V1-WbDCiPkKU',
'9Q6xLHe6HyjkU5Zn5k_2zxYPf2y4MxVyUbOSW8pcZRU',
'v0GegDmzjpqiinmdj7dOwRK1MaTAPVyCOpqn8hJ3Y3Q'
]
}
export default settings
-14
View File
@@ -6,25 +6,11 @@ if (NODE_ENV === 'development' || NODE_ENV === 'test') {
BASE_URL = 'https://shop.xdd618.com/api' BASE_URL = 'https://shop.xdd618.com/api'
SERVICE_URL = 'https://service-test.xdd618.com/api' SERVICE_URL = 'https://service-test.xdd618.com/api'
SERVICE_WS_URL = 'wss://service-test.xdd618.com/ws' SERVICE_WS_URL = 'wss://service-test.xdd618.com/ws'
wx.setEnableDebug({
enableDebug: false
})
}
if (NODE_ENV === 'fix') {
BASE_URL = 'https://shop-pre.xdd618.com/api'
SERVICE_URL = 'https://service-pre.xdd618.com/api'
SERVICE_WS_URL = 'wss://service-pre.xdd618.com/ws'
wx.setEnableDebug({
enableDebug: false
})
} }
if (NODE_ENV === 'prod') { if (NODE_ENV === 'prod') {
BASE_URL = 'https://wxapp.xdd618.com/api' BASE_URL = 'https://wxapp.xdd618.com/api'
SERVICE_URL = 'https://service.xdd618.com/api' SERVICE_URL = 'https://service.xdd618.com/api'
SERVICE_WS_URL = 'wss://service.xdd618.com/ws' SERVICE_WS_URL = 'wss://service.xdd618.com/ws'
wx.setEnableDebug({
enableDebug: false
})
} }
export const VUE_APP_API_URL = BASE_URL export const VUE_APP_API_URL = BASE_URL
+2 -2
View File
@@ -1,4 +1,4 @@
// import { subscribeMessage } from '@/libs/order' import { subscribeMessage } from '@/libs/order'
import { getProvider } from '@/utils' import { getProvider } from '@/utils'
import WechatJSSDK from 'wechat-jssdk/dist/client.umd' import WechatJSSDK from 'wechat-jssdk/dist/client.umd'
import { getWechatConfig, wechatAuth } from '@/api/public' import { getWechatConfig, wechatAuth } from '@/api/public'
@@ -65,7 +65,7 @@ export const weappPay = option => {
resolve(success) resolve(success)
}, 3000) }, 3000)
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
// subscribeMessage() subscribeMessage()
// #endif // #endif
}, },
fail: error => { fail: error => {
+1 -27
View File
@@ -75,39 +75,13 @@ const force2Decimal = function change2Decimal(value) {
return forceToDecimal(value, 2) return forceToDecimal(value, 2)
} }
const formatCount = function(value) {
if (!value) return 0;
const num = parseFloat(value);
if (isNaN(num)) return 0;
if (num >= 10000) {
let val = num / 10000;
val = parseFloat(val.toFixed(1));
return val + '万';
}
return num;
}
const toast = (title = '', position = 'center', success = function() {}) => {
uni.showToast({
title,
mask: false,
icon: 'none',
duration: 2500,
position,
success
})
}
Vue.prototype.$force2Decimal = force2Decimal Vue.prototype.$force2Decimal = force2Decimal
Vue.prototype.$forceToDecimal = forceToDecimal Vue.prototype.$forceToDecimal = forceToDecimal
Vue.prototype.$formatCount = formatCount
Vue.config.productionTip = false Vue.config.productionTip = false
App.mpType = 'app' App.mpType = 'app'
Vue.prototype.$store = store Vue.prototype.$store = store
Vue.prototype.$dialog = dialog Vue.prototype.$dialog = dialog;
Vue.prototype.$toast = toast
const app = new Vue(App) const app = new Vue(App)
+3 -10
View File
@@ -5,7 +5,6 @@
"versionName" : "4.0.0", "versionName" : "4.0.0",
"versionCode" : 4, "versionCode" : 4,
"transformPx" : false, "transformPx" : false,
"sassImplementationName" : "node-sass",
/* 5+App */ /* 5+App */
"app-plus" : { "app-plus" : {
"usingComponents" : true, "usingComponents" : true,
@@ -135,8 +134,7 @@
"mp-weixin" : { "mp-weixin" : {
"appid" : "wx9417047e1a0c340b", "appid" : "wx9417047e1a0c340b",
"setting" : { "setting" : {
"urlCheck" : true, "urlCheck" : false
"minified" : true
}, },
"usingComponents" : true, "usingComponents" : true,
"permission" : { "permission" : {
@@ -148,16 +146,11 @@
"plugins" : { "plugins" : {
"live-player-plugin" : { "live-player-plugin" : {
"version" : "1.3.5", "version" : "1.3.5",
// 最新直播组件版本号 //最新直播组件版本号
"provider" : "wx2b03c6e691cd7370" "provider" : "wx2b03c6e691cd7370"
},
"WechatSI" : {
"version" : "0.3.6",
// TTS版本号
"provider" : "wx069ba97219f66d99"
} }
}, },
// 直播appid //直播appid
"optimization" : { "optimization" : {
"subPackages" : true "subPackages" : true
} }
-80
View File
@@ -1,80 +0,0 @@
import { queryUserGuide, setUserGuide } from '@/api/user'
export default {
data() {
return {
scrollView: '',
functionGuideData: {
step: 0,
tips: '',
tipsPosition: '',
btnGroupPosition: '',
position: {}
},
screenWidth: 0,
scrollLeft: 0,
totalWidth: 0,
scrollViewWidth: 0,
imgs: [],
_step: 0
}
},
onLoad() {
// this.setGuide('countyFamousIndex', 0)
// this.setGuide('landmarkGoodsIndex', 0)
// this.setGuide('findFunIndex', 0)
// this.setGuide('wellnessFoodIndex', 0)
// this.setGuide('ichIndex', 0)
// this.setGuide('wenwanIndex', 0)
// this.setGuide('goodsIndex', 0)
// this.setGuide('index', 0)
},
methods: {
setGuide(type, status = 1) {
const params = {
guideName: type,
guideStatus: status
}
setUserGuide(params).then(res => {
if(type === 'index') {
this.queryGuide(type)
}
})
},
queryGuide(type) {
const params = {
guideName: type
}
queryUserGuide(params).then(res => {
const { data, success } = res
if(success && data.guideStatus === 0) {
this.$refs.FunctionGuide.init()
}
if(type === 'index' && data.guideStatus === 1) {
this.isOldUser = true
}
if(type === 'index' && data.guideStatus === 0) {
this.isOldUser = false
}
})
},
setFunctionGuideData(data) {
this.functionGuideData = {
...this.functionGuideData,
...data
}
this.showFunctionGuide()
},
getElementData(el, cb) {
const query = uni.createSelectorQuery().in(this)
query.select(el).boundingClientRect().exec((res)=> {
console.log(res, 'getElementData');
if(res[0]) {
cb(res[0])
} else {
this.$refs.FunctionGuide.show = false
}
})
},
}
}
-402
View File
@@ -1,402 +0,0 @@
import {
getCartCount,
getProductCode,
getProductDetail,
postCartAdd,
getProductSkuBySelected
} from '@/api/store'
export default {
data() {
return {
isWenwan: 0,
qualifications: [],
source: '',
isOpen: false,
attrTxt: '',
attrValue: '',
m_id: null,
productValueArr: [],
attr: {
cartAttr: false,
cart_num: 1,
defaultSku: [],
defaultSkuIndex: [],
productAttr: [],
productSelect: {
cart_num: 1,
earnPoints: 0,
image: '',
otPrice: 0,
price: 0,
stock: 0,
store_name: '',
unique: ''
}
},
cart_num: 1,
CartCount: 0,
// 只有一个规格时直接加入购物车;AI聊天界面则不直接加入购物车,每次都要显示规格选择弹窗
onlyOneToAddCart: true
}
},
methods: {
// 获取购物车数量
getCartCount () {
const isLogin = this.isLogin
if (isLogin) {
getCartCount({
numType: 0
}).then(res => {
this.CartCount = res.data.count
this.$forceUpdate()
})
}
},
getSkuActiveStatus(selectedSku) {
getProductSkuBySelected({ id: this.m_id, selectedSku }).then(res => {
const { success, data } = res
if (success) {
for (const key in data) {
if (data[key]) {
this.attr.productAttr.map(item => {
if (item.attrName === key) {
item.attrValue.map(subItem => {
data[key].map(dataItem => {
if (dataItem.sku === subItem.attr) {
subItem.canUsed = dataItem.canUsed
}
})
})
}
})
}
}
console.log(this.$refs);
this.$refs.attrWindow.reRender(this.attr)
}
})
},
productCon() {
getProductDetail(this.m_id).then(res => {
const { data } = res
this.storeInfo = {...data.storeInfo}
if(data.storeInfo.stock === 0) {
uni.showToast({
title: "产品库存不足,请选择其他商品",
icon: "none",
duration: 5000
})
return
}
this.isWenwan = data.isWenwan
this.qualifications = data.qualifications || []
// 给 attr 赋值,将请求回来的规格赋值给 attr
if (this.source !== 'pre' && this.source !== 'day' && this.source !== 'kill' && this.source !== 'spe') {
// this.$set(this.attr, 'productAttr', data.productAttr)
this.attr.productAttr = data.productAttr || []
this.productValueArr = []
for (const key in data.productValue) {
this.productValueArr.push({
attrItemkey: key,
...data.productValue[key]
})
}
// 初始化认为所有的规格都是可以选的
this.attr.productAttr.map(item => {
item.attrValue.map(subItem => {
subItem.canUsed = true
})
})
}
this.attr.defaultSku = data.defaultSku
this.attr.defaultSkuIndex = data.defaultSkuIndex
this.DefaultSelect()
// 是否单一规格
const onlyOne = Object.keys(data.productValue).length === 1
if(onlyOne && this.onlyOneToAddCart) {
this.handleOk(() => this.getCartCount())
return
}
this.attr.cartAttr = !this.isOpen ? true : false
})
},
getAttrItemData(attr) {
let result = {}
this.productValueArr.map(item => {
if (item.attrItemkey === attr) {
result = item
}
})
return result
},
// 默认选中属性
DefaultSelect() {
const productAttr = this.attr.productAttr
const productAttrLength = productAttr.length
this.attr.productAttr.map((item, index) => {
item.attrValue.map((subItem, subIndex) => {
if (this.attr.defaultSkuIndex[index] === subIndex) {
subItem.check = true
} else {
subItem.check = false
}
})
})
const skuKey = (this.attr.defaultSku || []).join(',')
if (!skuKey) {
return
}
const productSelect = this.getAttrItemData(skuKey)
this.attrValue = skuKey
this.attrTxt = '已选择'
if (productSelect && productAttrLength) {
// this.$set(
// this.attr.productSelect,
// 'store_name',
// this.storeInfo.storeName
// )
// this.$set(this.attr.productSelect, 'image', productSelect.image)
// this.$set(this.attr.productSelect, 'price', productSelect.price)
// this.$set(this.attr.productSelect, 'otPrice', productSelect.otPrice)
// this.$set(this.attr.productSelect, 'stock', productSelect.stock)
// this.$set(this.attr.productSelect, 'unique', productSelect.unique)
// this.$set(this.attr.productSelect, 'earnPoints', productSelect.earnPoints)
// this.$set(this.attr.productSelect, 'cart_num', 1)
// this.$set(this, 'attrValue', value.sort().join(',')) // 作废
// this.$set(this, 'attrValue', skuKey)
// this.$set(this, 'attrTxt', '已选择')
this.attr.productSelect = {
image: productSelect.image,
price: productSelect.price,
otPrice: productSelect.otPrice,
stock: productSelect.stock,
earnPoints: productSelect.earnPoints,
unique: productSelect.unique,
store_name: this.storeInfo.storeName,
cart_num: 1
}
this.getSkuActiveStatus(skuKey)
} else if (!productSelect && productAttrLength) {
// this.$set(
// this.attr.productSelect,
// 'store_name',
// this.storeInfo.storeName
// )
// this.$set(this.attr.productSelect, 'image', this.storeInfo.image)
// this.$set(this.attr.productSelect, 'price', this.storeInfo.price)
// this.$set(this.attr.productSelect, 'otPrice', this.storeInfo.otPrice)
// this.$set(this.attr.productSelect, 'stock', 0)
// this.$set(this.attr.productSelect, 'earnPoints', 0)
// this.$set(this.attr.productSelect, 'unique', '')
// this.$set(this.attr.productSelect, 'cart_num', 0)
// this.$set(this, 'attrValue', '')
// this.$set(this, 'attrTxt', '请选择')
this.attr.productSelect = {
image: this.storeInfo.image,
price: this.storeInfo.price,
otPrice: this.storeInfo.otPrice,
stock: 0,
earnPoints: 0,
unique: '',
store_name: this.storeInfo.storeName,
cart_num: 1
}
} else if (!productSelect && !productAttrLength) {
// this.$set(
// this.attr.productSelect,
// 'store_name',
// this.storeInfo.storeName
// )
// this.$set(this.attr.productSelect, 'image', this.storeInfo.image)
// this.$set(this.attr.productSelect, 'price', this.storeInfo.price)
// this.$set(this.attr.productSelect, 'otPrice', this.storeInfo.otPrice)
// this.$set(this.attr.productSelect, 'stock', this.storeInfo.stock)
// this.$set(this.attr.productSelect, 'earnPoints', 0)
// this.$set(
// this.attr.productSelect,
// 'unique',
// this.storeInfo.unique || ''
// )
// this.$set(this.attr.productSelect, 'cart_num', 1)
this.attr.productSelect = {
image: this.storeInfo.image,
price: this.storeInfo.price,
otPrice: this.storeInfo.otPrice,
stock: this.storeInfo.stock,
earnPoints: 0,
unique: this.storeInfo.unique || '',
store_name: this.storeInfo.storeName,
cart_num: 1
}
// this.$set(this, 'attrValue', '')
// this.$set(this, 'attrTxt', '请选择')
}
},
// 点击加入购物车按钮
addToCart(item, id = 'id') {
console.log(item, 'addToCart --------- item');
this.m_id = item[id]
this.$nextTick(() => {
this.productCon()
})// if(this.attr.cartAttr && !this.isOpen){
// return this.isOpen = true
// }
console.log(this.$refs.attrWindow, '--222--');
},
handleOk(cb) {
const productSelect = this.getAttrItemData(this.attrValue)
// 如果有属性,没有选择,提示用户选择
const hasNo = (this.attr.productAttr.length && productSelect === undefined && this.isOpen) || productSelect.stock === 0
if (hasNo) {
uni.showToast({
title: "产品库存不足,请选择其他商品",
icon: "none",
duration: 5000
})
return
}
const q = {
productId: this.m_id,
cartNum: this.attr.productSelect.cart_num,
new: 0,
uniqueId: this.attr.productSelect !== undefined ? this.attr.productSelect.unique : ''
}
postCartAdd(q).then(res => {
this.isOpen = false
this.attr.cartAttr = false
this.$set(this.attr.productSelect, 'cart_num', 1)
this.cart_num = 1
uni.showToast({
title: "添加购物车成功",
icon: "none",
duration: 2000
})
cb && cb()
})
},
ChangeCartNum(changeValue) {
if(changeValue === 0) return
// changeValue:是否 加|减
// 获取当前变动属性
const productSelect = this.getAttrItemData(this.attrValue)
// 如果没有属性,赋值给商品默认库存
if (productSelect === undefined && !this.attr.productAttr.length) {
productSelect = this.attr.productSelect
}
// 无属性值即库存为0;不存在加减
if (productSelect === undefined) return
let stock = productSelect.stock || 0
let num = this.attr.productSelect
if (changeValue) {
if(changeValue > 1) {
num.cart_num = changeValue
} else {
num.cart_num++
}
if (num.cart_num > stock) {
if(stock < 1) {
this.$set(this.attr.productSelect, 'cart_num', 1)
this.$set(this, 'cart_num', 1)
} else {
this.$set(this.attr.productSelect, 'cart_num', stock)
this.$set(this, 'cart_num', stock)
}
} else {
if (num.cart_num < 1) {
this.$set(this.attr.productSelect, 'cart_num', 1)
this.$set(this, 'cart_num', 1)
} else {
this.$set(this.attr.productSelect, 'cart_num', num.cart_num)
// this.$set(this, 'cart_num', num.cart_num)
}
}
} else {
num.cart_num--
if (num.cart_num < 1) {
this.$set(this.attr.productSelect, 'cart_num', 1)
this.$set(this, 'cart_num', 1)
} else {
this.$set(this.attr.productSelect, 'cart_num', num.cart_num)
this.$set(this, 'cart_num', num.cart_num)
}
}
},
// 关闭属性
changeattr(msg) {
// 修改了规格
this.attr.cartAttr = msg
this.$set(this.attr.productSelect, 'cart_num', 1)
this.$forceUpdate()
this.isOpen = false
},
// 打开属性插件
selecAttrTap() {
this.$set(this.attr.productSelect, 'cart_num', 1)
this.attr.cartAttr = true
this.isOpen = true
this.$forceUpdate()
},
ChangeAttr(res) {
const { index, subIndex, value } = res
// 修改了规格
const productSelect = this.getAttrItemData(value)
if (productSelect) {
this.attr.productAttr[index].attrValue.map((subItem, subIdx) => {
subItem.check= false
if (subIndex === subIdx) {
subItem.check = true
}
})
this.$set(this.attr.productSelect, 'image', productSelect.image)
this.$set(this.attr.productSelect, 'price', productSelect.price)
this.$set(this.attr.productSelect, 'otPrice', productSelect.otPrice)
this.$set(this.attr.productSelect, 'stock', productSelect.stock)
this.$set(this.attr.productSelect, 'unique', productSelect.unique)
this.$set(this.attr.productSelect, 'earnPoints', productSelect.earnPoints)
this.$set(this.attr.productSelect, 'cart_num', 1)
this.$set(this, 'attrValue', value)
this.$set(this, 'attrTxt', '已选择')
this.getSkuActiveStatus(value)
} else {
this.$set(this.attr.productSelect, 'image', this.storeInfo.image)
this.$set(this.attr.productSelect, 'price', this.storeInfo.price)
this.$set(this.attr.productSelect, 'otPrice', this.storeInfo.otPrice)
this.$set(this.attr.productSelect, 'stock', 0)
this.$set(this.attr.productSelect, 'unique', '')
this.$set(this.attr.productSelect, 'earnPoints', 0)
this.$set(this.attr.productSelect, 'cart_num', 0)
this.$set(this, 'attrValue', '')
this.$set(this, 'attrTxt', '请选择')
}
},
changeFun(opt) {
if (typeof opt !== 'object') opt = {}
let action = opt.action || ''
let value = opt.value === undefined ? '' : opt.value
this.cart_num = 1
this[action] && this[action](value)
},
// queryCartCount (isAnima) {
// const isLogin = this.isLogin
// if (isLogin) {
// getCartCount({
// numType: 0
// }).then(res => {
// this.CartCount = res.data.count
// //加入购物车后重置属性
// if (isAnima) {
// this.animated = true
// setTimeout(function () {
// this.animated = false
// }, 500)
// }
// })
// }
// },
}
}
@@ -1,72 +0,0 @@
import { getDrawTicketByOrder } from '@/api/lottery'
export const orderPaySuccessToCheckDrawStatus = {
data(){
return {
drawTicketPopup: {
show: false,
ticketCode: '',
drawTime: ''
}
}
},
methods: {
setDrawTicketPopupFromQuery(ticketData = '') {
const drawTicketData = ticketData || this.$yroute.query.drawTicketData
if (!drawTicketData) {
return
}
let result = {}
try {
result = typeof drawTicketData === 'string' ? JSON.parse(decodeURIComponent(drawTicketData)) : drawTicketData
console.log(result)
} catch (e) {
result = {}
}
const hasTicket = Number(result.hasTicket || 0) === 1
const howPopup = Number(result.showPopup || 0) === 1
if (!hasTicket || !howPopup) {
return
}
this.drawTicketPopup = {
show: true,
ticketCode: result.ticketCode || result.code || '',
drawTime: result.drawTime || ''
}
},
closeDrawTicketPopup() {
this.drawTicketPopup.show = false
},
goHomeFromPopup() {
this.drawTicketPopup.show = false
uni.switchTab({
url: '/pages/home/index'
})
},
goTicketsFromPopup() {
this.drawTicketPopup.show = false
uni.navigateTo({
url: '/pkg-video/views/county-my-tickets'
})
},
buildOrderDetailQuery(orderId, drawTicketResult = {}) {
return {
id: orderId,
drawTicketData: encodeURIComponent(JSON.stringify(drawTicketResult || {}))
}
},
async afterPaySuccess(orderId, fallback) {
if (!orderId) {
fallback && fallback()
return
}
try {
const res = await getDrawTicketByOrder(orderId)
const result = (res && res.data) || {}
fallback && fallback(result)
return
} catch (e) {
}
fallback && fallback({})
}
}
}
-2
View File
@@ -13,8 +13,6 @@ export const pageListenMixins = {
onShow() { onShow() {
this.pageViewDateTime = getCurrDateTime() this.pageViewDateTime = getCurrDateTime()
this.pageToWatchShowCount(this.pageKeyId) this.pageToWatchShowCount(this.pageKeyId)
this.videoContext = uni.createVideoContext('indexVideo', this);
}, },
onUnload() { onUnload() {
this.pageToHideHandle() this.pageToHideHandle()
+23 -34
View File
@@ -1,45 +1,34 @@
import { getWeixinShareConfig } from '@/api/public'
export default{ export default{
data(){ data(){
return { return {
//设置默认的分享参数 //设置默认的分享参数
sharePagePath: '/pages/home/index',
share:{ share:{
title: '云南香道滇官方商城', title:'云南香道滇官方商城',
path: this.sharePagePath, path:'/pages/Loading/index',
imageUrl: this.$VUE_APP_RESOURCES_URL + '/20210617211221217375.jpg?' + new Date().getTime(), imageUrl:'http://admin-api.xdd618.com/file/pic/20210617211221217375.jpg',
desc: '', desc:'',
content: '' content:''
} }
} }
}, },
onShareAppMessage(res) { onShareAppMessage(res) {
uni.updateShareMenu({ return {
isPrivateMessage: false, title:this.share.title,
withShareTicket: false path:this.share.path,
}) imageUrl:this.share.imageUrl,
return new Promise(async (resolve, reject) => { desc:this.share.desc,
const { success, data } = await getWeixinShareConfig() content:this.share.content,
if (success) { success(res){
resolve({ uni.showToast({
title: data.title || this.share.title, title:'分享成功'
path: data.url || this.share.path,
imageUrl: data.image || this.share.imageUrl,
desc: this.share.desc,
content: this.share.content,
success(res){
uni.showToast({
title:'分享成功'
})
},
fail(res){
uni.showToast({
title:'分享失败',
icon:'none'
})
}
}) })
} },
}) fail(res){
uni.showToast({
title:'分享失败',
icon:'none'
})
}
}
} }
} }
-17705
View File
File diff suppressed because it is too large Load Diff
+145 -157
View File
@@ -1,160 +1,148 @@
{ {
"name": "xdd_mp", "name": "xdd_mp",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": {
"serve": "npm run dev:h5",
"build": "npm run build:h5",
"build:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build",
"build:custom": "cross-env NODE_ENV=production uniapp-cli custom",
"build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build",
"build:mp-360": "cross-env NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build",
"build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
"build:mp-baidu": "cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build",
"build:mp-jd": "cross-env NODE_ENV=production UNI_PLATFORM=mp-jd vue-cli-service uni-build",
"build:mp-kuaishou": "cross-env NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build",
"build:mp-lark": "cross-env NODE_ENV=production UNI_PLATFORM=mp-lark vue-cli-service uni-build",
"build:mp-qq": "cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build",
"build:mp-toutiao": "cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
"build:mp-xhs": "cross-env NODE_ENV=production UNI_PLATFORM=mp-xhs vue-cli-service uni-build",
"build:quickapp-native": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build",
"build:quickapp-webview": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build",
"build:quickapp-webview-huawei": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build",
"build:quickapp-webview-union": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build",
"dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch",
"dev:custom": "cross-env NODE_ENV=development uniapp-cli custom",
"dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve",
"dev:mp-360": "cross-env NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch",
"dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch",
"dev:mp-baidu": "cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch",
"dev:mp-jd": "cross-env NODE_ENV=development UNI_PLATFORM=mp-jd vue-cli-service uni-build --watch",
"dev:mp-kuaishou": "cross-env NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch",
"dev:mp-lark": "cross-env NODE_ENV=development UNI_PLATFORM=mp-lark vue-cli-service uni-build --watch",
"dev:mp-qq": "cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch",
"dev:mp-toutiao": "cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch",
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch --minimize",
"dev:mp-xhs": "cross-env NODE_ENV=development UNI_PLATFORM=mp-xhs vue-cli-service uni-build --watch",
"dev:quickapp-native": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch",
"dev:quickapp-webview": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch",
"dev:quickapp-webview-huawei": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch",
"dev:quickapp-webview-union": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build --watch",
"info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js",
"serve:quickapp-native": "node node_modules/@dcloudio/uni-quickapp-native/bin/serve.js",
"test:android": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i",
"test:h5": "cross-env UNI_PLATFORM=h5 jest -i",
"test:ios": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i",
"test:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu jest -i",
"test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i"
},
"dependencies": {
"@dcloudio/uni-app": "^2.0.2-3090920231225001",
"@dcloudio/uni-app-plus": "^2.0.1-35320220729002",
"@dcloudio/uni-h5": "^2.0.1-35320220729002",
"@dcloudio/uni-helper-json": "*",
"@dcloudio/uni-i18n": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-360": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-alipay": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-baidu": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-jd": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-kuaishou": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-lark": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-qq": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-toutiao": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-vue": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-weixin": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-xhs": "^2.0.1-35320220729002",
"@dcloudio/uni-quickapp-native": "^2.0.1-35320220729002",
"@dcloudio/uni-quickapp-webview": "^2.0.1-35320220729002",
"@dcloudio/uni-stacktracey": "^2.0.1-35320220729002",
"@dcloudio/uni-stat": "^2.0.1-35320220729002",
"@vue/composition-api": "^1.7.2",
"@vue/shared": "^3.0.0",
"animate.css": "^3.7.2",
"async-validator": "^3.2.4",
"core-js": "^3.6.5",
"dayjs": "^1.11.2",
"flyio": "^0.6.2",
"jweixin-module": "^1.6.0",
"miniapp-color-thief": "^1.0.5",
"number-precision": "^1.5.2",
"regenerator-runtime": "^0.12.1",
"remove-markdown": "^0.6.2",
"uview-ui": "2.0.36",
"vconsole": "^3.14.6",
"vue": "^2.6.11",
"vue-ydui": "^1.2.6",
"vuex": "^3.2.0",
"wechat-jssdk": "^5.0.4"
},
"devDependencies": {
"@babel/runtime": "~7.17.9",
"@dcloudio/types": "^3.0.4",
"@dcloudio/uni-automator": "^2.0.1-35320220729002",
"@dcloudio/uni-cli-i18n": "^2.0.1-35320220729002",
"@dcloudio/uni-cli-shared": "^2.0.1-35320220729002",
"@dcloudio/uni-migration": "^2.0.1-35320220729002",
"@dcloudio/uni-template-compiler": "^2.0.1-35320220729002",
"@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.1-35320220729002",
"@dcloudio/vue-cli-plugin-uni": "^2.0.1-35320220729002",
"@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.1-35320220729002",
"@dcloudio/webpack-uni-mp-loader": "^2.0.1-35320220729002",
"@dcloudio/webpack-uni-pages-loader": "^2.0.1-35320220729002",
"@vue/cli-plugin-babel": "~4.5.19",
"@vue/cli-service": "~4.5.19",
"babel-plugin-import": "^1.11.0",
"cross-env": "^7.0.2",
"jest": "^25.4.0",
"less": "^4.1.0",
"less-loader": "^4.1.0",
"mini-types": "*",
"miniprogram-api-typings": "*",
"postcss-comment": "^2.0.0",
"sass": "^1.5.0",
"vue-template-compiler": "^2.6.11"
},
"browserslist": [
"Android >= 4.4",
"ios >= 9"
],
"resolutions": {
"@babel/runtime": "~7.17.9"
},
"uni-app": {
"scripts": { "scripts": {
"mp-weixin-test": { "serve": "npm run dev:h5",
"title": "微信小程序(Test环境)", "build": "npm run build:h5",
"env": { "build:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build",
"UNI_PLATFORM": "mp-weixin", "build:custom": "cross-env NODE_ENV=production uniapp-cli custom",
"VUE_APP_ENV": "test", "build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build",
"UNI_OUTPUT_DIR": "dist" "build:mp-360": "cross-env NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build",
}, "build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
"define": { "build:mp-baidu": "cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build",
"CUSTOM-CONST": true "build:mp-jd": "cross-env NODE_ENV=production UNI_PLATFORM=mp-jd vue-cli-service uni-build",
} "build:mp-kuaishou": "cross-env NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build",
}, "build:mp-lark": "cross-env NODE_ENV=production UNI_PLATFORM=mp-lark vue-cli-service uni-build",
"mp-weixin-fix": { "build:mp-qq": "cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build",
"title": "微信小程序(Fix环境)", "build:mp-toutiao": "cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
"env": { "build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
"UNI_PLATFORM": "mp-weixin", "build:mp-xhs": "cross-env NODE_ENV=production UNI_PLATFORM=mp-xhs vue-cli-service uni-build",
"VUE_APP_ENV": "fix", "build:quickapp-native": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build",
"UNI_OUTPUT_DIR": "dist" "build:quickapp-webview": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build",
}, "build:quickapp-webview-huawei": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build",
"define": { "build:quickapp-webview-union": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build",
"CUSTOM-CONST": true "dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch",
} "dev:custom": "cross-env NODE_ENV=development uniapp-cli custom",
}, "dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve",
"mp-weixin": { "dev:mp-360": "cross-env NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch",
"title": "微信小程序(生产环境)", "dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch",
"env": { "dev:mp-baidu": "cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch",
"UNI_PLATFORM": "mp-weixin", "dev:mp-jd": "cross-env NODE_ENV=development UNI_PLATFORM=mp-jd vue-cli-service uni-build --watch",
"VUE_APP_ENV": "prod", "dev:mp-kuaishou": "cross-env NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch",
"UNI_OUTPUT_DIR": "dist" "dev:mp-lark": "cross-env NODE_ENV=development UNI_PLATFORM=mp-lark vue-cli-service uni-build --watch",
}, "dev:mp-qq": "cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch",
"define": { "dev:mp-toutiao": "cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch",
"CUSTOM-CONST": true "dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch --minimize",
} "dev:mp-xhs": "cross-env NODE_ENV=development UNI_PLATFORM=mp-xhs vue-cli-service uni-build --watch",
} "dev:quickapp-native": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch",
} "dev:quickapp-webview": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch",
} "dev:quickapp-webview-huawei": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch",
"dev:quickapp-webview-union": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build --watch",
"info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js",
"serve:quickapp-native": "node node_modules/@dcloudio/uni-quickapp-native/bin/serve.js",
"test:android": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i",
"test:h5": "cross-env UNI_PLATFORM=h5 jest -i",
"test:ios": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i",
"test:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu jest -i",
"test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i"
},
"dependencies": {
"@dcloudio/uni-app": "^2.0.2-3090920231225001",
"@dcloudio/uni-app-plus": "^2.0.1-35320220729002",
"@dcloudio/uni-h5": "^2.0.1-35320220729002",
"@dcloudio/uni-helper-json": "*",
"@dcloudio/uni-i18n": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-360": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-alipay": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-baidu": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-jd": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-kuaishou": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-lark": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-qq": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-toutiao": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-vue": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-weixin": "^2.0.1-35320220729002",
"@dcloudio/uni-mp-xhs": "^2.0.1-35320220729002",
"@dcloudio/uni-quickapp-native": "^2.0.1-35320220729002",
"@dcloudio/uni-quickapp-webview": "^2.0.1-35320220729002",
"@dcloudio/uni-stacktracey": "^2.0.1-35320220729002",
"@dcloudio/uni-stat": "^2.0.1-35320220729002",
"@vue/composition-api": "^1.7.2",
"@vue/shared": "^3.0.0",
"animate.css": "^3.7.2",
"async-validator": "^3.2.4",
"core-js": "^3.6.5",
"dayjs": "^1.11.2",
"flyio": "^0.6.2",
"jweixin-module": "^1.6.0",
"miniapp-color-thief": "^1.0.5",
"number-precision": "^1.5.2",
"regenerator-runtime": "^0.12.1",
"uview-ui": "2.0.36",
"vconsole": "^3.14.6",
"vue": "^2.6.11",
"vue-ydui": "^1.2.6",
"vuex": "^3.2.0",
"wechat-jssdk": "^5.0.4"
},
"devDependencies": {
"@babel/runtime": "~7.17.9",
"@dcloudio/types": "^3.0.4",
"@dcloudio/uni-automator": "^2.0.1-35320220729002",
"@dcloudio/uni-cli-i18n": "^2.0.1-35320220729002",
"@dcloudio/uni-cli-shared": "^2.0.1-35320220729002",
"@dcloudio/uni-migration": "^2.0.1-35320220729002",
"@dcloudio/uni-template-compiler": "^2.0.1-35320220729002",
"@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.1-35320220729002",
"@dcloudio/vue-cli-plugin-uni": "^2.0.1-35320220729002",
"@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.1-35320220729002",
"@dcloudio/webpack-uni-mp-loader": "^2.0.1-35320220729002",
"@dcloudio/webpack-uni-pages-loader": "^2.0.1-35320220729002",
"@vue/cli-plugin-babel": "~4.5.19",
"@vue/cli-service": "~4.5.19",
"babel-plugin-import": "^1.11.0",
"cross-env": "^7.0.2",
"jest": "^25.4.0",
"less": "^4.1.0",
"less-loader": "^4.1.0",
"mini-types": "*",
"miniprogram-api-typings": "*",
"postcss-comment": "^2.0.0",
"sass": "^1.5.0",
"vue-template-compiler": "^2.6.11"
},
"browserslist": [
"Android >= 4.4",
"ios >= 9"
],
"resolutions": {
"@babel/runtime": "~7.17.9"
},
"uni-app": {
"scripts": {
"mp-weixin-test": {
"title": "微信小程序(Test环境)",
"env": {
"UNI_PLATFORM": "mp-weixin",
"VUE_APP_ENV": "test",
"UNI_OUTPUT_DIR": "dist"
},
"define": {
"CUSTOM-CONST": true
}
},
"mp-weixin": {
"title": "微信小程序(生产环境)",
"env": {
"UNI_PLATFORM": "mp-weixin",
"VUE_APP_ENV": "prod",
"UNI_OUTPUT_DIR": "dist"
},
"define": {
"CUSTOM-CONST": true
}
}
}
}
} }
+250 -518
View File
@@ -22,6 +22,12 @@
"navigationBarTitleText": "登录" "navigationBarTitleText": "登录"
} }
}, },
{
"path": "pages/user/RetrievePassword/index",
"style": {
"navigationBarTitleText": "重置密码"
}
},
{ {
"path": "pages/home/index", "path": "pages/home/index",
"style": { "style": {
@@ -33,20 +39,7 @@
{ {
"path": "pages/home/landMark", "path": "pages/home/landMark",
"style": { "style": {
"navigationBarTitleText": "地标好物" "navigationBarTitleText": "地标好物"
}
},
{
"path": "pages/home/searchPage",
"style": {
"navigationBarTitleText": "搜索"
}
},
{
"path": "pages/home/newZone",
"style": {
"navigationBarTitleText": "甄选好礼",
"navigationBarBackgroundColor": "#FFFFFF"
} }
}, },
{ {
@@ -76,6 +69,12 @@
"navigationBarTextStyle": "white" "navigationBarTextStyle": "white"
} }
}, },
{
"path": "pages/shop/StoreList/index",
"style": {
"navigationBarTitleText": "商家列表"
}
},
{ {
"path": "pages/shop/GoodsList/index", "path": "pages/shop/GoodsList/index",
"style": { "style": {
@@ -83,17 +82,15 @@
} }
}, },
{ {
"path": "pages/cloud/haveFun", "path": "pages/NotDefined/index",
"style": { "style": {
"navigationBarTitleText": "趣游生活" "navigationBarTitleText": "404"
} }
}, },
{ {
"path": "pages/town/index", "path": "pages/cloud/haveFun",
"style": { "style": {
"navigationBarTextStyle": "white", "navigationBarTitleText": "寻趣味"
"navigationStyle": "custom",
"navigationBarTitleText": "趣游生活"
} }
}, },
{ {
@@ -104,6 +101,36 @@
"navigationBarTextStyle": "white" "navigationBarTextStyle": "white"
} }
}, },
{
"path": "pages/shop/GoodsCollection/index",
"style": {
"navigationBarTitleText": "商品收藏"
}
},
{
"path": "pages/shop/EvaluateList/index",
"style": {
"navigationBarTitleText": "评价列表"
}
},
{
"path": "pages/shop/GoodsEvaluate/index",
"style": {
"navigationBarTitleText": "商品评价"
}
},
{
"path": "pages/shop/GoodsPromotion/index",
"style": {
"navigationBarTitleText": "促销商品"
}
},
{
"path": "pages/shop/HotNewGoods/index",
"style": {
"navigationBarTitleText": "热门商品"
}
},
{ {
"path": "pages/shop/GoodsCon/index", "path": "pages/shop/GoodsCon/index",
"style": { "style": {
@@ -125,24 +152,129 @@
"navigationBarTitleText": "新增收货地址" "navigationBarTitleText": "新增收货地址"
} }
}, },
{
"path": "pages/user/UserAccount/index",
"style": {
"navigationBarTitleText": "账户余额"
}
},
{ {
"path": "pages/user/address/AddressManagement/index", "path": "pages/user/address/AddressManagement/index",
"style": { "style": {
"navigationBarTitleText": "收货地址" "navigationBarTitleText": "收货地址"
} }
}, },
{
"path": "pages/user/promotion/Poster/index",
"style": {
"navigationBarTitleText": "推广名片"
}
},
{
"path": "pages/user/signIn/Sign/index",
"style": {
"navigationBarTitleText": "签到"
}
},
{
"path": "pages/user/signIn/SignRecord/index",
"style": {
"navigationBarTitleText": "签到记录"
}
},
{
"path": "pages/user/promotion/CashAudit/index",
"style": {
"navigationBarTitleText": "提现结果"
}
},
{
"path": "pages/user/promotion/PromoterOrder/index",
"style": {
"navigationBarTitleText": "分销详情"
}
},
{
"path": "pages/user/promotion/PromoterList/index",
"style": {
"navigationBarTitleText": "分销列表",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/user/promotion/UserPromotion/index",
"style": {
"navigationBarTitleText": "团队管理",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/user/History/index",
"style": {
"navigationBarTitleText": "商品足迹",
"navigationBarBackgroundColor": "#FFFFFF",
"enablePullDownRefresh": false
}
},
{
"path": "pages/user/UserBill/index",
"style": {
"navigationBarTitleText": "账单记录"
}
},
{
"path": "pages/user/promotion/CommissionDetails/index",
"style": {
"navigationBarTitleText": "佣金明细"
}
},
{ {
"path": "pages/user/signIn/Integral/index", "path": "pages/user/signIn/Integral/index",
"style": { "style": {
"navigationBarTitleText": "我的积分" "navigationBarTitleText": "我的积分"
} }
}, },
{
"path": "pages/user/UserVip/index",
"style": {
"navigationBarTitleText": "用户vip"
}
},
{
"path": "pages/user/promotion/UserCash/index",
"style": {
"navigationBarTitleText": "提现"
}
},
{
"path": "pages/user/CustomerList/index",
"style": {
"navigationBarTitleText": "客服列表"
}
},
{
"path": "pages/user/Recharge/index",
"style": {
"navigationBarTitleText": "充值"
}
},
{ {
"path": "pages/order/MyOrder/index", "path": "pages/order/MyOrder/index",
"style": { "style": {
"navigationBarTitleText": "我的订单", "navigationBarTitleText": "我的订单",
"navigationBarBackgroundColor": "#fff", "navigationBarBackgroundColor": "#fff"
"navigationStyle": "custom" }
},
{
"path": "pages/order/Logistics/index",
"style": {
"navigationBarTitleText": "查看物流"
}
},
{
"path": "pages/order/OrderDetails/index",
"style": {
"navigationBarTitleText": "订单详情"
} }
}, },
{ {
@@ -152,16 +284,55 @@
"navigationBarBackgroundColor": "#fff" "navigationBarBackgroundColor": "#fff"
} }
}, },
{
"path": "pages/order/PaymentStatus/index",
"style": {
"navigationBarTitleText": "支付状态"
}
},
{
"path": "pages/order/GoodsReturn/index",
"style": {
"navigationBarTitleText": "商品退货"
}
},
{
"path": "pages/order/ReturnList/index",
"style": {
"navigationBarTitleText": "退货列表"
}
},
{ {
"path": "pages/map/index", "path": "pages/map/index",
"style": { "style": {
"navigationBarTitleText": "地图" "navigationBarTitleText": "地图"
} }
}, },
{
"path": "pages/user/Message/Message",
"style": {
"navigationBarTitleText": "消息",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/user/MessageDetail/MessageDetail",
"style": {
"navigationBarTitleText": "消息详情",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/user/MemberUpgradeIntro/MemberUpgradeIntro",
"style": {
"navigationBarTitleText": "升级说明",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{ {
"path": "pages/VideoPlayBackList/VideoPlayBackList", "path": "pages/VideoPlayBackList/VideoPlayBackList",
"style": { "style": {
"navigationBarTitleText": "使用指南", "navigationBarTitleText": "寻看点",
"navigationBarBackgroundColor": "#FFFFFF" "navigationBarBackgroundColor": "#FFFFFF"
} }
}, },
@@ -171,6 +342,43 @@
"navigationBarTitleText": "视频详情", "navigationBarTitleText": "视频详情",
"navigationBarBackgroundColor": "#FFFFFF" "navigationBarBackgroundColor": "#FFFFFF"
} }
},
{
"path": "pages/user/UpgradeElectronicProtocol/UpgradeElectronicProtocol",
"style": {
"navigationBarTitleText": "升级",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/user/UpgradeProtocolDetail/UpgradeProtocolDetail",
"style": {
"navigationBarTitleText": "共享股东协议"
}
},
{
"path": "pages/LiveAndShortVideo/LiveAndShortVideo",
"style": {
"navigationBarTitleText": "直播/视频"
}
},
{
"path": "pages/LiveBroadcastList/LiveBroadcastList",
"style": {
"navigationBarTitleText": "直播列表"
}
},
{
"path": "pages/user/UserFavorite/UserFavorite",
"style": {
"navigationBarTitleText": "我的喜欢"
}
},
{
"path": "pages/user/Points/index",
"style": {
"navigationBarTitleText": "积分"
}
} }
], ],
"subPackages": [ "subPackages": [
@@ -184,13 +392,6 @@
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, },
{
"path": "inn/farmerStore",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{ {
"path": "inn/innGoodList", "path": "inn/innGoodList",
"style": { "style": {
@@ -218,8 +419,7 @@
{ {
"path": "inn/innInfoDetail", "path": "inn/innInfoDetail",
"style": { "style": {
"navigationBarTitleText": "资讯详情", "navigationBarTitleText": "资讯详情"
"navigationBarBackgroundColor": "#FFFFFF"
} }
}, },
{ {
@@ -251,47 +451,11 @@
"navigationBarTitleText": "抽奖" "navigationBarTitleText": "抽奖"
} }
}, },
{
"path": "views/county-lottery",
"style": {
"navigationBarTitleText": "抽奖"
}
},
{ {
"path": "views/lottery-log", "path": "views/lottery-log",
"style": { "style": {
"navigationBarTitleText": "抽奖记录" "navigationBarTitleText": "抽奖记录"
} }
},
{
"path": "views/county-lottery-rules",
"style": {
"navigationBarTitleText": "活动规则"
}
},
{
"path": "views/county-my-tickets",
"style": {
"navigationBarTitleText": "我的抽奖码"
}
},
{
"path": "views/county-winners",
"style": {
"navigationBarTitleText": "中奖名单"
}
},
{
"path": "views/county-claim-address",
"style": {
"navigationBarTitleText": "填写收货地址"
}
},
{
"path": "views/county-realname",
"style": {
"navigationBarTitleText": "实名认证"
}
} }
] ]
}, },
@@ -316,13 +480,6 @@
"navigationBarTitleText": "历史会话" "navigationBarTitleText": "历史会话"
} }
}, },
{
"path": "views/message",
"style": {
"navigationBarTitleText": "互动消息",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{ {
"path": "views/xiaoZhi", "path": "views/xiaoZhi",
"style": { "style": {
@@ -357,20 +514,6 @@
"style": { "style": {
"navigationBarTitleText": "采购批发商入驻" "navigationBarTitleText": "采购批发商入驻"
} }
},
{
"path": "views/travelResidence",
"style": {
"navigationBarTitleText": "旅居商家入驻",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/experienceStore",
"style": {
"navigationBarTitleText": "体验店入驻",
"navigationBarBackgroundColor": "#FFFFFF"
}
} }
] ]
}, },
@@ -397,56 +540,13 @@
{ {
"path": "views/healthList", "path": "views/healthList",
"style": { "style": {
"navigationBarTitleText": "选择城市", "navigationBarTitleText": "康养 · 食材"
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/expoList",
"style": {
"navigationBarTitleText": "康养旅居",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/expoDetails",
"style": {
"navigationBarTitleText": "文化艺术",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/healthSanctum",
"style": {
"navigationBarTitleText": "康养旅居",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/healthFoods",
"style": {
"navigationBarTitleText": "康养旅居",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/healthFoodDetails",
"style": {
"navigationBarTitleText": "康养旅居",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/healthSearch",
"style": {
"navigationBarTitleText": "搜索",
"navigationBarBackgroundColor": "#FFFFFF"
} }
}, },
{ {
"path": "views/heritage", "path": "views/heritage",
"style": { "style": {
"navigationBarTitleText": "非遗文" "navigationBarTitleText": "非遗文"
} }
}, },
{ {
@@ -455,20 +555,6 @@
"navigationBarTitleText": "" "navigationBarTitleText": ""
} }
}, },
{
"path": "views/heritage/index",
"style": {
"navigationBarTitleText": "非遗文创",
"navigationBarBackgroundColor": "#FAEED8"
}
},
{
"path": "views/heritage/details",
"style": {
"navigationBarTitleText": "非遗文创",
"navigationBarBackgroundColor": "#FAEED8"
}
},
{ {
"path": "views/heritageVideo", "path": "views/heritageVideo",
"style": { "style": {
@@ -490,7 +576,7 @@
{ {
"path": "views/giftList", "path": "views/giftList",
"style": { "style": {
"navigationBarTitleText": "全国礼品" "navigationBarTitleText": "特色礼品"
} }
}, },
{ {
@@ -503,71 +589,36 @@
{ {
"path": "views/famousList", "path": "views/famousList",
"style": { "style": {
"navigationBarTitleText": "寻千县万村" "navigationBarTitleText": "寻千县"
} }
}, },
{ {
"path": "views/famousQianxian", "path": "views/famousQianxian",
"style": { "style": {
"navigationBarTitleText": "寻千县万村" "navigationBarTitleText": "寻千县"
} }
}, },
{ {
"path": "views/famousQianxianShop", "path": "views/famousQianxianShop",
"style": { "style": {
"navigationBarTitleText": "寻千县万村", "navigationBarTitleText": "寻千县",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, },
{
"path": "views/newsInfo",
"style": {
"navigationBarTitleText": "资讯详情"
}
},
{ {
"path": "views/famousQianxianTheme", "path": "views/famousQianxianTheme",
"style": { "style": {
"navigationBarTitleText": "寻千县万村", "navigationBarTitleText": "寻千县",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, },
{ {
"path": "views/famousQianxianVillageShop", "path": "views/famousQianxianVillageShop",
"style": { "style": {
"navigationBarTitleText": "寻千县万村", "navigationBarTitleText": "寻千县",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, },
{
"path": "views/sojoumStore",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "views/oldSojumStore",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "views/housekeeperDetail",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "views/groupBuyDetails",
"style": {
"navigationBarTitleText": "团购详情",
"navigationStyle": "custom",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{ {
"path": "views/famousQianxianInvestment", "path": "views/famousQianxianInvestment",
"style": { "style": {
@@ -608,8 +659,8 @@
"path": "views/nativeList", "path": "views/nativeList",
"style": { "style": {
"navigationBarTitleText": "特产", "navigationBarTitleText": "特产",
"navigationBarTextStyle": "black", "navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#fff" "navigationBarBackgroundColor": "#FF564A"
} }
}, },
{ {
@@ -623,89 +674,12 @@
"style": { "style": {
"navigationBarTitleText": "时令尝鲜" "navigationBarTitleText": "时令尝鲜"
} }
},
{
"path": "views/experienceCoupon",
"style": {
"navigationBarTitleText": "体验券详情",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/experienceCouponOrderDetail",
"style": {
"navigationBarTitleText": "订单核销",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/experienceProjectDetail",
"style": {
"navigationBarTitleText": "体验项目详情",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationStyle": "custom"
}
},
{
"path": "views/storeLicense",
"style": {
"navigationBarTitleText": "营业执照",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationStyle": "custom"
}
},
{
"path": "views/submitOrder",
"style": {
"navigationBarTitleText": "提交订单",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/sojoumOrderDetails",
"style": {
"navigationBarTitleText": "订单详情",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "views/sojoumOrderRefund",
"style": {
"navigationBarTitleText": "申请退款",
"navigationBarBackgroundColor": "#FFFFFF"
}
} }
] ]
}, },
{ {
"root": "pkg_user", "root": "pkg_user",
"pages": [ "pages": [
{
"path": "views/giftList",
"style": {
"navigationBarTitleText": "我的礼品卡"
}
},
{
"path": "views/gift/gift",
"style": {
"navigationBarTitleText": "送礼包"
}
},
{
"path": "views/gift/receive",
"style": {
"navigationBarTitleText": "好友赠送的礼包"
}
},
{
"path": "views/gift/receiveDone",
"style": {
"navigationBarTitleText": "收礼完成",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{ {
"path": "views/myFavorite", "path": "views/myFavorite",
"style": { "style": {
@@ -765,41 +739,6 @@
} }
] ]
}, },
{
"root": "aiChat",
"pages": [
{
"path": "views/index",
"style": {
"navigationBarTitleText": "云灵",
"navigationStyle": "custom",
"navigationBarTextStyle": "white"
}
},
{
"path": "views/history",
"style": {
"navigationBarTitleText": "云灵",
"navigationStyle": "custom",
"navigationBarTextStyle": "white"
}
},
{
"path": "views/imageRecognition",
"style": {
"navigationBarTitleText": "拍照识图",
"navigationStyle": "custom",
"navigationBarTextStyle": "white"
}
},
{
"path": "views/imageRecognitionResult",
"style": {
"navigationBarTitleText": "云灵"
}
}
]
},
{ {
"root": "v4", "root": "v4",
"pages": [ "pages": [
@@ -894,213 +833,6 @@
} }
} }
] ]
},
{
"root": "pagesOrder",
"pages": [
{
"path": "order/GoodsReturn/index",
"style": {
"navigationBarTitleText": "申请退款"
}
},
{
"path": "order/Logistics/index",
"style": {
"navigationBarTitleText": "查看物流"
}
},
{
"path": "order/OrderDetails/index",
"style": {
"navigationBarTitleText": "订单详情"
}
},
{
"path": "order/ReturnList/index",
"style": {
"navigationBarTitleText": "退货列表"
}
}
]
},
{
"root": "pagesShop",
"pages": [
{
"path": "shop/EvaluateList/index",
"style": {
"navigationBarTitleText": "评价列表"
}
},
{
"path": "shop/GoodsCollection/index",
"style": {
"navigationBarTitleText": "商品收藏"
}
},
{
"path": "shop/GoodsEvaluate/index",
"style": {
"navigationBarTitleText": "商品评价"
}
},
{
"path": "shop/GoodsPromotion/index",
"style": {
"navigationBarTitleText": "商品促销"
}
},
{
"path": "shop/StoreList/index",
"style": {
"navigationBarTitleText": "商家列表"
}
}
]
},
{
"root": "pagesUser",
"pages": [
{
"path": "user/CustomerList/index",
"style": {
"navigationBarTitleText": "客服列表"
}
},
{
"path": "user/History/index",
"style": {
"navigationBarTitleText": "商品足迹",
"navigationBarBackgroundColor": "#FFFFFF",
"enablePullDownRefresh": false
}
},
{
"path": "user/MemberUpgradeIntro/MemberUpgradeIntro",
"style": {
"navigationBarTitleText": "升级介绍"
}
},
{
"path": "user/Message/Message",
"style": {
"navigationBarTitleText": "消息",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "user/MessageDetail/MessageDetail",
"style": {
"navigationBarTitleText": "消息详情",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "user/ModifyPayPassword/ModifyPayPassword",
"style": {
"navigationBarTitleText": "评价列表"
}
},
{
"path": "user/Points/index",
"style": {
"navigationBarTitleText": "积分"
}
},
{
"path": "user/Recharge/index",
"style": {
"navigationBarTitleText": "充值"
}
},
{
"path": "user/RetrievePassword/index",
"style": {
"navigationBarTitleText": "找回密码"
}
},
{
"path": "user/UpgradeElectronicProtocol/UpgradeElectronicProtocol",
"style": {
"navigationBarTitleText": "升级电子协议"
}
},
{
"path": "user/UpgradeProtocolDetail/UpgradeProtocolDetail",
"style": {
"navigationBarTitleText": "升级电子协议详情"
}
},
{
"path": "user/UserAccount/index",
"style": {
"navigationBarTitleText": "账户余额"
}
},
{
"path": "user/UserBill/index",
"style": {
"navigationBarTitleText": "账单记录"
}
},
{
"path": "user/UserFavorite/UserFavorite",
"style": {
"navigationBarTitleText": "我的喜欢"
}
},
{
"path": "user/UserVip/index",
"style": {
"navigationBarTitleText": "用户等级"
}
},
{
"path": "user/promotion/CashAudit/index",
"style": {
"navigationBarTitleText": "提现审核"
}
},
{
"path": "user/promotion/CommissionDetails/index",
"style": {
"navigationBarTitleText": "提现审核"
}
},
{
"path": "user/promotion/Poster/index",
"style": {
"navigationBarTitleText": "海报生成"
}
},
{
"path": "user/promotion/PromoterList/index",
"style": {
"navigationBarTitleText": "分销列表",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "user/promotion/PromoterOrder/index",
"style": {
"navigationBarTitleText": "分销详情"
}
},
{
"path": "user/promotion/UserCash/index",
"style": {
"navigationBarTitleText": "提现"
}
},
{
"path": "user/promotion/UserPromotion/index",
"style": {
"navigationBarTitleText": "团队管理",
"navigationBarBackgroundColor": "#FFFFFF"
}
}
]
} }
], ],
"preloadRule": { "preloadRule": {
@@ -1126,26 +858,26 @@
"list": [ "list": [
{ {
"pagePath": "pages/home/index", "pagePath": "pages/home/index",
"iconPath": "/static/images/tabbar/tabbar-01-on.png", "iconPath": "static/tabbar/icon-home.png",
"selectedIconPath": "/static/images/tabbar/tabbar-01-on.png", "selectedIconPath": "static/tabbar/icon-home-hot.png",
"text": "首页" "text": "首页"
}, },
{ {
"pagePath": "pages/cloud/haveFun", "pagePath": "pages/cloud/haveFun",
"iconPath": "/static/images/tabbar/tabbar-01-on.png", "iconPath": "static/tabbar/icon-land.png",
"selectedIconPath": "/static/images/tabbar/tabbar-01-on.png", "selectedIconPath": "static/tabbar/icon-land-hot.png",
"text": "寻趣味" "text": "寻趣味"
}, },
{ {
"pagePath": "pages/cart", "pagePath": "pages/cart",
"iconPath": "/static/images/tabbar/tabbar-01-on.png", "iconPath": "static/tabbar/icon-cart.png",
"selectedIconPath": "/static/images/tabbar/tabbar-01-on.png", "selectedIconPath": "static/tabbar/icon-cart-hot.png",
"text": "购物车" "text": "购物车"
}, },
{ {
"pagePath": "pages/user/User/index", "pagePath": "pages/user/User/index",
"iconPath": "/static/images/tabbar/tabbar-01-on.png", "iconPath": "static/tabbar/icon-user.png",
"selectedIconPath": "/static/images/tabbar/tabbar-01-on.png", "selectedIconPath": "static/tabbar/icon-user-hot.png",
"text": "我的" "text": "我的"
} }
] ]
@@ -1,16 +1,6 @@
<template> <template>
<view class=""> <view class="">
<video <video class="video" :show-fullscreen-btn="false" id="myVideo" autoplay :src="curPlayVideoUrl" @error="videoErrorCallback" controls></video>
class="video"
:show-fullscreen-btn="false"
:direction="videoDirection"
id="myVideo"
autoplay
:src="curPlayVideoUrl"
@loadedmetadata="handleLoadedMetadata"
@error="videoErrorCallback"
controls
></video>
</view> </view>
</template> </template>
<script> <script>
@@ -25,48 +15,19 @@ export default {
return { return {
curPlayVideoUrl:'', curPlayVideoUrl:'',
isVideoPopupShow:false, isVideoPopupShow:false,
pageKeyId: '', pageKeyId: ''
videoDirection: 90,
hasLoadedMetadata: false,
hasRequestedFullscreen: false
} }
}, },
onReady(res) { onReady: function(res) {
this.videoContext = uni.createVideoContext('myVideo'); this.videoContext = uni.createVideoContext('myVideo');
this.videoContext.requestFullScreen();
}, },
onLoad(options) { onLoad:function(e){
if (!options.click) { this.curPlayVideoUrl = e.videoUrl
uni.switchTab({ url: '/pages/home/index' })
return
}
this.curPlayVideoUrl = options.videoUrl
const id = options.id const id = options.id
this.pageKeyId = `findVideo_videoId_${id}` this.pageKeyId = `findVideo_videoId_${id}`
}, },
methods: { methods: {
handleLoadedMetadata(e) {
const detail = e.detail || {}
const width = Number(detail.width) || 0
const height = Number(detail.height) || 0
if (height > width && width > 0) {
this.videoDirection = 0
} else {
this.videoDirection = 90
}
this.hasLoadedMetadata = true
this.enterFullScreen()
},
enterFullScreen() {
if (!this.videoContext || !this.hasLoadedMetadata || this.hasRequestedFullscreen) {
return
}
this.hasRequestedFullscreen = true
this.videoContext.requestFullScreen({
direction: this.videoDirection
})
},
videoErrorCallback: function(e) { videoErrorCallback: function(e) {
uni.showModal({ uni.showModal({
content: e.target.errMsg, content: e.target.errMsg,
+14 -34
View File
@@ -7,23 +7,21 @@
</view> </view>
<view class="list" v-if="list.length"> <view class="list" v-if="list.length">
<view class="video-waterfalls-wrap"> <custom-waterfalls-flow :value="list" imageKey="cover">
<custom-waterfalls-flow :value="list" imageKey="cover"> <view class="item" v-for="(item,index) in list" :key="index" slot="slot{{index}}" @click="goDetail(item)">
<view class="item" v-for="(item,index) in list" :key="index" slot="slot{{index}}" @click="goDetail(item)"> <image class="cover" :src="item.cover" mode="widthFix"></image>
<image class="cover" :src="item.cover" mode="widthFix"></image> <view class="content">
<view class="content"> <view class="title more-t">{{ item.title }}</view>
<view class="title more-t">{{ item.title }}</view> <view class="footer flex jc-between ai-center">
<view class="footer flex jc-between ai-center"> <view class="visit flex ai-center">
<view class="visit flex ai-center"> <image class="icon" style="margin-right: 8rpx" :src="item.storeLogo" mode="scaleToFill"></image>
<image class="icon" style="margin-right: 8rpx" :src="item.storeLogo" mode="scaleToFill"></image> {{ item.storeName }}
{{ item.storeName }}
</view>
<image class="icon flex-0" :src="webUrl+'/20210806121203835373.png'" mode="scaleToFill"></image>
</view> </view>
<image class="icon flex-0" :src="webUrl+'/20210806121203835373.png'" mode="scaleToFill"></image>
</view> </view>
</view> </view>
</custom-waterfalls-flow> </view>
</view> </custom-waterfalls-flow>
</view> </view>
<view class="v4-nodata" v-else> <view class="v4-nodata" v-else>
@@ -53,11 +51,7 @@ export default {
pageKeyId: Object.freeze('findVideoList') pageKeyId: Object.freeze('findVideoList')
} }
}, },
onLoad(options) { onLoad() {
if (!options.click) {
uni.switchTab({ url: '/pages/home/index' })
return
}
this.getType() this.getType()
this.fetchList() this.fetchList()
}, },
@@ -100,7 +94,7 @@ export default {
}) })
}, },
goDetail(item) { goDetail(item) {
this.$yrouter.push("/pages/VideoPlayBackList/VideoPlayBackDetail?videoUrl=" + item.video + '&id=' + item.id + '&click=1') this.$yrouter.push("/pages/VideoPlayBackList/VideoPlayBackDetail?videoUrl=" + item.video + '&id=' + item.id)
} }
} }
} }
@@ -116,7 +110,6 @@ export default {
border-radius: 20rpx; border-radius: 20rpx;
background: #fff; background: #fff;
font-size: 26rpx; font-size: 26rpx;
white-space: nowrap;
} }
.active { .active {
@@ -128,19 +121,6 @@ export default {
.list { .list {
margin: 28rpx 32rpx; margin: 28rpx 32rpx;
.video-waterfalls-wrap {
direction: ltr;
/deep/ .waterfalls-flow {
direction: ltr;
text-align: left;
}
/deep/ .waterfalls-flow-column {
float: left !important;
}
}
.item { .item {
border-radius: 4rpx; border-radius: 4rpx;
background: #fff; background: #fff;
+32 -29
View File
@@ -131,7 +131,7 @@
<view class="v12-mt-3 v12-font-32 v12-dark-text v12-font-weight-600">发现家乡好物</view> <view class="v12-mt-3 v12-font-32 v12-dark-text v12-font-weight-600">发现家乡好物</view>
</view> </view>
<view class="btn-box"> <view class="btn-box">
<button class="btn-yes v12-primary" type="mini" @tap="getUserInfoProfile">快捷登录</button> <button class="btn-yes v12-primary" type="mini" v-if="canIUseGetUserProfile" @tap="getUserInfoProfile">快捷登录</button>
<!-- <button class="btn-no" type="default" @tap="back">拒绝</button> --> <!-- <button class="btn-no" type="default" @tap="back">拒绝</button> -->
</view> </view>
<view class="agree-box v12-align-center"> <view class="agree-box v12-align-center">
@@ -171,6 +171,7 @@ export default {
return { return {
webUrl: this.$VUE_APP_RESOURCES_URL, webUrl: this.$VUE_APP_RESOURCES_URL,
authorize: false, authorize: false,
canIUseGetUserProfile: false,
agreeInfo: {}, agreeInfo: {},
isAgree: [], isAgree: [],
show: false, show: false,
@@ -187,6 +188,9 @@ export default {
...mapState(['isAuthorization', '$deviceType', 'token']), ...mapState(['isAuthorization', '$deviceType', 'token']),
}, },
onLoad() { onLoad() {
if (wx.getUserProfile) {
this.canIUseGetUserProfile = true
}
// 先校验用户是否授权,如果没有授权,显示授权按钮 // 先校验用户是否授权,如果没有授权,显示授权按钮
getAgree().then(({data}) => this.agreeInfo = data); getAgree().then(({data}) => this.agreeInfo = data);
}, },
@@ -223,19 +227,18 @@ export default {
}) })
}, },
doneRedirect() { doneRedirect() {
let redirectUrl = cookie.get('redirect') || '' let redirectUrl = cookie.get('redirect') || "";
redirectUrl = redirectUrl.replace(/\ /g, '') redirectUrl = redirectUrl.replace(/\ /g, '');
// 如果已经是授权页,跳转主页 //如果已经是授权页,跳转主页
if (redirectUrl == '/pages/authorization/index' || redirectUrl.length === 0) { if (redirectUrl == '/pages/authorization/index' || redirectUrl.length === 0) {
redirectUrl = '/pages/home/index' redirectUrl = '/pages/home/index';
} }
this.$yrouter.reLaunch({ this.$yrouter.reLaunch({
path: redirectUrl path: redirectUrl,
}) })
}, },
getUserInfoProfile() { getUserInfoProfile() {
const _this = this if (!this.isAgree[0]) {
if (!_this.isAgree[0]) {
uni.showToast({ uni.showToast({
title: "请先阅读并同意《用户服务协议及隐私政策》", title: "请先阅读并同意《用户服务协议及隐私政策》",
icon: "none", icon: "none",
@@ -243,33 +246,33 @@ export default {
}) })
return return
} }
wx.getUserProfile({ wx.getUserProfile({
lang: 'zh_CN', lang: 'zh_CN',
desc: '需要获取您的信息用来展示', desc: '需要获取您的信息用来展示',
success: res => { success: res => {
_this.loginReq(res) uni.showLoading({
} title: '登录中',
}) })
}, login(res).then(e => {
loginReq(res) { let db_nickname = e.data.nickname;
uni.showLoading({
title: '登录中' if (db_nickname === null || db_nickname === undefined || db_nickname === "" || db_nickname === "微信用户") {
}) this.showFillOut = true;
login(res).then(e => { } else {
const db_nickname = e.data.nickname this.doneRedirect();
if (db_nickname === null || db_nickname === undefined || db_nickname === '' || db_nickname === '微信用户') { }
this.showFillOut = true }).catch(error => {
} else { uni.showToast({
this.doneRedirect() title: error,
} icon: 'none',
}).catch(error => { duration: 2000,
uni.showToast({ })
title: error, })
icon: 'none', },
duration: 2000
})
}) })
}, },
onChooseAvatar(e) { onChooseAvatar(e) {
const {avatarUrl} = e.detail; const {avatarUrl} = e.detail;
this.avatarUrl = avatarUrl; this.avatarUrl = avatarUrl;
+298 -536
View File
File diff suppressed because it is too large Load Diff
+26 -131
View File
@@ -10,14 +10,14 @@
@confirm="search" @confirm="search"
> >
<image <image
:src="webUrl + '/orderIcon/search.png'" :src="webUrl + '/20220903142935869059.png'"
class="icon" class="icon"
mode="scaleToFill" mode="scaleToFill"
@click="search" @click="search"
/> />
</view> </view>
</view> </view>
<view class="aside" id="aside"> <view class="aside">
<view <view
v-for="(item, index) in listGroup" v-for="(item, index) in listGroup"
:key="index" :key="index"
@@ -44,7 +44,7 @@
<view class="fixed-box"> <view class="fixed-box">
<view class="line-location flex ai-center"> <view class="line-location flex ai-center">
<image :src="webUrl + '/20220903142929759087.png'" mode="scaleToFill"></image> <image :src="webUrl + '/20220903142929759087.png'" mode="scaleToFill"></image>
<text class="bold" v-if="location">当前城市{{ location }}</text> <text class="bold" v-if="location">当前定位{{ location }}</text>
<view style="color:#f66" @click="reload()" v-else>定位失败 <view style="color:#f66" @click="reload()" v-else>定位失败
<image :src="webUrl + '/20231215213824297278.png'" mode="scaleToFill" /> <image :src="webUrl + '/20231215213824297278.png'" mode="scaleToFill" />
</view> </view>
@@ -90,11 +90,7 @@
class="item flex-0 flex flex-col jc-between ai-center" class="item flex-0 flex flex-col jc-between ai-center"
@click="goToStore(item.hotelId || '')" @click="goToStore(item.hotelId || '')"
> >
<image <image class="cover" :src="item.hotelImage" mode="scaleToFill" />
:src="item.hotelImage + (item.hotelImage.indexOf('.mp4') > -1 ? '?vframe/jpg/offset/1' : '')"
class="cover"
mode="scaleToFill"
/>
<image class="logo" :src="item.hotelLogo" mode="scaleToFill" /> <image class="logo" :src="item.hotelLogo" mode="scaleToFill" />
<view style="width: 100%;box-sizing: border-box;padding:0 8rpx"> <view style="width: 100%;box-sizing: border-box;padding:0 8rpx">
<view class="name tc one-t">{{ item.hotelName }}</view> <view class="name tc one-t">{{ item.hotelName }}</view>
@@ -129,7 +125,7 @@
@click="select(item)" @click="select(item)"
> >
<view class="has-goods" v-if="type === 0 && item.hasData === 0">暂无特产</view> <view class="has-goods" v-if="type === 0 && item.hasData === 0">暂无特产</view>
<view class="has-goods" v-if="type > 0 && type < 6 && item.hasShop === 0 && item.hasAncientTown === 0">暂无店铺</view> <view class="has-goods" v-if="type > 0 && type < 6 && item.hasShop === 0">暂无店铺</view>
<view class="has-goods" v-if="type === 6 && item.hasData === 0">暂无景点</view> <view class="has-goods" v-if="type === 6 && item.hasData === 0">暂无景点</view>
<image :src="item.icon" mode="scaleToFill"></image> <image :src="item.icon" mode="scaleToFill"></image>
<view class="one-t">{{ item.cityName }}</view> <view class="one-t">{{ item.cityName }}</view>
@@ -137,7 +133,6 @@
</view> </view>
</mescroll-body> </mescroll-body>
</view> </view>
<FunctionGuide :maxStep="maxStep" @hide="setGuide(pageKeyId)" :guideData="functionGuideData" ref="FunctionGuide"></FunctionGuide>
</view> </view>
</template> </template>
@@ -147,14 +142,11 @@ import {fetchCity} from '@/api/wenwan'
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue' import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
import {getCurAddress, getLocation} from '@/utils/common.js' import {getCurAddress, getLocation} from '@/utils/common.js'
import { pageListenMixins } from '@/mixins/pageListenMixins' import { pageListenMixins } from '@/mixins/pageListenMixins'
import FunctionGuide from '@/components/FunctionGuide'
import GuideMixins from '@/mixins/GuideMixins'
export default { export default {
name: 'ChoseCity', name: 'ChoseCity',
components: { components: {
MescrollBody, MescrollBody
FunctionGuide
}, },
mixins: [ mixins: [
MescrollMixins({ MescrollMixins({
@@ -162,8 +154,7 @@ export default {
mescroll.endSuccess(10) mescroll.endSuccess(10)
} }
}), }),
pageListenMixins, pageListenMixins
GuideMixins
], ],
data() { data() {
return { return {
@@ -193,15 +184,6 @@ export default {
pageKeyId: '' pageKeyId: ''
} }
}, },
computed: {
maxStep() {
const stepsMap = {
0: 1,
1: 2,
}
return stepsMap[this.type] || 1
}
},
onLoad(options) { onLoad(options) {
const type = Number(options.type) const type = Number(options.type)
this.type = type this.type = type
@@ -230,79 +212,8 @@ export default {
this.getMapData() this.getMapData()
} }
this.init() this.init()
if([0,1] .includes(type)) {
this.queryGuide(this.pageKeyId)
}
}, },
methods: { methods: {
showFunctionGuide() {
if(this._step == this.functionGuideData.step) return
if(this.functionGuideData.step == 1) {
this._step = this.functionGuideData.step
const imgs = [
{
url: this.webUrl + '/引导页素材/全国特产/Group 1-1.png',
style: {
position: 'absolute',
zIndex: 99,
width: '357rpx',
top: '100rpx',
left: '-110rpx',
right: 0,
margin: 'auto',
height: '382rpx',
/* px: ; */
},
isBtn: false
},
{
url: this.webUrl + '/引导页素材/全国特产/Group 1-2.png',
style: {
position: 'absolute',
zIndex: 99,
width: '117rpx',
top: 125*2+'rpx',
left: -120*2+'rpx',
right: 0,
margin: 'auto',
height: '46rpx',
},
isBtn: 'jump'
},
{
url: this.webUrl + '/引导页素材/全国特产/Group 1-3.png',
style: {
position: 'absolute',
zIndex: 99,
width: '117rpx',
top: 125*2+'rpx',
left: 170*2+'rpx',
height: '46rpx',
},
isBtn: 'next'
},
]
this.getElementData('#aside', res=>{
this.setFunctionGuideData({
imgs: imgs,
tipsPosition: '420rpx',
btnGroupPosition: '',
position: {
top: res.top*2 + 'rpx',
left: res.left*2 + 'rpx',
width: `${res.width*2}rpx`,
height: `${res.height*2}rpx`,
}
})
})
return
} else {
if(this.type === 1) {
this.$refs.FunctionGuide.show = false
}
return
}
},
reload() { reload() {
uni.getSetting({ uni.getSetting({
success(res) { success(res) {
@@ -341,11 +252,10 @@ export default {
}, },
async getMapData() { async getMapData() {
const map = await getLocation() const map = await getLocation()
if (map.length > 1) { if (map) {
const {latitude, longitude} = map[1] const {latitude, longitude} = map[1]
getCurAddress(latitude, longitude, address => { const address = await getCurAddress(latitude, longitude)
this.location = address.city this.location = address[1].data.result.ad_info.city
})
} }
}, },
init() { init() {
@@ -384,27 +294,23 @@ export default {
this.mescroll && this.mescroll.triggerDownScroll() this.mescroll && this.mescroll.triggerDownScroll()
}, },
search() { search() {
const keyword = (this.keyword || '').trim() this.listGroup.findIndex((group, index) => {
if (!keyword) return let result
const matchIndex = this.listGroup.findIndex(group => { group.city.forEach(item => {
const cityList = Array.isArray(group.city) ? group.city : [] result = item.cityName.indexOf(this.keyword, 0)
return cityList.some(item => item && item.cityName && item.cityName.indexOf(keyword) !== -1) if (result !== -1) {
}) this.asideTap(index);
if (matchIndex !== -1) { return null;
this.keyword = keyword }
this.asideTap(matchIndex)
return
}
if (matchIndex === -1) {
uni.showToast({
title: '未找到该城市,请重新输入城市名称',
icon: 'none'
}) })
} if (result !== -1) {
return result
}
})
}, },
select(item) { select(item) {
if (this.type === 0 && item.hasData === 0) return if (this.type === 0 && item.hasData === 0) return
if ((this.type === 1 || this.type === 2) && item.hasShop === 0 && item.hasAncientTown === 0) return if ((this.type === 1 || this.type === 2) && item.hasShop === 0) return
uni.setStorageSync("cityName", item.cityName) uni.setStorageSync("cityName", item.cityName)
switch (this.type) { switch (this.type) {
@@ -444,14 +350,6 @@ export default {
url: `/pages/shop/GoodsCon/index?id=${productId}&from=${this.getOptionsParams()}` url: `/pages/shop/GoodsCon/index?id=${productId}&from=${this.getOptionsParams()}`
}) })
}, },
goToExhibition(linkExhibitionId) {
if (!linkExhibitionId) {
return
}
uni.navigateTo({
url: `/pkg_product/views/expoDetails?id=${linkExhibitionId}&from=${this.getOptionsParams()}`
})
},
getOptionsParams() { getOptionsParams() {
// 0、特产;1、文玩;2、七彩云上;3、特色礼品;4、康养食材;5、千县名品;6、景点门票 // 0、特产;1、文玩;2、七彩云上;3、特色礼品;4、康养食材;5、千县名品;6、景点门票
let from = '' let from = ''
@@ -494,9 +392,6 @@ export default {
case 2: case 2:
this.goToGoods(banner.linkProductId) this.goToGoods(banner.linkProductId)
break break
case 3:
this.goToExhibition(banner.linkExhibitionId)
break
default: default:
break break
} }
@@ -597,10 +492,10 @@ export default {
} }
.item.on { .item.on {
border-left: 6rpx solid #C52733; border-left: 6rpx solid #FD574B;
.name { .name {
color: #C52733; color: #FD574B;
font-weight: bold; font-weight: bold;
} }
} }
@@ -620,7 +515,7 @@ export default {
box-sizing: border-box; box-sizing: border-box;
margin: 18rpx 0; margin: 18rpx 0;
padding: 8rpx 0 0 8rpx; padding: 8rpx 0 0 8rpx;
border-left: 6rpx solid #C52733; border-left: 6rpx solid #FD574B;
color: #262626; color: #262626;
font-size: 30rpx; font-size: 30rpx;
line-height: 30rpx; line-height: 30rpx;
+316 -287
View File
@@ -1,19 +1,9 @@
<template> <template>
<view class="cloud-page"> <view class="cloud-page">
<view class="search-box flex"> <view class="search-box">
<view class="city-box" @click="goCity('cloud')"> <uni-search-bar placeholder="输入搜索关键词" @confirm="search" @clear="clearName"></uni-search-bar>
<image
:src="webUrl+'/20220903142929759087.png'"
mode="scaleToFill"
/>
<text>{{ cityName }}</text>
</view>
<uni-search-bar
placeholder="输入搜索关键词"
@confirm="search"
@clear="clearName"
/>
</view> </view>
<view class="nav-box"> <view class="nav-box">
<view <view
v-for="(item, index) in typeList" v-for="(item, index) in typeList"
@@ -22,331 +12,370 @@
@click="changeType(index)" @click="changeType(index)"
> >
<image :src="item.icon" mode="scaleToFill"></image> <image :src="item.icon" mode="scaleToFill"></image>
<view class="nav">{{ item.name }}</view> <view class="nav">{{item.name}}</view>
</view> </view>
</view> </view>
<view class="list-box"> <view class="list-box">
<view <text class="type-name">{{typeList[type]['name']}}</text>
v-if="hotelList.length"
class="list" <view class="city-box" @click="goCity('cloud')">
> <image :src="webUrl+'/20220903142929759087.png'" mode="scaleToFill"></image>
<text>{{cityName}}</text>
</view>
<view class="list" v-if="hotelList.length">
<custom-waterfalls-flow :value="hotelList" imageKey="cover"> <custom-waterfalls-flow :value="hotelList" imageKey="cover">
<view <view class="item" v-for="(item,index) in hotelList" :key="index" slot="slot{{index}}"
v-for="(item,index) in hotelList" @click="goInnDetail(item)">
:key="index"
slot="slot{{index}}"
class="item"
@click="goInnDetail(item)"
>
<view class="cover-box"> <view class="cover-box">
<image <image class="cover" :src="item.cover" mode="scaleToFill"></image>
:src="item.cover"
mode="scaleToFill"
class="cover"
/>
<view class="my-mask"> <view class="my-mask">
<image <image class="icon" :src="webUrl+'/20220510142728577618.png'" mode="scaleToFill"></image>
class="icon" <text>{{item.cityName}}</text>
:src="webUrl+'/20220510142728577618.png'"
mode="scaleToFill"
/>
<text>{{ item.cityName }}</text>
</view> </view>
</view> </view>
<view class="more-t">{{ item.content }}</view> <view class="more-t">{{item.content}}</view>
<view class="flex ai-center" style="margin-bottom: 18rpx;"> <view class="flex ai-center" style="margin-bottom: 18rpx;">
<image <image class="logo" :src="item.logo" mode="scaleToFill"></image>
class="logo" <text class="one-t">{{item.name}}</text>
:src="item.logo"
mode="scaleToFill"
/>
<text class="one-t">{{ item.name }}</text>
</view> </view>
</view> </view>
</custom-waterfalls-flow> </custom-waterfalls-flow>
</view> </view>
<view class="v4-nodata" v-else> <view class="v4-nodata" v-else>
<image src="@/static/images/img_nodata.png" mode="scaleToFill" /> <image src="@/static/images/img_nodata.png" mode="scaleToFill" />
<view class="text">暂无数据</view> <view class="text">暂无数据</view>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import { getCurAddress, getLocation } from "@/utils/common" import config from '@/utils/mapConfig';
import { import {
getHotelTypeList, getHotelTypeList,
getHotelList getHotelList
} from '@/api/inn.js' } from "@/api/inn.js";
export default {
data() { export default {
return { data() {
webUrl: this.$VUE_APP_RESOURCES_URL, return {
typeList: [], webUrl: this.$VUE_APP_RESOURCES_URL,
name: '', typeList: [],
page: 1, name: "",
type: 0, page: 1,
// 跳转初始分类名 type: 0,
tabName: '', tabName: "", // 跳转初始分类名
hotelList: [], hotelList: [],
cityName: '丽江市', cityName: "丽江市",
paramCity: '' paramCity: ""
}
},
onLoad(){
this.fetchTypeList()
},
onShow() {
const name = uni.getStorageSync('name')
if (name) {
this.tabName = name
uni.removeStorageSync('name')
}
const memCityName = uni.getStorageSync('cityName')
if (memCityName.length) {
this.cityName = memCityName
this.paramCity = memCityName
this.page = 1
this.hotelList = []
this.fetchList()
uni.removeStorageSync('cityName')
}
},
onReachBottom() {
this.page++
this.fetchList()
},
methods: {
goCity() {
uni.navigateTo({
url:`/pages/chose-city/chose-city?type=2&city=${this.cityName}`
})
},
//获取当前定位地址
async getCurAddressFn() {
const that = this
uni.showLoading({
title: '定位中...'
})
const map = await getLocation()
if (map.length > 1) {
const {latitude, longitude} = map[1]
getCurAddress(latitude, longitude, address => {
that.cityName = address.city
that.paramCity = address.city
})
} }
}, },
fetchTypeList() { onLoad(){
this.hotelList = [] this.fetchTypeList()
getHotelTypeList().then(res => { },
const { status, data } = res onShow() {
if (status === 200) { let name = uni.getStorageSync("name");
for (let i = 0; i < data.length; i++) { if (name) {
if (this.tabName == data[i].name) { this.tabName = name;
this.type = i uni.removeStorageSync("name");
}
let memCityName = uni.getStorageSync("cityName")
if (memCityName.length) {
this.cityName = memCityName;
this.paramCity = memCityName;
this.page = 1;
this.hotelList = [];
this.fetchList();
uni.removeStorageSync("cityName")
}
},
onReachBottom() {
this.page++;
this.fetchList();
},
methods: {
goCity() {
uni.navigateTo({
url:`/pages/chose-city/chose-city?type=2&city=${this.cityName}`
})
},
//获取当前定位地址
getCurAddress() {
var that = this;
//定位
uni.showLoading({
title: '定位中...'
});
uni.getLocation({
type: 'wgs84',
success: function(res) {
let latitude = res.latitude;
let longitude = res.longitude;
// #ifdef H5
Vue.jsonp(
'https://apis.map.qq.com/ws/geocoder/v1/?location=' + latitude + ',' + longitude + '&key=' +
config.key, {
output: 'jsonp',
}).then(json => {
// Success.
uni.hideLoading();
that.cityName = json.result.ad_info.city;
that.paramCity = json.result.ad_info.city;
//定位成功刷新数据
that.fetchList()
}).catch(err => {
uni.hideLoading();
})
// #endif
// #ifndef H5
uni.request({
url: 'https://apis.map.qq.com/ws/geocoder/v1/?location=' + latitude + ',' + longitude +
'&key=' + config.key,
success: function(res) {
uni.hideLoading();
that.cityName = res.data.result.ad_info.city;
that.paramCity = res.data.result.ad_info.city;
//定位成功刷新数据
that.fetchList()
},
fail: function(res) {
uni.hideLoading();
},
complete: function() {}
});
// #endif
},
fail: function(res) {
uni.hideLoading();
}
});
},
fetchTypeList() {
this.hotelList = []
getHotelTypeList().then(res => {
if (res.status === 200) {
for (let i = 0; i < res.data.length; i++) {
if (this.tabName == res.data[i].name) this.type = i;
}
this.typeList = res.data
let memCityName = uni.getStorageSync("cityName")
if (memCityName.length) {
this.cityName = memCityName;
this.paramCity = memCityName;
this.page = 1;
this.list = [];
this.fetchList();
uni.removeStorageSync("cityName")
} else {
this.getCurAddress();
} }
} }
this.typeList = data })
const memCityName = uni.getStorageSync('cityName') },
if (memCityName.length) { search(e) {
this.cityName = memCityName this.name = e.value;
this.paramCity = memCityName this.page = 1;
this.page = 1 this.hotelList = [];
this.list = [] this.fetchList();
this.fetchList() },
uni.removeStorageSync('cityName')
} else { clearName() {
this.getCurAddressFn() this.name = "";
this.page = 1;
this.hotelList = [];
this.fetchList();
},
changeType(index) {
this.type = index;
this.page = 1;
this.hotelList = [];
this.fetchList();
},
fetchList() {
getHotelList({
name: this.name,
page: this.page,
type: this.typeList[this.type].id,
cityName: this.paramCity
}).then(res => {
if (res.status === 200) {
this.paramCity = this.cityName;
for (let i = 0; i < res.data.length; i++) {
res.data[i].hide = true;
this.hotelList.push(res.data[i])
}
} }
} })
}) },
},
search(e) { goInnDetail: function(item) {
this.name = e.value //跳转到客栈详情
this.page = 1 this.$yrouter.push({
this.hotelList = [] path: "/pagesInn/inn/innHome",
this.fetchList() query: {
}, id: item.id
clearName() {
this.name = ''
this.page = 1
this.hotelList = []
this.fetchList()
},
changeType(index) {
this.type = index
this.page = 1
this.hotelList = []
this.fetchList()
},
fetchList() {
getHotelList({
name: this.name,
page: this.page,
type: this.typeList[this.type].id,
cityName: this.paramCity
}).then(res => {
if (res.status === 200) {
this.paramCity = this.cityName
for (let i = 0; i < res.data.length; i++) {
res.data[i].hide = true
this.hotelList.push(res.data[i])
} }
} });
}) },
},
goInnDetail(item) {
//跳转到客栈详情
this.$yrouter.push({
path: '/pagesInn/inn/innHome',
query: {
id: item.id
}
})
} }
} }
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.cloud-page { .cloud-page {
.search-box { .search-box {
padding: 0 12rpx; padding: 0 12rpx;
background: #fff; background: #fff;
/deep/.uni-searchbar__box { /deep/.uni-searchbar__box {
border-radius: 44rpx !important; border-radius: 44rpx !important;
} }
}
.city-box {
position: absolute;
right: 30rpx;
display: inline-flex;
align-items: center;
margin-left: 32rpx;
padding: 8rpx 18rpx 8rpx 16rpx;
border-radius: 30px;
background: #fff;
image {
width: 32rpx;
height: 32rpx;
margin-right: 4rpx;
} }
text { .city-box {
color: #333; position: absolute;
font-size: 28rpx; right: 30rpx;
} display: inline-flex;
}
.nav-box {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16rpx 36rpx 24rpx;
background: #fff;
overflow-x: auto;
.item {
display: flex;
flex-direction: column;
align-items: center; align-items: center;
margin-left: 70rpx; margin-left: 32rpx;
padding: 8rpx 18rpx 8rpx 16rpx;
border-radius: 30px;
background: #fff;
image { image {
width: 64rpx; width: 32rpx;
height: 64rpx; height: 32rpx;
margin-right: 4rpx;
} }
.nav { text {
color: #666; color: #333;
font-size: 24rpx; font-size: 28rpx;
line-height: 34rpx;
font-weight: bold;
} }
} }
.item:first-child { .nav-box {
margin-left: 0; display: flex;
} justify-content: space-between;
} align-items: center;
padding: 16rpx 36rpx 24rpx;
background: #fff;
overflow-x: auto;
::-webkit-scrollbar { .item {
display: none; display: flex;
} flex-direction: column;
align-items: center;
margin-left: 70rpx;
.list-box { image {
padding: 20rpx 32rpx; width: 64rpx;
height: 64rpx;
}
.type-name { .nav {
position: relative; color: #666;
font-size: 28rpx; font-size: 24rpx;
line-height: 40rpx; line-height: 34rpx;
color: #080F1A; font-weight: bold;
}
.type-name::before {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 10rpx;
background: rgba(253, 104, 93, 0.39);
z-index: -1;
}
.list {
margin-top: 20rpx;
.cover {
width: 332rpx;
height: 332rpx;
vertical-align: middle;
}
.icon {
width: 22rpx;
height: 22rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.logo {
width: 36rpx;
height: 36rpx;
vertical-align: middle;
margin: 0 8rpx;
border-radius: 50%;
}
.cover-box {
position: relative;
height: auto;
.my-mask {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 56rpx;
line-height: 56rpx;
box-sizing: border-box;
padding: 0 24rpx;
background: linear-gradient(rgba(51, 51, 51, 0), rgba(0, 0, 0, 1));
color: #fff;
font-size: 22rpx;
} }
} }
.more-t { .item:first-child {
margin: 10rpx; margin-left: 0;
}
}
::-webkit-scrollbar {
display: none;
}
.list-box {
padding: 20rpx 32rpx;
.type-name {
position: relative;
font-size: 28rpx;
line-height: 40rpx;
color: #080F1A;
}
.type-name::before {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 10rpx;
background: rgba(253, 104, 93, 0.39);
z-index: -1;
}
.list {
margin-top: 20rpx;
.cover {
width: 332rpx;
height: 332rpx;
vertical-align: middle;
}
.icon {
width: 22rpx;
height: 22rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.logo {
width: 36rpx;
height: 36rpx;
vertical-align: middle;
margin: 0 8rpx;
border-radius: 50%;
}
.cover-box {
position: relative;
height: auto;
.my-mask {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 56rpx;
line-height: 56rpx;
box-sizing: border-box;
padding: 0 24rpx;
background: linear-gradient(rgba(51, 51, 51, 0), rgba(0, 0, 0, 1));
color: #fff;
font-size: 22rpx;
}
}
.more-t {
margin: 10rpx;
}
} }
} }
} }
}
</style> </style>
+9 -20
View File
@@ -17,22 +17,18 @@
</view> </view>
<view class="more-t">{{ item.content }}</view> <view class="more-t">{{ item.content }}</view>
<view class="flex ai-center bottom"> <view class="flex ai-center bottom">
<view <image
v-if="item.logo"
:src="item.logo"
class="logo" class="logo"
> mode="scaleToFill"
<image ></image>
v-if="item.logo" <image
:src="item.logo"
class="logo"
mode="scaleToFill"
></image>
<image
v-else v-else
:src="webUrl + '/20230609145651814148.png'" :src="webUrl + '/20230609145651814148.png'"
class="logo" class="logo"
/> />
</view> <text class="one-t">{{ item.name }}</text>
<text class="one-t v12-ml-1">{{ item.name }}</text>
</view> </view>
</view> </view>
</template> </template>
@@ -55,12 +51,6 @@ export default {
} }
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.logo {
width: 46rpx;
height: 46rpx;
vertical-align: middle;
border-radius: 50%;
}
.cover-box-wrap { .cover-box-wrap {
margin: 20rpx 0 0 0; margin: 20rpx 0 0 0;
.cover-box { .cover-box {
@@ -83,8 +73,8 @@ export default {
vertical-align: middle; vertical-align: middle;
} }
.logo { .logo {
width: 46rpx; width: 36rpx;
height: 46rpx; height: 36rpx;
vertical-align: middle; vertical-align: middle;
margin: 0 8rpx; margin: 0 8rpx;
border-radius: 50%; border-radius: 50%;
@@ -115,7 +105,6 @@ export default {
} }
.bottom { .bottom {
margin: 0 0 20rpx 0; margin: 0 0 20rpx 0;
align-content: center;
} }
} }
</style> </style>
+51 -471
View File
@@ -3,12 +3,11 @@
<view class="top-box"> <view class="top-box">
<view class="v12-justify-start v12-align-center"> <view class="v12-justify-start v12-align-center">
<view class="flex jc-end"> <view class="flex jc-end">
<view class="city-box" @click="goCity('cloud')" id="city-box"> <view class="city-box" @click="goCity('cloud')">
<text style="white-space:nowrap; width: 90rpx" class="v12-primary-text one-t">{{ cityName }}</text> <text style="white-space:nowrap; width: 90rpx" class="v12-primary-text one-t">{{ cityName }}</text>
<image :src="webUrl+'/icon/fun-city-change.png'" mode="scaleToFill"></image> <image :src="webUrl+'/orderIcon/map.png'" mode="scaleToFill"></image>
</view> </view>
</view> </view>
<view class="search-box v12-primary-border flex jc-between ai-center"> <view class="search-box v12-primary-border flex jc-between ai-center">
<input <input
v-model="name" v-model="name"
@@ -27,56 +26,22 @@
</view> </view>
</view> </view>
</view> </view>
<view class="v12-pa-2" style="position: relative"> <scroll-view class="type-box flex" scroll-x enable-flex>
<view class="v12-radius-20 v12-px-2 v12-py-1 tip-wrap v12-align-center v12-justify-between"> <view
<view class="v12-align-center"> v-for="(item, index) in typeList"
<image :key="index"
class="map-icon" :class="{
mode="scaleToFill" 'active': typeIndex === index
:src="webUrl + '/orderIcon/map_white.png'" }"
></image> class="item flex-0 flex flex-col jc-center ai-center"
<text style="width: 95%" class="v12-font-24 v12-white-text">定位显示你在 {{ cityName }} 点击可切换其他城市</text> @click="tapType(index)"
</view> >
<view @click="goCity('cloud')" class="qh-btn v12-white v12-radius-10 v12-font-24 v12-font-bold v12-dark-text v12-px-2">点击切换</view> <image :src="item.icon" mode="scaleToFill"/>
<view class="name">{{ item.name }}</view>
</view> </view>
</view> </scroll-view>
<view>
<view class="type-box flex" id="type-box">
<view class="first-box">
<view class="first-box__inner">
<view
:class="{
'active': typeIndex === -1
}"
class="item flex-0 flex flex-col jc-center ai-center"
@click="tapType(-1)"
>
<image :src="townConfig.icon" mode="scaleToFill"/>
<view class="name">{{ townConfig.label }}</view>
</view>
</view>
</view>
<!-- <view style="padding-left: 0" class="type-box flex " >
</view> -->
<view class="scroll-box">
<view
v-for="(item, index) in typeList"
:key="index"
:class="{
'active': typeIndex === index
}"
class="item flex-0 flex flex-col jc-center ai-center"
@click="tapType(index)"
>
<image :src="item.icon" mode="scaleToFill"/>
<view class="name">{{ item.name }}</view>
</view>
</view>
</view>
</view>
</view> </view>
<view class="type-banner-wrap" v-if="typeIndex !== -1"> <view class="type-banner-wrap">
<view v-if="currType.titleImage" class="title"> <view v-if="currType.titleImage" class="title">
<image <image
:src="currType.titleImage" :src="currType.titleImage"
@@ -84,7 +49,7 @@
class="img" class="img"
/> />
</view> </view>
<view v-if="hotelBanner.length" class="slider-wrap"> <view v-if="currType.carousel" class="slider-wrap">
<swiper <swiper
indicatorDots="true" indicatorDots="true"
indicator-color="rgba(255, 255, 255, .3)" indicator-color="rgba(255, 255, 255, .3)"
@@ -94,38 +59,21 @@
style="height: 330rpx;" style="height: 330rpx;"
> >
<block <block
v-for="(item, bannerIndex) in hotelBanner" v-for="(item, bannerIndex) in currType.carousel"
:key="bannerIndex" :key="bannerIndex"
> >
<swiper-item> <swiper-item>
<view class="swiper-item" @click="typeBannerItemClick(item)"> <view class="swiper-item" @click="typeBannerItemClick(item)">
<image :src="item.bannerImage" class="img" /> <image :src="item.carouselImage" class="img" />
</view> </view>
</swiper-item> </swiper-item>
</block> </block>
</swiper> </swiper>
</view> </view>
</view> </view>
<view class="body" v-if="typeIndex === -1" id="body1"> <view class="body">
<view class="town-card" v-for="(town, i) in townList" :key="i" @click="toTown(town)"> <view>
<!-- <view class="town-title">{{ town.name }}</view> --> <text class="v12-font-bold" v-if="currType.carousel">推荐</text>
<image :src="town.frontImage" mode="scaleToFill"/>
<view class="v12-primary enter-btn">点击进入
<view class="icon-box"><u-icon name="arrow-rightward" color="#fff" size="8"></u-icon></view>
</view>
</view>
<view class="v4-nodata" v-if="townList.length === 0">
<image src="@/static/images/img_nodata.png" mode="scaleToFill"/>
<view class="text">暂无数据</view>
</view>
</view>
<view class="body" v-else>
<view class="v12-justify-between v12-align-center" v-if="hotelList.length > 0">
<text class="v12-font-bold" v-if="hotelBanner.length">推荐</text>
<view class="v12-dark1-text v12-font-28 v12-align-center refresh-btn" @click="handleRefresh">
<u-icon name="reload"></u-icon>
换一换
</view>
</view> </view>
<view v-if="isLoad"> <view v-if="isLoad">
<view v-if="hotelList.length > 0"> <view v-if="hotelList.length > 0">
@@ -162,51 +110,35 @@
:show-avatar="false" :show-avatar="false"
/> />
</view> </view>
<FunctionGuide @hide="setGuide('findFunIndex')" :maxStep="3" :guideData="functionGuideData" ref="FunctionGuide"></FunctionGuide>
<AiEntrance
:city-name="cityName"
/>
<xdd-tabbar :curr-index="4" /> <xdd-tabbar :curr-index="4" />
</view> </view>
</template> </template>
<script> <script>
import { getHotelList, getHotelTypeList, getAncientTownIcon, getAncientTownList, getHotelBanner } from "@/api/inn.js" import { getHotelList, getHotelTypeList } from "@/api/inn.js"
import { fetchCity } from "@/api/wenwan"
import { getCurAddress, getLocation } from "@/utils/common" import { getCurAddress, getLocation } from "@/utils/common"
import FunHotelItem from './components/HotelItem' import FunHotelItem from './components/HotelItem'
import { pageListenMixins } from '@/mixins/pageListenMixins' import { pageListenMixins } from '@/mixins/pageListenMixins'
import XddTabbar from '@/components/xdd-tabbar' import XddTabbar from '@/components/xdd-tabbar'
import FunctionGuide from '@/components/FunctionGuide'
import AiEntrance from '@/components/aiChat/entrance'
import GuideMixins from '@/mixins/GuideMixins'
export default { export default {
components: { components: {
FunHotelItem, FunHotelItem,
XddTabbar, XddTabbar
FunctionGuide,
AiEntrance
}, },
mixins: [pageListenMixins, GuideMixins], mixins: [pageListenMixins],
data() { data() {
return { return {
webUrl: this.$VUE_APP_RESOURCES_URL, webUrl: this.$VUE_APP_RESOURCES_URL,
name: '', name: '',
page: 1, page: 1,
typeList: [], typeList: [],
typeIndex: -1, typeIndex: 0,
// 当前选中的类型 // 当前选中的类型
currType: {}, currType: {},
cityName: '', cityName: '',
hotelList: [], hotelList: [],
isLoad: false, isLoad: false,
pageKeyId: Object.freeze('findFunIndex'), pageKeyId: Object.freeze('findFunIndex'),
isNext: false, isNext: false
townConfig: {},
townList: [],
randomSeed: null,
hotelBanner: [],
goodCityId: '',
cityOptions: []
} }
}, },
computed: { computed: {
@@ -223,29 +155,23 @@ export default {
// 后端接口结构需要调整下,需要补充总页数,前端可判断当前页数大于等于总页数则不发送网络请求 // 后端接口结构需要调整下,需要补充总页数,前端可判断当前页数大于等于总页数则不发送网络请求
if(this.isNext) { if(this.isNext) {
this.page++ this.page++
const random = this.randomSeed ? 1 : 0 this.fetchList()
this.fetchList(random, this.randomSeed)
} }
}, },
onLoad(options) { onLoad() {
this.currType = {}
if (options && options.city) {
this.goodCityId = options.city
}
this.initGoodCity()
getHotelTypeList().then(({data}) => {
this.typeList = data
this.currType = this.typeIndex === -1 ? {} : data[this.typeIndex]
this.getMapData()
})
this.getIcon()
this.queryGuide('findFunIndex')
}, },
onShow() { onShow() {
uni.$emit('updateUnreadMessageCount')
const memCityName = uni.getStorageSync('cityName') const memCityName = uni.getStorageSync('cityName')
// this.typeIndex = 0 this.page = 1
this.currType = {}
this.typeIndex = 0
this.name = '' this.name = ''
getHotelTypeList().then(({data}) => {
this.typeList = data
this.currType = data[this.typeIndex]
this.getMapData()
})
if (memCityName.length) { if (memCityName.length) {
this.cityName = memCityName this.cityName = memCityName
uni.removeStorageSync('cityName') uni.removeStorageSync('cityName')
@@ -255,8 +181,7 @@ export default {
watch: { watch: {
cityName: { cityName: {
handler(value) { handler(value) {
if (value) { if(value) {
this.updateGoodCityId()
this.search() this.search()
} }
}, },
@@ -265,217 +190,6 @@ export default {
} }
}, },
methods: { methods: {
showFunctionGuide() {
if(this._step == this.functionGuideData.step) return
if(this.functionGuideData.step == 1) {
this._step = this.functionGuideData.step
this.getElementData('#city-box', res=>{
const imgs = [
{
url: this.webUrl + '/引导页素材/寻趣味/Group 1/Group 1-1.png',
style: {
position: 'absolute',
zIndex: 99,
width: '390rpx',
top: 0*2+'rpx',
left: res.width*2+'rpx',
height: '162rpx',
/* px: ; */
},
isBtn: false
},
{
url: this.webUrl + '/引导页素材/寻趣味/Group 1/Group 1-2.png',
style: {
position: 'absolute',
zIndex: 99,
width: '117rpx',
top: 80*2+'rpx',
left: -60*2+'rpx',
right: 0,
margin: 'auto',
height: '46rpx',
},
isBtn: 'jump'
},
{
url: this.webUrl + '/引导页素材/寻趣味/Group 1/Group 1-3.png',
style: {
position: 'absolute',
zIndex: 99,
width: '117rpx',
top: 80*2+'rpx',
left: 200*2+'rpx',
height: '46rpx',
},
isBtn: 'next'
},
]
this.setFunctionGuideData({
imgs: imgs,
tipsPosition: '420rpx',
btnGroupPosition: '',
position: {
top: res.top + 'px',
left: res.left + 'px',
width: `${res.width}px`,
height: `${res.height}px`,
}
})
})
return
} else {
if(this.functionGuideData.step == 2) {
this._step = this.functionGuideData.step
this.getElementData('#type-box', res=>{
const imgs = [
{
url: this.webUrl + '/引导页素材/寻趣味/Group 2/Group 2-1.png',
style: {
position: 'absolute',
zIndex: 99,
width: '504rpx',
top: 170*2+'rpx',
left: 0+'rpx',
right: 0,
margin: 'auto',
height: '191rpx',
/* px: ; */
},
isBtn: false
},
{
url: this.webUrl + '/引导页素材/寻趣味/Group 2/Group 2-3.png',
style: {
position: 'absolute',
zIndex: 99,
width: '117rpx',
top: 270*2+'rpx',
left: -160*2+'rpx',
right: 0,
margin: 'auto',
height: '46rpx',
},
isBtn: 'jump'
},
{
url: this.webUrl + '/引导页素材/寻趣味/Group 2/Group 2-2.png',
style: {
position: 'absolute',
zIndex: 99,
width: '117rpx',
top: 270*2+'rpx',
left: 160*2+'rpx',
height: '46rpx',
},
isBtn: 'next'
},
]
this.setFunctionGuideData({
imgs: imgs,
tipsPosition: '420rpx',
btnGroupPosition: '',
position: {
top: res.top + 'px',
left: res.left + 'px',
width: `${res.width}px`,
height: `${(res.height-20)}px`,
}
})
})
return
}
if(this.functionGuideData.step == 3) {
this._step = this.functionGuideData.step
this.getElementData('#body1', res=>{
const imgs = [
{
url: this.webUrl + '/引导页素材/寻趣味/Group 3/Group 3-1.png',
style: {
position: 'absolute',
zIndex: 99,
width: '290rpx',
top: 90*2+'rpx',
left: 0,
right: 0,
margin: 'auto',
height: '165rpx',
/* px: ; */
},
isBtn: false
},
{
url: this.webUrl + '/引导页素材/寻趣味/Group 3/Group 3-2.png',
style: {
position: 'absolute',
zIndex: 99,
width: '97rpx',
top: 60*2+'rpx',
left: 60*2+'rpx',
right: 0,
margin: 'auto',
height: '55rpx',
},
isBtn: 'jump'
},
]
this.setFunctionGuideData({
imgs: imgs,
tipsPosition: '420rpx',
btnGroupPosition: '',
position: {
top: (res.top) + 'px',
left: res.left+10 + 'px',
width: `${res.width-20}px`,
height: `${res.height-20}px`,
}
})
})
return
}
return
}
},
handleRefresh() {
uni.showLoading()
this.page = 1
this.hotelList = []
this.fetchList(1, this.randomSeed)
},
toTown(town) {
uni.navigateTo({
url: `/pages/town/index?id=${town.id}`
})
},
getIcon() {
getAncientTownIcon().then(res => {
this.townConfig = res.data
})
},
initGoodCity() {
fetchCity(2).then(({ data }) => {
const group = data && data.group ? data.group : []
const list = []
group.forEach(item => {
if (item.city && item.city.length) {
list.push(...item.city)
}
})
this.cityOptions = list
this.updateGoodCityId()
})
},
updateGoodCityId() {
if (!this.cityOptions.length || !this.cityName) return
const found = this.cityOptions.find(item => item.cityName === this.cityName)
if (found) {
this.goodCityId = found.id || found.cityId || this.goodCityId
this.fetchHotelBanner()
}
},
goCity() { goCity() {
uni.navigateTo({ uni.navigateTo({
url: `/pages/chose-city/chose-city?type=2&city=${this.cityName}` url: `/pages/chose-city/chose-city?type=2&city=${this.cityName}`
@@ -488,19 +202,19 @@ export default {
}, },
async getMapData() { async getMapData() {
const map = await getLocation() const map = await getLocation()
if (map.length > 1 && !this.cityName) { if (map.length > 1) {
const {latitude, longitude} = map[1] const {latitude, longitude} = map[1]
getCurAddress(latitude, longitude, address => { const address = await getCurAddress(latitude, longitude)
this.cityName = address.city if(!this.cityName) {
}) this.cityName = address[1].data.result.ad_info.city
}
// this.search()
} }
}, },
tapType(index) { tapType(index) {
if (this.typeIndex === index) return if (this.typeIndex === index) return
this.typeIndex = index this.typeIndex = index
this.randomSeed = null this.currType = this.typeList[index]
this.currType = index === -1 ? {} : this.typeList[index]
this.name = '' this.name = ''
this.search() this.search()
}, },
@@ -510,35 +224,19 @@ export default {
this.hotelList = [] this.hotelList = []
this.fetchList() this.fetchList()
}, },
fetchList(random = 0, randomSeed) { fetchList() {
if(this.typeIndex === -1) {
const params = {
cityName: this.cityName,
page: 1,
limit: 999
}
getAncientTownList(params).then(res => {
this.townList = res.data.records
})
return
}
const param = { const param = {
page: this.page, page: this.page,
type: this.typeList[this.typeIndex].id, type: this.typeList[this.typeIndex].id,
cityName: this.cityName, cityName: this.cityName
random: random,
randomSeed: this.page > 1 ? randomSeed : null
} }
const name = this.name.trim() const name = this.name.trim()
if (name.length > 0) { if (name.length > 0) {
param.name = name param.name = name
} }
getHotelList(param).then(res => { getHotelList(param).then(res => {
const { success, data, msg } = res const { success, data } = res
if (success) { if (success) {
if(random === 1) {
this.randomSeed = msg
}
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
const cover = data[i].cover const cover = data[i].cover
data[i].hide = true data[i].hide = true
@@ -559,25 +257,6 @@ export default {
} }
}).finally(() => { }).finally(() => {
this.isLoad = true this.isLoad = true
uni.hideLoading()
})
},
fetchHotelBanner() {
if (!this.goodCityId) {
return
}
const params = {
goodCityId: this.goodCityId
}
getHotelBanner(params).then(res => {
const { success, data } = res
if (success && data) {
if (Array.isArray(data.hotelBanner)) {
this.hotelBanner = data.hotelBanner
} else if (Array.isArray(data)) {
this.hotelBanner = data
}
}
}) })
}, },
typeBannerItemClick(item) { typeBannerItemClick(item) {
@@ -588,101 +267,6 @@ export default {
} }
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.map-icon{
width: 30rpx;
height: 30rpx;
margin-right: 5rpx;
}
.qh-btn{
padding-top: 4rpx;
padding-bottom: 4rpx;
// border: thin dashed #999;
white-space: nowrap;
}
.tip-wrap{
background: #AAAEB3;
position: relative;
align-items: self-start !important;
&::before{
position: absolute;
content: '';
border-left: 15rpx solid transparent;
border-right: 15rpx solid transparent;
border-top: 20rpx solid transparent;
border-bottom: 20rpx solid #AAAEB3;
top: -30rpx;
left: 10%;
}
}
.icon-box{
border: 1rpx solid #fff;
border-radius: 100%;
width: 16rpx;
height: 16rpx;
margin-left: 5rpx;
padding: 2rpx;
}
.enter-btn{
color: #fff;
width: fit-content;
display: flex;
align-items: center;
padding: 10rpx 16rpx;
position: absolute;
right: 0;
bottom: 0;
border-radius: 30rpx 0;
font-size: 24rpx;
}
.town-title{
border-radius: 100rpx;
/* border-color: #333; */
// mix-blend-mode: difference;
width: fit-content;
padding: 5rpx 20rpx;
border: 1rpx solid #fff;
color: #fff;
position: absolute;
margin: auto;
top: 20rpx;
left: 0;
right: 0;
}
.town-card{
width: 100%;
height: 400rpx;
background: #fff;
border-radius: 30rpx;
position: relative;
overflow: hidden;
margin-bottom: 30rpx;
image{
width: -webkit-fit-content;
width: inherit;
height: -webkit-fit-content;
height: inherit;
}
}
.first-box{
padding-right: 15rpx;
position: sticky;
left: 0;
background-color: #f5f5f5;
z-index: 9;
}
.first-box__inner{
padding: 10rpx;
background: #fff;
border-radius: 30rpx;
}
.scroll-box{
display: flex;
height: fit-content;
background: #fff;
overflow-x: scroll;
padding: 10rpx;
border-radius: 30rpx;
}
.search-btn{ .search-btn{
position: absolute; position: absolute;
top: 2rpx; top: 2rpx;
@@ -724,7 +308,7 @@ export default {
height: 200rpx; height: 200rpx;
box-sizing: border-box; box-sizing: border-box;
white-space: nowrap; white-space: nowrap;
padding: 0rpx 20rpx 0 20rpx; padding: 20rpx 20rpx 0 20rpx;
.item { .item {
width: 154rpx; width: 154rpx;
@@ -756,14 +340,10 @@ export default {
} }
.body { .body {
padding: 0 20rpx 20rpx; padding: 20rpx 20rpx;
background: #f5f5f5; background: #f5f5f5;
} }
.refresh-btn {
margin-left: auto;
}
.city-box { .city-box {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
+3 -9
View File
@@ -1,13 +1,13 @@
<template> <template>
<view> <view>
<view class="culture v12-d-grid-columns-2"> <view class="culture v12-d-grid-columns-2">
<view class="img-item " v-for="(item, index) in list" :key="index" @click="viewImg(item)"> <view class="img-item " v-for="(item, index) in list" :key="index">
<image class="img-item" :src="item" mode="widthFix|heightFix" lazy-load="false"></image> <image class="img-item" :src="item" mode="widthFix|heightFix" lazy-load="false"></image>
</view> </view>
</view> </view>
<image <image
v-if="list.length === 0" v-if="list.length === 0"
:src="webUrl + '/orderIcon/wu.png'" :src="webUrl + '/20231023131208675588.png'"
class="img-nodata" class="img-nodata"
mode="scaleToFill" mode="scaleToFill"
/> />
@@ -39,15 +39,9 @@ export default {
this.getData() this.getData()
}, },
methods: { methods: {
viewImg(item) {
uni.previewImage({
current: item, // 当前显示图片的http链接
urls: this.list || [] // 需要预览的图片http链接列表
})
},
getData() { getData() {
getCulture({landmarkDataId: this.landmarkDataId}).then(res => { getCulture({landmarkDataId: this.landmarkDataId}).then(res => {
this.list = res.data.cultureImages || [] this.list = res.data.cultureImages
}) })
} }
} }
-2
View File
@@ -21,7 +21,6 @@
<view class="flex jc-between ai-center"> <view class="flex jc-between ai-center">
<text class="price">{{ item.price }}</text> <text class="price">{{ item.price }}</text>
<image <image
@click.stop="$emit('add', item)"
:src="webUrl + '/home/icon-cart.png'" :src="webUrl + '/home/icon-cart.png'"
class="btn" class="btn"
/> />
@@ -71,7 +70,6 @@ export default {
} }
.list-box { .list-box {
margin-top: 24rpx; margin-top: 24rpx;
padding: 0 20rpx;
.item { .item {
position: relative; position: relative;
width: 344rpx; width: 344rpx;
+6 -49
View File
@@ -20,25 +20,13 @@
</view> </view>
</view> </view>
<view class="info-item-body"> <view class="info-item-body">
<video
v-if="item.type === 2"
@play="infoItemViewClick(item, index)"
play-btn-position="center"
:show-fullscreen-btn="false"
class="video-item v12-mt-0"
:src="item.video"
controls
:id="'video-item' + index"
:poster="item.video + '?vframe/jpg/offset/1'"></video>
<img-box <img-box
v-else
:imgList="item.images" :imgList="item.images"
:num="item.images.length" :num="item.images.length"
:img-radius="10" :img-radius="10"
style="width: 100%" style="width: 100%"
@click="infoItemViewClick(item)" @click="infoItemViewClick(item)"
/> />
</view> </view>
<view class="info-item-bottom"> <view class="info-item-bottom">
<view class="time"> <view class="time">
@@ -54,7 +42,7 @@
:src="webUrl + '/20230803152147141807.png'" :src="webUrl + '/20230803152147141807.png'"
class="icon" class="icon"
/> />
<text class="seeNum-txt v12-font-28">{{ $formatCount(item.pv) }}</text> <text class="seeNum-txt v12-font-28">{{ item.pv }}</text>
</view> </view>
<view class="flex"> <view class="flex">
<image <image
@@ -73,7 +61,7 @@
v-show="item.zan > 0" v-show="item.zan > 0"
:class="item.hasZan ? 'on' : ''" :class="item.hasZan ? 'on' : ''"
class="seeNum-txt v12-font-28 v12-ml-1" class="seeNum-txt v12-font-28 v12-ml-1"
>{{ $formatCount(item.zan) }}</text >{{ item.zan }}</text
> >
</view> </view>
</view> </view>
@@ -84,12 +72,11 @@
:src="webUrl + '/home/no-data-bg.png'" :src="webUrl + '/home/no-data-bg.png'"
mode="widthFix" mode="widthFix"
class="no-data-loadend" class="no-data-loadend"
style="width: 100%;"
/> />
</view> </view>
<image <image
v-if="infoArray.length === 0" v-if="infoArray.length === 0"
:src="webUrl + '/orderIcon/wu.png'" :src="webUrl + '/20231023131208675588.png'"
class="img-nodata" class="img-nodata"
mode="scaleToFill" mode="scaleToFill"
/> />
@@ -113,8 +100,7 @@ export default {
data() { data() {
return { return {
webUrl: this.$VUE_APP_RESOURCES_URL, webUrl: this.$VUE_APP_RESOURCES_URL,
infoArray: [], infoArray: []
videoPlayers:[]
} }
}, },
watch: { watch: {
@@ -135,7 +121,7 @@ export default {
limit: 9999 limit: 9999
} }
getNews(params).then(res => { getNews(params).then(res => {
this.infoArray = res.data.records || [] this.infoArray = res.data.records
}) })
}, },
likeInfoItemHandle(item, index, value, voValue) { likeInfoItemHandle(item, index, value, voValue) {
@@ -150,27 +136,7 @@ export default {
} }
}) })
}, },
infoItemViewClick(item, index) { infoItemViewClick(item) {
if(item.type === 2) {
// const coverCtx = uni.createVideoContext('coverVideo', this)
// coverCtx.pause()
const playerId = 'video-item' + index
if(this.videoPlayers.includes(playerId)) {
this.videoPlayers.forEach(player => {
if(player === playerId) return
const playerCtx = uni.createVideoContext(player, this)
playerCtx.pause()
})
} {
this.videoPlayers.push(playerId)
this.videoPlayers.forEach(player => {
if(player === playerId) return
const playerCtx = uni.createVideoContext(player, this)
playerCtx.pause()
})
}
this.$emit('video')
}
uni.$u.debounce(() => { uni.$u.debounce(() => {
hadView({ landmarkNewsId: item.id }).finally(() => { hadView({ landmarkNewsId: item.id }).finally(() => {
this.infoArray.map(info => { this.infoArray.map(info => {
@@ -185,15 +151,6 @@ export default {
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.video-item {
width: 100%;
height: 400rpx;
border-radius: 10rpx;
}
.info-wrapper{
padding: 20px 10px;
}
.info-item + .info-item { .info-item + .info-item {
margin: 22rpx 0 0 0; margin: 22rpx 0 0 0;
} }
+12 -15
View File
@@ -3,19 +3,19 @@
<view class="list-item" v-for="(item, index) in currentList" :key="index" @click="fileItemClick(item)"> <view class="list-item" v-for="(item, index) in currentList" :key="index" @click="fileItemClick(item)">
<view class="v12-justify-start v12-align-center"> <view class="v12-justify-start v12-align-center">
<view class="v12-font-bold v12-font-28">·</view> <view class="v12-font-bold v12-font-28">·</view>
<view class="item-title">{{ item.title }}</view> <view class="item-title one-t">{{ item.title }}</view>
</view> </view>
<view class="item-action v12-dark"><u-icon name="arrow-right" color="#fff" size="8"></u-icon></view> <view class="item-action v12-dark"><u-icon name="arrow-right" color="#fff" size="8"></u-icon></view>
</view> </view>
<view class="more-wrap"> <view class="more-wrap" v-if="isMore ? isMore : list.length > 3">
<view class="more-btn v12-primary v12-align-center" @click="showMore" v-if="list.length > 0"> <view class="more-btn v12-primary v12-align-center" @click="showMore">
{{ isMore ? '查看更多' : '查看更多' }} {{ isMore ? '收起' : '查看更多' }}
<view class="item-action v12-white"><u-icon name="arrow-right" color="#C52733 " size="12"></u-icon></view> <view class="item-action v12-white"><u-icon name="arrow-right" color="#C52733 " size="12"></u-icon></view>
</view> </view>
</view> </view>
<image <image
v-if="list.length === 0" v-if="list.length === 0"
:src="webUrl + '/orderIcon/wu.png'" :src="webUrl + '/20231023131208675588.png'"
class="img-nodata" class="img-nodata"
mode="scaleToFill" mode="scaleToFill"
/> />
@@ -56,7 +56,7 @@ export default {
limit: 99999 limit: 99999
} }
getPorjectPolicyFiles(params).then(res => { getPorjectPolicyFiles(params).then(res => {
this.list = res.data.records || [] this.list = res.data.records
if(this.isMore) { if(this.isMore) {
this.currentList = this.list this.currentList = this.list
} else { } else {
@@ -65,14 +65,12 @@ export default {
}) })
}, },
showMore() { showMore() {
// this.isMore = !this.isMore this.isMore = !this.isMore
// if(this.isMore) { if(this.isMore) {
// this.currentList = this.list this.currentList = this.list
// } else { } else {
// this.currentList = this.list.filter((item, index) => index < 3) this.currentList = this.list.filter((item, index) => index < 3)
// } }
uni.navigateTo({ url: `/pages/home/searchPage?id=${this.landmarkDataId}&type=2` })
}, },
fileItemClick(file) { fileItemClick(file) {
const url = file.attachment || '' const url = file.attachment || ''
@@ -132,7 +130,6 @@ export default {
font-size: 24rpx; font-size: 24rpx;
color: #333; color: #333;
margin-left: 10rpx; margin-left: 10rpx;
max-width: 520rpx;
} }
.log-img{ .log-img{
width: 68rpx; width: 68rpx;
+4 -19
View File
@@ -17,13 +17,7 @@
'no-actived-3': actived === 3 && item.value === 2, 'no-actived-3': actived === 3 && item.value === 2,
'no-actived-4': actived === 2 && item.value === 3, 'no-actived-4': actived === 2 && item.value === 3,
}" }"
> >{{ item.name }}</view>
<image class="tab-icon" :src="webUrl + '/orderIcon/' + item.icon" mode="aspectFit|aspectFill|widthFix"></image>
{{ item.name }}
<!-- <view>
<view>{{ item.name }}</view>
</view> -->
</view>
</view> </view>
</view> </view>
<view <view
@@ -59,12 +53,11 @@ export default {
}, },
data() { data() {
return { return {
webUrl: this.$VUE_APP_RESOURCES_URL,
actived: 1, actived: 1,
tabs: [ tabs: [
{name: '企业推荐', value: 1, icon: 'qytj.png'}, {name: '企业推荐', value: 1},
{name: '政策', value: 2, icon: 'zc.png'}, {name: '政策', value: 2},
{name: '服务', value: 3, icon: 'fw.png'}, {name: '服务', value: 3},
] ]
} }
}, },
@@ -77,11 +70,6 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.tab-icon{
height: 30rpx;
width: 30rpx;
margin-right: 10rpx;
}
.fit-box-inner{ .fit-box-inner{
background: #f0f0f0; background: #f0f0f0;
width: initial; width: initial;
@@ -118,9 +106,6 @@ export default {
background: #f0f0f0; background: #f0f0f0;
width: inherit; width: inherit;
height: inherit; height: inherit;
display: flex;
justify-content: center;
align-items: center
} }
} }
.no-actived-1{ .no-actived-1{
+2 -3
View File
@@ -20,7 +20,7 @@
</view> </view>
<image <image
v-if="list.length === 0" v-if="list.length === 0"
:src="webUrl + '/orderIcon/wu.png'" :src="webUrl + '/20231023131208675588.png'"
class="img-nodata" class="img-nodata"
mode="scaleToFill" mode="scaleToFill"
/> />
@@ -57,7 +57,7 @@ export default {
methods: { methods: {
getData() { getData() {
getPorjectRecommend({landmarkDataId: this.landmarkDataId}).then(res => { getPorjectRecommend({landmarkDataId: this.landmarkDataId}).then(res => {
this.list = res.data || [] this.list = res.data
if(this.isMore) { if(this.isMore) {
this.currentList = this.list this.currentList = this.list
} else { } else {
@@ -132,7 +132,6 @@ export default {
font-size: 26rpx; font-size: 26rpx;
color: #333; color: #333;
margin-left: 20rpx; margin-left: 20rpx;
max-width: 180rpx;
} }
.log-img{ .log-img{
width: 68rpx; width: 68rpx;
+10 -34
View File
@@ -4,28 +4,27 @@
<map <map
:longitude="info.longitude" :longitude="info.longitude"
:latitude="info.latitude" :latitude="info.latitude"
:markers="[{latitude: info.latitude,longitude: info.longitude,width: 20, height: 25, iconPath: webUrl + '/page/qianxian/icon-location.png'}]" style="width: 100%;height: 400rpx; border-radius: 20rpx;"
style="width: 100%;height: 100%; border-radius: 20rpx;"
/> />
</view> </view>
<view class="v12-mt-3 info-wrap"> <view class="v12-mt-3 info-wrap">
<view> <view>
<view class="v12-font-32 v12-font-bold v12-mb-2">{{ info.name || '' }}</view> <view class="v12-font-32 v12-font-bold v12-mb-2">{{ info.name }}</view>
<view class="v12-font-24 v12-mb-1 v12-dark1-text">办公时间:{{ info.officeTime || '' }}</view> <view class="v12-font-24 v12-mb-1 v12-dark1-text">办公时间:{{ info.officeTime }}</view>
<view class="v12-font-24 v12-mb-1 v12-dark1-text">{{ info.address || '' }}</view> <view class="v12-font-24 v12-mb-1 v12-dark1-text">{{ info.address }}</view>
</view> </view>
<view class="action-wrap"> <view class="action-wrap">
<view @click="showLocation"> <view>
<view> <view>
<image :src="webUrl + '/page/qianxian/icon-addr.png'" class="img" /> <image :src="webUrl + '/page/qianxian/icon-addr.png'" class="img" />
</view> </view>
<view class="text-center">导航</view> <view class="text-center">导航</view>
</view> </view>
<view @click="call"> <view>
<view> <view>
<image :src="webUrl + '/page/qianxian/icon-phone.png'" class="img" /> <image :src="webUrl + '/page/qianxian/icon-phone.png'" class="img" />
</view> </view>
<view class="text-center">咨询</view> <view class="text-center">客服</view>
</view> </view>
</view> </view>
</view> </view>
@@ -35,7 +34,7 @@
简介 简介
</view> </view>
<view class="intro-text"> <view class="intro-text">
{{ info.intro || '' }} {{ info.intro }}
</view> </view>
</view> </view>
</view> </view>
@@ -56,29 +55,6 @@ export default {
mounted() { mounted() {
console.log(this.info); console.log(this.info);
}, },
methods: {
showLocation() {
console.log(this.info);
if (!this.info.latitude || !this.info.longitude) {
this.$dialog.error('暂无位置信息')
} else {
uni.openLocation({
latitude: this.info.latitude,
longitude: this.info.longitude
})
}
},
call() {
if (this.info.tel) {
uni.makePhoneCall({
phoneNumber: this.info.tel
})
} else {
this.$dialog.error('电话为空')
}
},
}
} }
</script> </script>
@@ -102,8 +78,8 @@ export default {
} }
.info-wrap{ .info-wrap{
display: flex; display: flex;
justify-content: space-between; justify-content: space-around;
padding: 40rpx 20rpx 0; padding: 40rpx 0 0;
} }
.service{ .service{
position: relative; position: relative;

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