refactor: 重构多个组件以支持 Vue 3 语法和功能

- 将多个组件转换为 `<script setup>` 语法,提升可读性和性能
- 优化状态管理和事件处理逻辑,简化代码结构
- 更新样式和布局以适应新组件结构
- 添加新功能和修复已知问题,提升用户体验
This commit is contained in:
Yer11214
2026-07-08 18:37:11 +08:00
parent 4d0b0fb5e4
commit 349ffa4f34
189 changed files with 18278 additions and 20758 deletions

243
App.vue
View File

@@ -1,228 +1,171 @@
<script> <script setup lang="ts">
/** import config from '@/config/config'
* vuex管理登录状态具体可以参考官方登录模板示例 import { getClipboardData } from '@/js_sdk/h5-copy/h5-copy.js'
*/ import APPUpdate from '@/plugins/APPUpdate'
import config from "@/config/config"; import storage from '@/utils/storage'
import { import { getThemeSetting } from '@/api/common.js'
getClipboardData
} from "@/js_sdk/h5-copy/h5-copy.js";
import APPUpdate from "@/plugins/APPUpdate";
import storage from "@/utils/storage";
import { getThemeSetting } from "@/api/common.js";
import { import {
applyTabBarStyle, applyTabBarStyle,
cacheTheme, cacheTheme,
loadCachedTheme, loadCachedTheme,
normalizeTheme, normalizeTheme,
} from "@/utils/theme"; } from '@/utils/theme'
import { import { onLaunch, onShow } from '@dcloudio/uni-app'
mapMutations import { useStore } from '@/store'
} from "vuex";
const store = useStore()
/**
* 路由监听并删除路由
* https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.navigateTo.html
* */
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
wx.onAppRoute((res) => { wx.onAppRoute(() => {})
})
// #endif // #endif
export default { onLaunch((val) => {
data() { initTheme()
return { if (val?.query?.inviter) {
config,
};
},
/**
* 监听返回(页面级 onBackPress 在 App.vue 不生效,保留空实现避免误导)
*/
onLaunch: function(val) {
this.initTheme();
if(val.query.inviter){
storage.setInviter(val.query.inviter) storage.setInviter(val.query.inviter)
} }
// #ifdef APP-PLUS // #ifdef APP-PLUS
// 重点是以下: 一定要监听后台恢复 !一定要 plus.globalEvent.addEventListener('newintent', () => {
plus.globalEvent.addEventListener("newintent", (e) => { checkArguments()
this.checkArguments(); // 检测启动参数 })
});
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
this.applyUpdateWeChat(); applyUpdateWeChat()
// #endif // #endif
}, })
onShow() { onShow(() => {
// #ifndef H5 // #ifndef H5
if(this.config.enableGetClipboard){ if (config.enableGetClipboard) {
this.getClipboard(); getClipboard()
} }
// #endif // #endif
// #ifdef APP-PLUS
// #ifdef APP-PLUS
if (storage.getShow()) { if (storage.getShow()) {
if (uni.getSystemInfoSync().platform == 'ios') { if (uni.getSystemInfoSync().platform == 'ios') {
this.$u.route("/pages/tabbar/screen/fullScreen"); uni.navigateTo({ url: '/pages/tabbar/screen/fullScreen' })
} }
} }
// #endif // #endif
}, })
methods: {
...mapMutations(["login", "SET_THEME"]), function initTheme() {
initTheme() { const cached = loadCachedTheme()
const cached = loadCachedTheme();
if (cached) { if (cached) {
this.SET_THEME(cached); store.commit('SET_THEME', cached)
applyTabBarStyle(cached.mainColor); applyTabBarStyle(cached.mainColor)
} }
getThemeSetting() getThemeSetting()
.then((res) => { .then((res) => {
if (res.data && res.data.success && res.data.result && res.data.result.settingValue) { if (res.data?.success && res.data.result?.settingValue) {
try { try {
const raw = JSON.parse(res.data.result.settingValue); const raw = JSON.parse(res.data.result.settingValue)
const theme = normalizeTheme(raw); const theme = normalizeTheme(raw)
this.SET_THEME(theme); store.commit('SET_THEME', theme)
cacheTheme(theme); cacheTheme(theme)
applyTabBarStyle(theme.mainColor); applyTabBarStyle(theme.mainColor)
} catch (e) { } catch (e) {
// 主题配置解析失败时使用缓存 // 主题配置解析失败时使用缓存
} }
} }
}) })
.catch(() => {}); .catch(() => {})
}, }
/**
* 微信小程序版本提交更新版本 解决缓存问题
*/
applyUpdateWeChat() {
const updateManager = uni.getUpdateManager();
updateManager.onCheckForUpdate(function(res) { function applyUpdateWeChat() {
// 请求完新版本信息的回调 const updateManager = uni.getUpdateManager()
});
updateManager.onUpdateReady(function(res) { updateManager.onCheckForUpdate(() => {})
updateManager.onUpdateReady(() => {
uni.showModal({ uni.showModal({
title: "更新提示", title: '更新提示',
content: "发现新版本,是否重启应用?", content: '发现新版本,是否重启应用?',
success(res) { success(res) {
if (res.confirm) { if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 updateManager.applyUpdate()
updateManager.applyUpdate();
} }
}, },
}); })
}); })
updateManager.onUpdateFailed(function(res) {
// 新的版本下载失败
});
},
// TODO 开屏广告 后续优化添加 updateManager.onUpdateFailed(() => {})
launch() { }
function launch() {
try { try {
// 获取本地存储中launchFlag标识 开屏广告 const value = uni.getStorageSync('launchFlag')
const value = uni.getStorageSync("launchFlag");
if (!value) { if (!value) {
// this.$u.route("/pages/index/agreement"); // uni.navigateTo({ url: '/pages/index/agreement' })
} else { } else {
//app启动时打开启动广告页 const w = plus.webview.open(
var w = plus.webview.open( '/hybrid/html/advertise/advertise.html',
"/hybrid/html/advertise/advertise.html", '本地地址',
"本地地址", { {
top: 0, top: 0,
bottom: 0, bottom: 0,
zindex: 999, zindex: 999,
}, },
"fade-in", 'fade-in',
500 500,
); )
//设置定时器4s后关闭启动广告页 setTimeout(() => {
setTimeout(function() { plus.webview.close(w)
plus.webview.close(w); APPUpdate()
APPUpdate(); }, 3000)
}, 3000);
} }
} catch (e) { } catch (e) {
// error
uni.setStorage({ uni.setStorage({
key: "launchFlag", key: 'launchFlag',
data: true, data: true,
success: function() { success() {
console.log("error时存储launchFlag"); console.log('error时存储launchFlag')
}, },
}); })
}
} }
},
/** async function getClipboard() {
* 获取粘贴板数据 const res = await getClipboardData()
*/ if (res.indexOf(config.shareLink) != -1 && res != store.state.shareLink) {
async getClipboard() { store.state.shareLink = res
let res = await getClipboardData();
/**
* 解析粘贴板数据
*/
if (res.indexOf(config.shareLink) != -1 && (res != this.$store.state.shareLink)) {
this.$store.state.shareLink = res
uni.showModal({ uni.showModal({
title: "提示", title: '提示',
content: "检测到一个分享链接是否跳转?", content: '检测到一个分享链接是否跳转?',
confirmText: "跳转", confirmText: '跳转',
success: function(callback) { success(callback) {
if (callback.confirm) { if (callback.confirm) {
const path = res.split(config.shareLink)[1]; const path = res.split(config.shareLink)[1]
if (path.indexOf("tabbar") != -1) { if (path.indexOf('tabbar') != -1) {
uni.switchTab({ uni.switchTab({ url: path })
url: path,
});
} else { } else {
uni.navigateTo({ uni.navigateTo({ url: path })
url: path,
});
} }
} }
}, },
}); })
}
} }
},
/** function checkArguments() {
* h5中打开app获取跳转app的链接并跳转
*/
checkArguments() {
// #ifdef APP-PLUS // #ifdef APP-PLUS
setTimeout(() => { setTimeout(() => {
const args = plus.runtime.arguments; const args = plus.runtime.arguments
if (args) { if (args) {
const argsStr = decodeURIComponent(args); const argsStr = decodeURIComponent(args)
const path = argsStr.split("//")[1]; const path = argsStr.split('//')[1]
if (path.indexOf("tabbar") != -1) { if (path.indexOf('tabbar') != -1) {
uni.switchTab({ uni.switchTab({ url: `/${path}` })
url: `/${path}`,
});
} else { } else {
uni.navigateTo({ uni.navigateTo({ url: `/${path}` })
url: `/${path}`,
});
} }
} }
}); })
// #endif // #endif
}, }
},
};
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@@ -10,40 +10,30 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { import { ref, onMounted } from 'vue'
props: {
// 购物车 cart 消息 msg 订单 order 查询 search
type: {
type: String,
default: 'search'
},
isBtn:{
type: Boolean,
default: false
},
title:{
type: String,
default: '没有相关内容'
}
},
data() { const props = withDefaults(defineProps<{
return { type?: string
src:'' isBtn?: boolean
}; title?: string
}, }>(), {
mounted() { type: 'search',
this.src ='/static/default/default_'+ this.type + '.png'; isBtn: false,
}, title: '没有相关内容'
methods: { })
toHome() {
const src = ref('')
onMounted(() => {
src.value = `/static/default/default_${props.type}.png`
})
const toHome = () => {
uni.switchTab({ uni.switchTab({
url: '/pages/home/home' url: '/pages/home/home'
}); })
} }
}
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -13,49 +13,41 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import config from "@/config/config"; import { ref, onMounted } from 'vue'
import logoImg from "@/icon.png"; import config from "@/config/config"
export default { import logoImg from "@/icon.png"
data() {
return { const weChat = ref(false)
config, // 设置工具类 const logo = logoImg
weChat: false, // 是否微信浏览器该项为true时不显示 当前整个页面
logo: logoImg, //显示的圆形logo onMounted(() => {
};
},
mounted() {
// #ifdef H5 // #ifdef H5
// 判断是否是微信浏览器 // 判断是否是微信浏览器
var ua = navigator.userAgent.toLowerCase(); var ua = navigator.userAgent.toLowerCase();
var isWeixin = ua.indexOf("micromessenger") != -1; var isWeixin = ua.indexOf("micromessenger") != -1;
if (isWeixin) { weChat.value = isWeixin ? true : false
this.weChat = true;
} else {
this.weChat = false;
}
// #endif // #endif
}, })
methods: {
/** /**
* 跳转到下载app页面 * 跳转到下载app页面
*/ */
downloadApp() { const downloadApp = () => {
setTimeout(function () { setTimeout(function () {
window.location.href = config.downloadLink; window.location.href = config.downloadLink;
}, 2000); }, 2000);
}, }
/** /**
* 打开app 仅在h5生效 使用ifream唤醒app * 打开app 仅在h5生效 使用ifream唤醒app
*/ */
openApp() { const openApp = () => {
let src; let src: string = ''
if (location.href) { if (location.href) {
src = location.href.split("/pages")[1]; src = location.href.split("/pages")[1];
} }
let t = `${config.schemeLink}pages${src}`; let t = `${config.schemeLink}pages${src}`
try { try {
var e = navigator.userAgent.toLowerCase(), var e = navigator.userAgent.toLowerCase(),
@@ -63,22 +55,20 @@ export default {
if ( if (
((n = null !== n ? n[1].replace(/_/g, ".") : 0), parseInt(n) >= 9) ((n = null !== n ? n[1].replace(/_/g, ".") : 0), parseInt(n) >= 9)
) { ) {
window.location.href = t; window.location.href = t
this.downloadApp(); downloadApp()
} else { } else {
var r = document.createElement("iframe"); var r = document.createElement("iframe");
(r.src = t), (r.style.display = "none"), document.body.appendChild(r); (r.src = t), (r.style.display = "none"), document.body.appendChild(r)
this.downloadApp(); downloadApp()
} }
} catch (e) { } catch (e) {
window.location.href = t; window.location.href = t
this.downloadApp(); downloadApp()
}
} }
},
},
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -94,7 +94,7 @@
</view> </view>
</view> </view>
<div class="soldout" v-if="goodsDetail.quantity === 0"> <div class="soldout" v-if="goodsDetail.quantity === 0">
<u-alert-tips type="warning" title="商品已售罄" description="当前商品库存为0"></u-alert-tips> <u-alert type="warning" title="商品已售罄" :description="'当前商品库存为0'"></u-alert>
</div> </div>
<!-- 数量 --> <!-- 数量 -->
<view v-if="goodsDetail.quantity !== 0" class="goods-skus-number flex flex-a-c flex-j-sb"> <view v-if="goodsDetail.quantity !== 0" class="goods-skus-number flex flex-a-c flex-j-sb">
@@ -111,207 +111,163 @@
</u-popup> </u-popup>
</div> </div>
</template> </template>
<script>
import * as API_trade from '@/api/trade.js';
import setup from './popup';
import uniNumberBox from '@/components/uni-number-box'
export default {
components: {
uniNumberBox
},
data() {
return {
setup,
num: this.wholesaleList && this.wholesaleList.length > 0 ? this.wholesaleList[0].num : 1,
selectName: '', //选中商品的昵称 <script setup lang="ts">
selectSkuList: '', //选中商铺sku, import { ref, reactive, watch, onMounted } from 'vue'
selectedSpecImg: '', //选中的图片路径 import * as API_trade from '@/api/trade.js'
buyType: '', //用于存储促销,拼团等活动类型 import setup from './popup.js'
parentOrder: '', //父级拼团活动的数据 - 如果是团员则有数据 import uniNumberBox from '@/components/uni-number-box.vue'
formatList: [], import { goodsFormatPrice } from '@/utils/filters.js'
currentSelected: [],
skuList: '',
isClose: false //是否可以点击遮罩关闭
};
},
props: {
wholesaleList: {
type: null,
default: false
},
buyMask: {
type: Boolean,
default: false
},
isGroup: {
type: Boolean,
default: false
},
goodsDetail: {
default: '',
type: null
},
selectedSku: {
default: '',
type: null
},
goodsSpec: {
default: '',
type: null
},
addr: {
default: '',
type: null
},
pointDetail: {
default: '',
type: null
}
},
computed: {
wholesalePrice(key) {
return this.wholesaleList.length
? this.wholesaleList.map(item => {
return item.price;
})
: [];
},
wholesaleNum(key) {
return this.wholesaleList.length
? this.wholesaleList.map(item => {
return item.num;
})
: [];
}
},
watch: {
num(val) {
val == 0 ? this.num = 1 : '' const props = withDefaults(defineProps<{
wholesaleList?: any[] | boolean
buyMask?: boolean
isGroup?: boolean
goodsDetail?: any
selectedSku?: any | null
goodsSpec?: any | null
addr?: any | null
pointDetail?: any | null
}>(), {
wholesaleList: false,
buyMask: false,
isGroup: false,
goodsDetail: () => ({}),
selectedSku: '',
goodsSpec: '',
addr: '',
pointDetail: ''
})
const emit = defineEmits(['closeBuy', 'changed', 'handleClickSku', 'queryCart'])
const num = ref(props.wholesaleList && Array.isArray(props.wholesaleList) && props.wholesaleList.length > 0 ? props.wholesaleList[0].num : 1)
const selectName = ref('')
const selectSkuList = ref<any>('')
const selectedSpecImg = ref('')
const buyType = ref('')
const parentOrder = ref<any>('')
const formatList = ref<any[]>([])
const currentSelected = ref<string[]>([])
const skuList = ref('')
watch(num, (val) => {
val == 0 ? num.value = 1 : ''
if (val) { if (val) {
//超过库存后修改回库存 //超过库存后修改回库存
if (val > this.goodsDetail.quantity) { if (val > props.goodsDetail.quantity) {
this.$nextTick(function() { num.value = props.goodsDetail.quantity
this.num = this.goodsDetail.quantity;
});
} }
} }
}, })
buyType: {
handler(val) { watch(() => props.buyType, (val) => {
if (val) { if (val) {
this.buyType = val; buyType.value = val as string
} }
}, }, { immediate: true })
immediate: true
}, watch(selectSkuList, (_val) => {
selectSkuList: { emit('changed', selectSkuList.value)
handler(val, oldval) { }, { deep: true })
this.$emit('changed', val);
}, watch(() => props.goodsDetail?.quantity, (val) => {
deep: true
},
'goodsDetail.quantity': {
handler(val) {
if (val == 0) { if (val == 0) {
uni.showToast({ uni.showToast({
title: '商品已售罄', title: '商品已售罄',
duration: 2000, duration: 2000,
icon: 'none' icon: 'none'
}) })
this.num = 1; num.value = 1
} }
} })
}
},
methods: { const numCheck = (val: number) => {
numCheck(val) { if (Array.isArray(props.wholesaleList) && props.wholesaleList.length > 0) {
if (this.wholesaleList && this.wholesaleList.length > 0) { if (num.value <= props.wholesaleList[0].num) {
if (this.num <= this.wholesaleList[0].num) {
uni.showToast({ uni.showToast({
title: '批发商品购买数量不能小于起批数量!', title: '批发商品购买数量不能小于起批数量!',
duration: 2000, duration: 2000,
icon: 'none' icon: 'none'
}); })
this.num = this.wholesaleList[0].num; num.value = props.wholesaleList[0].num
} }
} }
}, }
closeMask() {
this.$emit('closeBuy', false); const closeMask = () => {
}, emit('closeBuy', false)
}
/**点击规格 */ /**点击规格 */
handleClickSpec(val, index, specValue) { const handleClickSpec = (val: any, index: number, specValue: any) => {
this.currentSelected[index] = specValue.value; currentSelected.value[index] = specValue.value
let selectedSkuId = this.goodsSpec.find(i => { let selectedSkuId = props.goodsSpec.find((i: any) => {
let matched = true; let matched = true
let specValues = i.specValues.filter(j => j.specName !== 'images'); let specValues = i.specValues.filter((j: any) => j.specName !== 'images')
for (let n = 0; n < specValues.length; n++) { for (let n = 0; n < specValues.length; n++) {
if (specValues[n].specValue !== this.currentSelected[n]) { if (specValues[n].specValue !== currentSelected.value[n]) {
matched = false; matched = false
return; return
} }
} }
if (matched) { if (matched) {
return i; return i
} }
}); })
if (selectedSkuId?.skuId) { if (selectedSkuId?.skuId) {
this.currentSelected[index] = specValue.value; currentSelected.value[index] = specValue.value
this.selectSkuList = { selectSkuList.value = {
spec: { spec: {
specName: val.name, specName: val.name,
specValue: specValue.value specValue: specValue.value
}, },
data: this.goodsDetail data: props.goodsDetail
}; }
this.selectName = specValue.value; selectName.value = specValue.value
this.$emit('handleClickSku', { emit('handleClickSku', {
skuId: selectedSkuId.skuId, skuId: selectedSkuId.skuId,
goodsId: this.goodsDetail.goodsId goodsId: props.goodsDetail.goodsId
}); })
} else { } else {
uni.showToast({ uni.showToast({
title: '暂无该商品!', title: '暂无该商品!',
duration: 2000, duration: 2000,
icon: 'none' icon: 'none'
}); })
}
} }
},
/** /**
* 直接购买 * 直接购买
*/ */
buy(data) { const buy = (data: any) => {
API_trade.addToCart(data).then(res => { API_trade.addToCart(data).then(res => {
if (res.data.success) { if (res.data.success) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/order/fillorder?way=${data.cartType}&addr=${''}&parentOrder=${encodeURIComponent(JSON.stringify(this.parentOrder))}` url: `/pages/order/fillorder?way=${data.cartType}&addr=${''}&parentOrder=${encodeURIComponent(JSON.stringify(parentOrder.value))}`
}); })
}
})
} }
});
},
/** /**
* 添加到购物车或购买 * 添加到购物车或购买
*/ */
addToCartOrBuy(val) { const addToCartOrBuy = (val: string) => {
if (!this.selectSkuList) { if (!selectSkuList.value) {
uni.showToast({ uni.showToast({
title: '请选择规格商品', title: '请选择规格商品',
icon: 'none' icon: 'none'
}); })
return; return
} }
let data = { let data = {
skuId: this.goodsDetail.id, skuId: props.goodsDetail.id,
num: this.num num: num.value
}; }
if (val == 'cart') { if (val == 'cart') {
API_trade.addToCart(data).then(res => { API_trade.addToCart(data).then(res => {
@@ -319,105 +275,105 @@ export default {
uni.showToast({ uni.showToast({
title: '商品已添加到购物车', title: '商品已添加到购物车',
icon: 'none' icon: 'none'
}); })
this.$emit('queryCart'); emit('queryCart')
this.closeMask(); closeMask()
} }
}); })
} else { } else {
// 判断是否拼团商品 // 判断是否拼团商品
if (this.buyType) { if (buyType.value) {
data.cartType = 'PINTUAN'; data.cartType = 'PINTUAN'
} else if (this.goodsDetail.goodsType == 'VIRTUAL_GOODS') { } else if (props.goodsDetail.goodsType == 'VIRTUAL_GOODS') {
data.cartType = 'VIRTUAL'; data.cartType = 'VIRTUAL'
} else { } else {
data.cartType = 'BUY_NOW'; data.cartType = 'BUY_NOW'
} }
API_trade.addToCart(data).then(res => { API_trade.addToCart(data).then(res => {
if (res.data.code == 200) { if (res.data.code == 200) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/order/fillorder?way=${data.cartType}&addr=${this.addr.id || ''}&parentOrder=${encodeURIComponent(JSON.stringify(this.parentOrder))}` url: `/pages/order/fillorder?way=${data.cartType}&addr=${props.addr?.id || ''}&parentOrder=${encodeURIComponent(JSON.stringify(parentOrder.value))}`
}); })
} }
}); })
} }
}, }
formatSku(list) {
const formatSku = (list: any[]) => {
// 格式化数据 // 格式化数据
let arr = [{}]; let arr: any[] = [{}]
if (!Array.isArray(list)) { if (!Array.isArray(list)) {
return false; return false
} }
list.forEach((item, index) => { list.forEach((_item, _index) => {
item.specValues.forEach((spec, specIndex) => { let item = list[_index]
let name = spec.specName; item.specValues.forEach((spec: any, specIndex: number) => {
let name = spec.specName
let values = { let values = {
value: spec.specValue, value: spec.specValue,
quantity: item.quantity, quantity: item.quantity,
skuId: item.skuId skuId: item.skuId
}; }
if (name === 'images') { if (name === 'images') {
return; return
} }
arr.forEach((arrItem, arrIndex) => { arr.forEach((arrItem, arrIndex) => {
if ( if (
arrItem.name == name && arrItem.name == name &&
arrItem.values && arrItem.values &&
!arrItem.values.find(i => { !arrItem.values.find((i: any) => {
return i.value === values.value; return i.value === values.value
}) })
) { ) {
arrItem.values.push(values); arrItem.values.push(values)
} }
let keys = arr.map(key => { let keys = arr.map(key => {
return key.name; return key.name
}); })
if (!keys.includes(name)) { if (!keys.includes(name)) {
arr.push({ arr.push({
name: name, name: name,
values: [values] values: [values]
}); })
} }
}); })
}); })
}); })
arr.shift(); arr.shift()
this.formatList = arr; formatList.value = arr
list.forEach(item => { list.forEach(item => {
// 默认选中 // 默认选中
if (item.skuId === this.goodsDetail.id) { if (item.skuId === props.goodsDetail.id) {
item.specValues item.specValues
.filter(i => i.specName !== 'images') .filter(i => i.specName !== 'images')
.forEach((value, _index) => { .forEach((value, _index) => {
this.currentSelected[_index] = value.specValue; currentSelected.value[_index] = value.specValue
this.selectName = value.specValue; selectName.value = value.specValue
this.selectSkuList = { selectSkuList.value = {
spec: value, spec: value,
data: this.goodsDetail data: props.goodsDetail
};
});
} }
}); })
}
})
this.skuList = list; skuList.value = list
// console.log(" this.skuList", this.skuList)
} }
},
mounted() { onMounted(() => {
this.formatSku(this.goodsSpec); formatSku(props.goodsSpec)
} })
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import './popup.scss'; @import './popup.scss';

View File

@@ -17,168 +17,156 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { ref, onMounted, getCurrentInstance } from 'vue'
// 引入绘制插件 // 引入绘制插件
import DrawPoster from "@/js_sdk/u-draw-poster"; import DrawPoster from "@/js_sdk/u-draw-poster"
import logoImg from "@/pages/passport/static/logo-title.png"; import logoImg from "@/pages/passport/static/logo-title.png"
export default { const instance = getCurrentInstance()
data: () => ({
imgUrl: "", //绘制出来的图片路径
show: false, //是否展示模态框
dp: {}, //绘制的dp对象用于存储绘制等一些方法。
logo: logoImg, //本地logo地址
}),
props: { const props = defineProps<{
/** res?: any
* 父级传参的数据 }>()
*/
res: { const imgUrl = ref("")
type: null, const show = ref(false)
default: "", const dp = ref<any>({})
}, const logo = logoImg
},
onUnload() {},
methods: {
/** /**
* 解决微信小程序中图片模糊问题 * 解决微信小程序中图片模糊问题
*/ */
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
st2: (size) => size * 2, const st2 = (size: number) => size * 2
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
st2: (size) => size, const st2 = (size: number) => size
// #endif // #endif
/** /**
* 保存图片 * 保存图片
*/ */
downLoad() { const downLoad = () => {
uni.saveImageToPhotosAlbum({ uni.saveImageToPhotosAlbum({
filePath: this.imgUrl, filePath: imgUrl.value,
success: function () { success: function () {
uni.showToast({ uni.showToast({
title: "保存成功!", title: "保存成功!",
icon: "none", icon: "none",
}); })
}, },
fail: function () { fail: function () {
uni.showToast({ uni.showToast({
title: "保存失败,请稍后重试!", title: "保存失败,请稍后重试!",
icon: "none", icon: "none",
}); })
},
});
}, },
})
}
/** /**
* 创建canvas * 创建canvas
*/ */
async init() { const init = async () => {
this.show = true; show.value = true
this.dp = await DrawPoster.build({ dp.value = await DrawPoster.build({
selector: "canvas", selector: "canvas",
componentThis: this, componentThis: instance?.proxy,
loading: true, loading: true,
debugging: true, debugging: true,
}); })
let dp = this.dp; let dpVal = dp.value
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
// 用于微信小程序中画布错乱问题 // 用于微信小程序中画布错乱问题
dp.canvas.width = this.st2(600); dpVal.canvas.width = st2(600)
dp.canvas.height = this.st2(960); dpVal.canvas.height = st2(960)
// #endif // #endif
this.draw(dp); await draw(dpVal)
}, }
async draw(dp) { const draw = async (dp: any) => {
const { width, height, background, title } = this.res.container; const { width, height, background, title } = props.res.container
const { code, img, price } = this.res.bottom; const { code, img, price } = props.res.bottom
// /** 绘制背景 */ // /** 绘制背景 */
await dp.draw((ctx) => { await dp.draw((ctx: any) => {
ctx.fillStyle = background; ctx.fillStyle = background
ctx.fillRoundRect( ctx.fillRoundRect(
this.st2(0), st2(0),
this.st2(0), st2(0),
this.st2(width), st2(width),
this.st2(height), st2(height),
this.st2(12) st2(12)
); )
ctx.clip(); ctx.clip()
}); })
/** 绘制图片 */ /** 绘制图片 */
dp.draw(async (ctx) => { dp.draw(async (ctx: any) => {
await Promise.all([ await Promise.all([
// 绘制Logo // 绘制Logo
ctx.drawImage( ctx.drawImage(
this.logo, logo,
this.st2(175), st2(175),
this.st2(0), st2(0),
this.st2(256), st2(256),
this.st2(144) st2(144)
), ),
// 中间图片 // 中间图片
ctx.drawImage( ctx.drawImage(
img, img,
this.st2(100), st2(100),
this.st2(150), st2(150),
this.st2(400), st2(400),
this.st2(400) st2(400)
), ),
// 二维码 // 二维码
ctx.drawImage( ctx.drawImage(
code, code,
this.st2(39), st2(39),
this.st2(750), st2(750),
this.st2(150), st2(150),
this.st2(150) st2(150)
), ),
]); ])
}); })
/** 绘制中间文字*/ /** 绘制中间文字*/
await dp.draw((ctx) => { await dp.draw((ctx: any) => {
ctx.fillStyle = "#333"; ctx.fillStyle = "#333"
ctx.font = `bold ${this.st2(24)}px PingFang SC`; ctx.font = `bold ${st2(24)}px PingFang SC`
ctx.textAlign = "center"; ctx.textAlign = "center"
ctx.fillWarpText({ ctx.fillWarpText({
text: title, text: title,
maxWidth: this.st2(500), maxWidth: st2(500),
x: this.st2(300), x: st2(300),
y: this.st2(600), y: st2(600),
layer: 1, layer: 1,
}); })
ctx.fillStyle = "#ff3c2a"; ctx.fillStyle = "#ff3c2a"
ctx.font = `${this.st2(38)}px PingFang SC`; ctx.font = `${st2(38)}px PingFang SC`
ctx.textAlign = "center"; ctx.textAlign = "center"
ctx.fillText(price, this.st2(300), this.st2(680)); ctx.fillText(price, st2(300), st2(680))
}); })
// /** 绘制底部文字 */ // /** 绘制底部文字 */
await dp.draw((ctx) => { await dp.draw((ctx: any) => {
ctx.fillStyle = "#666"; ctx.fillStyle = "#666"
ctx.font = `${this.st2(24)}px PingFang SC`; ctx.font = `${st2(24)}px PingFang SC`
ctx.fillText("长按图片,识别二维码", this.st2(200), this.st2(866)); ctx.fillText("长按图片,识别二维码", st2(200), st2(866))
ctx.fillStyle = "#666"; ctx.fillStyle = "#666"
ctx.font = `${this.st2(24)}px PingFang SC`; ctx.font = `${st2(24)}px PingFang SC`
ctx.fillText("查看商品详情", this.st2(200), this.st2(900)); ctx.fillText("查看商品详情", st2(200), st2(900))
}); })
this.imgUrl = await dp.createImagePath(); imgUrl.value = await dp.createImagePath()
}
// console.log(posterImgUrl) onMounted(() => {
}, init()
}, })
async mounted() {
this.init();
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -79,192 +79,182 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { ref, getCurrentInstance } from 'vue'
import { getRegionsById } from "@/api/common.js"
const instance = getCurrentInstance()
let windowWidth = 0 let windowWidth = 0
import { getRegionsById } from "@/api/common.js";
export default { const props = withDefaults(defineProps<{
name: "UniCityNvue", headTitle?: string
props: { pickerSize?: string | string[]
headTitle: { provinceData?: any[]
//标题 }>(), {
type: String, headTitle: "区域选择",
default: "区域选择", pickerSize: "1",
}, provinceData: () => [],
pickerSize: { })
// 使用多少个tab
type: [String, String], const emit = defineEmits(['funcValue'])
default: "1",
}, const clearRightIcon = ref(true)
provinceData: { const scrollLeft = ref(500)
// 默认的省市区id如果不使用id的情况下则为[] const scrollTop = ref(0)
type: Array, const enableScroll = ref(true)
default: function () { const tabCurrentIndex = ref(0)
return []; const tabbars = ref<any[]>(props.provinceData)
}, const pickersize = ref(props.pickerSize)
}, const showPicker = ref(false)
},
data() {
return {
clearRightIcon: true, //是否显示右侧关闭icon
scrollLeft: 500, //顶部选项卡左滑距离
scrollTop: 0, //默认滚动顶部为0
enableScroll: true, //是否启用滚动
tabCurrentIndex: 0, //当前选项卡索引
tabbars: this.provinceData, //默认的省市区id
pickersize: this.pickerSize, //多少个tab 推荐为4级
showPicker: false, //显示选取器
};
},
methods: {
/** /**
* 显示选择器 * 显示选择器
*/ */
show() { const show = () => {
this.showPicker = true; showPicker.value = true
if (this.tabbars[0].children.length == 0) { if (tabbars.value[0].children.length == 0) {
getRegionsById(0).then((res) => { getRegionsById(0).then((res: any) => {
this.tabbars[0].children = res.data.result; tabbars.value[0].children = res.data.result
}); })
} }
windowWidth = uni.getSystemInfoSync().windowWidth; windowWidth = uni.getSystemInfoSync().windowWidth
}, }
/** /**
* 关闭选择器 * 关闭选择器
*/ */
hide() { const hide = () => {
this.showPicker = false; showPicker.value = false
}, }
/** /**
* tab切换 * tab切换
*/ */
changeTab(e) { const changeTab = (e: number) => {
let index = e; let index = e
this.setScroll(index); setScroll(index)
//延迟300ms,等待swiper动画结束再修改tabbar //延迟300ms,等待swiper动画结束再修改tabbar
this.tabCurrentIndex = index; tabCurrentIndex.value = index
setTimeout(() => { setTimeout(() => {
this.getScroll("show" + index); getScroll("show" + index)
}, 10); }, 10)
}, }
/** /**
* 获得元素的大小 * 获得元素的大小
*/ */
getElSize(id) { const getElSize = (id: string): Promise<any> => {
return new Promise((res, rej) => { return new Promise((res) => {
let el = uni let el = uni
.createSelectorQuery() .createSelectorQuery()
.in(this) .in(instance!.proxy)
.select("#" + id); .select("#" + id)
el.fields( el.fields(
{ {
size: true, size: true,
scrollOffset: true, scrollOffset: true,
rect: true, rect: true,
}, },
(data) => { (data: any) => {
res(data); res(data)
}
).exec()
})
} }
).exec();
});
},
/** /**
* 点击城市后回调 * 点击城市后回调
*/ */
async changCity(index, item) { const changCity = async (index: number, item: any) => {
if (this.tabbars[index].id != item.id) { if (tabbars.value[index].id != item.id) {
this.tabbars[index].localName = item.name; tabbars.value[index].localName = item.name
this.tabbars[index].id = item.id; tabbars.value[index].id = item.id
this.tabbars[index].center = item.center tabbars.value[index].center = item.center
if (index < this.tabbars.length - 1) { if (index < tabbars.value.length - 1) {
this.tabbars.splice(index + 1, this.tabbars.length - index - 1); tabbars.value.splice(index + 1, tabbars.value.length - index - 1)
} }
if (this.tabbars.length < this.pickersize) { if (tabbars.value.length < pickersize.value as number) {
uni.showLoading({ uni.showLoading({
title: "加载中", title: "加载中",
mask: true mask: true
}); })
try { try {
let data = await getRegionsById(item.id); let data = await getRegionsById(item.id)
uni.hideLoading(); uni.hideLoading()
// 当前选项级为最后一级时回调,将选中的数据返回 // 当前选项级为最后一级时回调,将选中的数据返回
if (data.data.result.length == 0) { if (data.data.result.length == 0) {
this.$emit("funcValue", this.tabbars); emit("funcValue", tabbars.value)
this.hide(); hide()
} else { } else {
// 将新的数据填充进下一级 // 将新的数据填充进下一级
var current = { var current = {
localName: "请选择", localName: "请选择",
id: "", id: "",
children: data.data.result, children: data.data.result,
}
}; tabbars.value.push(current)
this.tabbars.push(current); tabCurrentIndex.value++
this.tabCurrentIndex++;
// 当前距离重新为最上面 // 当前距离重新为最上面
this['scrollTop'] = 0 scrollTop.value = 0
} }
} catch (error) { } catch (error) {
uni.hideLoading(); uni.hideLoading()
} }
} else { } else {
this.$emit("funcValue", this.tabbars); emit("funcValue", tabbars.value)
this.hide(); hide()
}
} }
} }
},
/** /**
* 获取当前tab中滚动的距离 * 获取当前tab中滚动的距离
*/ */
async setScroll(index) { const setScroll = async (index: number) => {
let width = 0; let width = 0
let nowWidth = 0; let nowWidth = 0
for (let i = 0; i <= index; i++) { for (let i = 0; i <= index; i++) {
let result = await this.getElSize("tab" + i); let result = await getElSize("tab" + i)
width += result.width; width += result.width
if (i === index) { if (i === index) {
nowWidth = result.width; nowWidth = result.width
} }
} }
if (width + nowWidth > windowWidth) { if (width + nowWidth > windowWidth) {
this.scrollLeft = width + nowWidth; scrollLeft.value = width + nowWidth
} else { } else {
this.scrollLeft = 0; scrollLeft.value = 0
}
} }
},
/** /**
* 计算当前的滚动距离 * 计算当前的滚动距离
*/ */
getScroll(id) { const getScroll = (id: string) => {
uni uni
.createSelectorQuery() .createSelectorQuery()
.in(this) .in(instance!.proxy)
.select(".panel-scroll-box") .select(".panel-scroll-box")
.boundingClientRect((data) => { .boundingClientRect((data: any) => {
uni uni
.createSelectorQuery() .createSelectorQuery()
.in(this) .in(instance!.proxy)
.select("#" + id) .select("#" + id)
.boundingClientRect((res) => { .boundingClientRect((res: any) => {
if (res != undefined && res != null && res != "") { if (res != undefined && res != null && res != "") {
this.scrollTop = res.top - data.top; scrollTop.value = res.top - data.top
} }
}) })
.exec(); .exec()
}) })
.exec(); .exec()
}, }
},
}; // 暴露方法给父组件调用
defineExpose({ show, hide })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div> <view>
<!-- 一行两列商品展示 --> <!-- 一行两列商品展示 -->
<view class="goods-list" v-if="type == 'twoColumns'"> <view class="goods-list" v-if="type == 'twoColumns'">
<view v-for="(item, index) in res" :key="index" class="goods-item"> <view v-for="(item, index) in res" :key="index" class="goods-item">
@@ -10,7 +10,7 @@
height="330rpx" height="330rpx"
mode="aspectFit" mode="aspectFit"
> >
<template #loading><u-loading></u-loading></template> <template #loading><u-loading-icon></u-loading-icon></template>
</u-image> </u-image>
</view> </view>
<view class="goods-detail"> <view class="goods-detail">
@@ -57,7 +57,7 @@
</view> </view>
<!-- 一行一列商品展示 --> <!-- 一行一列商品展示 -->
<div v-if="type == 'oneColumns'"> <div v-if="type == 'oneColumns'">
<div v-for="(item, index) in res" :key="index" class="goods-row"> div v-for="(item, index) in res" :key="index" class="goods-row">
<div class="flex goods-col"> <div class="flex goods-col">
<div class="goods-img" @click="navigateToDetailPage(item)"> <div class="goods-img" @click="navigateToDetailPage(item)">
<u-image <u-image
@@ -67,7 +67,7 @@
mode="aspectFit" mode="aspectFit"
:src="item.goodsImage || item.thumbnail" :src="item.goodsImage || item.thumbnail"
> >
<template #loading><u-loading></u-loading></template> <template #loading><u-loading-icon></u-loading-icon></template>
</u-image> </u-image>
</div> </div>
<div class="goods-detail"> <div class="goods-detail">
@@ -112,41 +112,26 @@
</div> </div>
</div> </div>
</div> </div>
</div> </view>
</template> </template>
<script> <script setup lang="ts">
import commonTpl from "@/components/m-goods-list/common"; import { useGoodsListCommon } from './common'
export default { import { goodsFormatPrice } from '@/utils/filters.js'
data() {
return { const { lightSearchStr, getPromotion, navigateToDetailPage, navigateToStoreDetailPage } = useGoodsListCommon()
lightColor: this.$mainColor,
}; const props = withDefaults(defineProps<{
}, type?: string
mixins: [commonTpl], res?: any[]
props: { storeName?: boolean
// 展示的类型 keyword?: string | null
type:{ }>(), {
type:String, type: 'oneColumns',
default:"oneColumns" res: () => [],
}, storeName: true,
// 遍历的数据 keyword: ''
res: { })
type: Array,
default: () => {
return [];
},
},
},
methods: {
// 跳转到商品详情
navigateToDetailPage(item) {
uni.navigateTo({
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -0,0 +1,90 @@
import { useStore } from '@/store'
/**
* 商品列表公共逻辑(原 common.vue mixin
* 提供高亮搜索、unicode 转换、促销标签、导航跳转等通用方法
*/
export function useGoodsListCommon() {
const store = useStore()
const lightColor = store.getters.lightColor
/**
* 高亮显示搜索内容
*/
const lightSearchStr = (keyword: string, str: string) => {
if (!keyword) {
return str
} else {
let unicodes = ''
for (let i of Array.from(keyword)) {
unicodes += unicode(i) + "|"
}
const rule = '(' + unicodes + ')'
const reg = new RegExp(rule, 'gi')
return str ? str.replace(reg, (matchValue) =>
`<span style="color:${lightColor}">${matchValue}</span>`
) : ''
}
}
/**
* 转换为 unicode
*/
const unicode = (str: string) => {
var value = ''
for (var i = 0; i < str.length; i++) {
value += '\\u' + leftZero4(parseInt(str.charCodeAt(i).toString(16)))
}
return value
}
const leftZero4 = (str: string) => {
if (str != null && str != '' && str != 'undefined') {
if (str.length == 2) {
return '00' + str
}
}
return str
}
/**
* 数据去重 只显示一次 减免 劵等
*/
const getPromotion = (item: any) => {
if (item.promotionMap) {
let array: string[] = []
Object.keys(item.promotionMap).forEach((child) => {
if (!array.includes(child.split("-")[0])) {
array.push(child.split("-")[0])
}
})
return array
}
}
/**
* 跳转到商品详情
*/
const navigateToDetailPage = (item: any) => {
uni.navigateTo({
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
})
}
/**
* 跳转到店铺详情
*/
const navigateToStoreDetailPage = (item: any) => {
uni.navigateTo({
url: `/pages/product/shopPage?id=${item.storeId}`,
})
}
return {
lightSearchStr,
getPromotion,
navigateToDetailPage,
navigateToStoreDetailPage,
}
}

View File

@@ -1,69 +0,0 @@
<template>
</template>
<script>
export default {
methods: {
// 高亮显示搜索内容
lightSearchStr(keyword, str) {
if (!keyword) {
return str
} else {
let unicodes = '';
for (let i of Array.from(keyword)) {
unicodes += this.unicode(i) + "|"
}
const rule = '(' + unicodes + ')'
const reg = new RegExp(rule, 'gi');
return str ? str.replace(reg, matchValue =>
`<span style="color:${this.lightColor}">${matchValue}</span>`
) : ''
}
},
// 转换为unicode
unicode(str) {
var value = '';
for (var i = 0; i < str.length; i++) {
value += '\\u' + this.left_zero_4(parseInt(str.charCodeAt(i)).toString(16));
}
return value;
},
left_zero_4(str) {
if (str != null && str != '' && str != 'undefined') {
if (str.length == 2) {
return '00' + str;
}
}
return str;
},
// 数据去重一下 只显示一次 减免 劵 什么的
getPromotion(item) {
if (item.promotionMap) {
let array = [];
Object.keys(item.promotionMap).forEach((child) => {
if (!array.includes(child.split("-")[0])) {
array.push(child.split("-")[0]);
}
});
return array;
}
},
// 跳转到商品详情
navigateToDetailPage(item) {
uni.navigateTo({
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
});
},
// 跳转地址
navigateToStoreDetailPage(item) {
uni.navigateTo({
url: `/pages/product/shopPage?id=${item.storeId}`,
});
},
},
}
</script>
<style lang='scss' scoped>
</style>

View File

@@ -5,7 +5,7 @@
<view v-for="(item, index) in res" :key="index" class="goods-item"> <view v-for="(item, index) in res" :key="index" class="goods-item">
<view class="image-wrapper" @click="navigateToDetailPage(item)"> <view class="image-wrapper" @click="navigateToDetailPage(item)">
<u-image :src="item.thumbnail" width="100%" height='330rpx' mode="aspectFit"> <u-image :src="item.thumbnail" width="100%" height='330rpx' mode="aspectFit">
<template #loading><u-loading></u-loading></template> <template #loading><u-loading-icon></u-loading-icon></template>
</u-image> </u-image>
</view> </view>
<view class="goods-detail"> <view class="goods-detail">
@@ -51,7 +51,7 @@
<div class="flex goods-col"> <div class="flex goods-col">
<div class="goods-img" @click="navigateToDetailPage(item)"> <div class="goods-img" @click="navigateToDetailPage(item)">
<u-image width="230rpx" mode="aspectFit" border-radius='16' height="230rpx" :src="item.thumbnail"> <u-image width="230rpx" mode="aspectFit" border-radius='16' height="230rpx" :src="item.thumbnail">
<template #loading><u-loading></u-loading></template> <template #loading><u-loading-icon></u-loading-icon></template>
</u-image> </u-image>
</div> </div>
<div class="goods-detail"> <div class="goods-detail">
@@ -94,114 +94,32 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import commonTpl from '@/components/m-goods-list/common' import { watch } from 'vue'
export default { import { useGoodsListCommon } from './common'
data() { import { goodsFormatPrice } from '@/utils/filters.js'
return {
lightColor: this.$mainColor
}
},
mixins: [commonTpl],
props: { const { lightSearchStr, getPromotion, navigateToDetailPage, navigateToStoreDetailPage } = useGoodsListCommon()
// 遍历的数据
res: {
type: Array,
default: () => {
return []
}
},
// 一行两列还是一行一列显示
type: {
type: String,
default: 'twoColumns',
validator() {
return ['twoColumns', 'oneColumns']
}
},
storeName: {
type: Boolean,
default: true
},
tabBarGap: {
type: Boolean,
default: true
},
keyword: {
type: null,
default: ''
}
}, const props = withDefaults(defineProps<{
watch: { res?: any[]
keyword(val) { type?: string
storeName?: boolean
tabBarGap?: boolean
keyword?: string | null
}>(), {
res: () => [],
type: 'twoColumns',
storeName: true,
tabBarGap: true,
keyword: ''
})
watch(() => props.keyword, (val) => {
if (val) { if (val) {
this.lightSearchStr(val) lightSearchStr(val as string, '')
}
}
},
methods: {
// 高亮显示搜索内容
lightSearchStr(keyword, str) {
if (!keyword) {
return str
} else {
let unicodes = '';
for (let i of Array.from(keyword)) {
unicodes += this.unicode(i) + "|"
}
const rule = '(' + unicodes + ')'
const reg = new RegExp(rule, 'gi');
return str ? str.replace(reg, matchValue =>
`<span style="color:${this.lightColor}">${matchValue}</span>`
) : ''
}
},
// 转换为unicode
unicode(str) {
var value = '';
for (var i = 0; i < str.length; i++) {
value += '\\u' + this.left_zero_4(parseInt(str.charCodeAt(i)).toString(16));
}
return value;
},
left_zero_4(str) {
if (str != null && str != '' && str != 'undefined') {
if (str.length == 2) {
return '00' + str;
}
}
return str;
},
// 数据去重一下 只显示一次 减免 劵 什么的
getPromotion(item) {
if (item ? item.promotionMap : item.promotionMap) {
const fieldList = item ? item.promotionMap : item.promotionMap
let array = [];
Object.keys(fieldList).forEach((child) => {
if (!array.includes(child.split("-")[0])) {
array.push(child.split("-")[0]);
}
});
return array;
}
},
// 跳转到商品详情
navigateToDetailPage(item) {
uni.navigateTo({
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
});
},
// 跳转地址
navigateToStoreDetailPage(item) {
uni.navigateTo({
url: `/pages/product/shopPage?id=${item.storeId}`,
});
},
}
} }
})
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
@@ -212,6 +130,7 @@
.goods-list { .goods-list {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between;
margin: 10rpx 20rpx 284rpx; margin: 10rpx 20rpx 284rpx;
width: calc(100% - 40rpx); width: calc(100% - 40rpx);
box-sizing: border-box; box-sizing: border-box;
@@ -225,14 +144,10 @@
display: flex; display: flex;
border-radius: 16rpx; border-radius: 16rpx;
flex-direction: column; flex-direction: column;
width: calc(50% - 30rpx); width: calc(50% - 10rpx);
margin-bottom: 20rpx; margin-bottom: 20rpx;
padding-bottom: 20rpx; padding-bottom: 20rpx;
&:nth-child(2n + 1) {
margin-right: 20rpx;
}
.image-wrapper { .image-wrapper {
width: 100%; width: 100%;
@@ -344,7 +259,7 @@
color: $light-color; color: $light-color;
margin-right: 10rpx; margin-right: 10rpx;
padding: 0 4rpx; padding: 0 4rpx;
border-radius: 2rpx; border-radius: 2px;
} }
} }
@@ -421,6 +336,5 @@
} }
} }
} }
} }
</style> </style>

View File

@@ -4,7 +4,7 @@
<div class="flex goods-col"> <div class="flex goods-col">
<div class="goods-img"> <div class="goods-img">
<u-image width="230rpx" mode="aspectFit" border-radius='16' height="230rpx" :src="item.goodsImage || item.thumbnail"> <u-image width="230rpx" mode="aspectFit" border-radius='16' height="230rpx" :src="item.goodsImage || item.thumbnail">
<template #loading><u-loading></u-loading></template> <template #loading><u-loading-icon></u-loading-icon></template>
</u-image> </u-image>
</div> </div>
<div class="goods-detail"> <div class="goods-detail">
@@ -43,42 +43,32 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import commonTpl from '@/components/m-goods-list/common' import { useGoodsListCommon } from './common'
export default { import { goodsFormatPrice } from '@/utils/filters.js'
data() {
return { const { navigateToDetailPage } = useGoodsListCommon()
lightColor: this.$mainColor,
} const props = withDefaults(defineProps<{
}, res?: any[]
mixins: [commonTpl], type?: string | null
props: { }>(), {
// 遍历的数据 res: () => [],
res: { type: ''
type: Array, })
default: () => {
return [] // 跳转到商品详情(覆盖公共方法,增加砍价跳转)
} const navigateToDetailPageOverride = (item: any) => {
}, if(props.type == 'kanJia'){
type:{
type:null,
default:""
}
},
methods: {
// 跳转到商品详情
navigateToDetailPage(item) {
if(this.type == 'kanJia'){
uni.navigateTo({ uni.navigateTo({
url: `/pages/promotion/bargain/detail?id=${item.id}`, url: `/pages/promotion/bargain/detail?id=${item.id}`,
}); })
return return
} }
uni.navigateTo({ navigateToDetailPage({
url: `/pages/product/goods?id=${item.skuId}&goodsId=${item.goodsId}`, id: item.skuId,
}); goodsId: item.goodsId,
}, })
}
} }
</script> </script>

View File

@@ -1,73 +1,63 @@
<template> <template>
<div> <view>
<div class="goods-recommend">{{title ? `--${title}-- `:''}}</div> <view class="goods-recommend">{{title ? `--${title}-- `:''}}</view>
<goodsTemplate :res='goodsList' /> <goodsTemplate :res='goodsList' />
</div> </view>
</template> </template>
<script> <script setup lang="ts">
import goodsTemplate from '@/components/m-goods-list/list' import { ref, onMounted } from 'vue'
import { getGoodsList } from "@/api/goods.js"; import goodsTemplate from '@/components/m-goods-list/list.vue'
export default { import { getGoodsList } from "@/api/goods.js"
data() {
return { const props = withDefaults(defineProps<{
goodsList: [], title?: string
params: { pageSize?: number | null
categoryId?: string | null
storeId?: string | null
}>(), {
title: '',
pageSize: 12,
categoryId: '',
storeId: ''
})
const goodsList = ref<any[]>([])
const params = ref({
pageNumber: 1, pageNumber: 1,
}, })
};
}, onMounted(() => {
props: { initGoods()
title: { })
type: String,
default: "",
},
pageSize: {
type: null,
default: 12,
},
categoryId: {
type: null,
default: "",
},
storeId: {
type: null,
default: "",
},
},
components:{goodsTemplate},
mounted() {
this.initGoods();
},
methods: {
/** /**
* 初始化商品 * 初始化商品
*/ */
async initGoods() { const initGoods = async () => {
let submit = JSON.parse( let submit = JSON.parse(
JSON.stringify( JSON.stringify(
Object.assign(this.params, { Object.assign(params.value, {
pageSize: this.pageSize, pageSize: props.pageSize,
categoryId: this.categoryId, categoryId: props.categoryId,
storeId: this.storeId, storeId: props.storeId,
}) })
) )
); )
Object.keys(submit).map((key) => { Object.keys(submit).map((key) => {
if (!submit[key] || submit[key].length == 0) { if (!submit[key] || (submit[key] as any).length == 0) {
delete submit[key]; delete submit[key]
} }
}); })
let goodsList = await getGoodsList(submit); let res = await getGoodsList(submit)
this.goodsList.push(...goodsList.data.result.records); goodsList.value.push(...(res.data.result.records as any[]))
}, }
handleClick(item) {
const handleClick = (item: any) => {
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`, url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
}); })
}, }
},
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="index"> <view class="index">
<view v-model="show" class="slot-content"> <view v-model="show" class="slot-content">
<image @click="downLoad()" class="img" :src="imgUrl" /> <image @click="downLoad()" class="img" :src="imgUrl" />
<div class="canvas-hide"> <div class="canvas-hide">
@@ -11,181 +11,153 @@
<!-- #endif --> <!-- #endif -->
</div> </div>
</view> </view>
</div> </view>
</template> </template>
<script> <script setup lang="ts">
import { ref, onMounted, getCurrentInstance } from 'vue'
// 引入绘制插件 // 引入绘制插件
import DrawPoster from "@/js_sdk/u-draw-poster"; import DrawPoster from "@/js_sdk/u-draw-poster"
// 生成二维码 // 生成二维码
import uQRCode from '@/components/Sansnn-uQRCode/uqrcode.js'; import uQRCode from '@/components/Sansnn-uQRCode/uqrcode.js'
import logoImg from "@/pages/passport/static/logo-title.png"; import logoImg from "@/pages/passport/static/logo-title.png"
import myFaceImg from "@/pages/passport/static/missing-face.png"; import myFaceImg from "@/pages/passport/static/missing-face.png"
const instance = getCurrentInstance()
const props = defineProps<{
res?: any
}>()
const imgUrl = ref("")
const show = ref(false)
const dp = ref<any>({})
const logo = logoImg
const myFace = myFaceImg
const sharingLink = ref('')
export default {
data: () => ({
imgUrl: "", //绘制出来的图片路径
show: false, //是否展示模态框
dp: {}, //绘制的dp对象用于存储绘制等一些方法。
logo: logoImg, // 本地logo地址
myFace: myFaceImg, // 本地默认头像
sharingLink: '', // 二维码链接
}),
props: {
/**
* 父级传参的数据
*/
res: {
type: null,
default: "",
},
},
onUnload() {},
onReady() {},
methods: {
/** 解决微信小程序中图片模糊问题 */ /** 解决微信小程序中图片模糊问题 */
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
st2: (size) => size * 2, const st2 = (size: number) => size * 2
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
st2: (size) => size, const st2 = (size: number) => size
// #endif // #endif
/** 保存图片 */ /** 保存图片 */
downLoad() { const downLoad = () => {
uni.saveImageToPhotosAlbum({ uni.saveImageToPhotosAlbum({
filePath: this.imgUrl, filePath: imgUrl.value,
success: function () { success: function () {
uni.showToast({title: "保存成功!",icon: "none",}); uni.showToast({title: "保存成功!",icon: "none"})
}, },
fail: function () { fail: function () {
uni.showToast({title: "保存失败,请稍后重试!",icon: "none",}); uni.showToast({title: "保存失败,请稍后重试!",icon: "none"})
},
});
}, },
})
}
/** 创建canvas */ /** 创建canvas */
async init() { const init = async () => {
this.show = true; show.value = true
this.dp = await DrawPoster.build({ dp.value = await DrawPoster.build({
selector: "canvas", selector: "canvas",
componentThis: this, componentThis: instance?.proxy,
loading: true, loading: true,
debugging: true, debugging: true,
}); })
let dp = this.dp; let dpVal = dp.value
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
// 用于微信小程序中画布错乱问题 // 用于微信小程序中画布错乱问题
dp.canvas.width = this.st2(560); dpVal.canvas.width = st2(560)
dp.canvas.height = this.st2(800); dpVal.canvas.height = st2(800)
// #endif // #endif
this.showQRCode(dp); await showQRCode(dpVal)
}, }
/** 生成二维码 */ /** 生成二维码 */
async showQRCode(dp){ const showQRCode = async (dp: any) => {
await uQRCode.make({ await uQRCode.make({
canvasId: 'canvas', // canvas画布 canvasId: 'canvas',
componentInstance: this, componentInstance: instance?.proxy,
text: this.res.bottom.code, // 二维码内容 text: props.res.bottom.code,
size: 130, // 二维码大小 size: 130,
margin: 5, // 二维码内边距 margin: 5,
backgroundColor: '#ffffff', // 二维码背景颜色 backgroundColor: '#ffffff',
foregroundColor: '#000000', // !二维码色块颜色 foregroundColor: '#000000',
fileType: 'jpg', fileType: 'jpg',
errorCorrectLevel: 0, // <== 关键 容错率M:0,L:1,H:2,Q:3, errorCorrectLevel: 0,
// errorCorrectLevel: uQRCode.errorCorrectLevel.M, // <== 关键 容错率M:0,L:1,H:2,Q:3, success: (res: any) => {
success: res => { sharingLink.value = res
this.sharingLink = res; // res => 图片路径 draw(dp)
// 对画布进行绘制
this.draw(dp);
}, },
fail: res => { fail: (_res: any) => {
// console.log('失败',res) // console.log('失败',res)
} }
}) })
}, }
async draw(dp) {
const { face, nickName, desc } = this.res.memberInfo; const draw = async (dp: any) => {
const { width, height, background, title } = this.res.container; const { face, nickName, desc } = props.res.memberInfo
const { code, img, price } = this.res.bottom; const { width, height, background, title } = props.res.container
const { img, price } = props.res.bottom
/** 绘制背景 */ /** 绘制背景 */
await dp.draw((ctx) => { await dp.draw((ctx: any) => {
ctx.fillStyle = background; ctx.fillStyle = background
ctx.fillRoundRect( this.st2(0), this.st2(0), this.st2(width), this.st2(height), this.st2(12)); ctx.fillRoundRect(st2(0), st2(0), st2(width), st2(height), st2(12))
ctx.clip(); ctx.clip()
}); })
/** 绘制圆角矩形 */ /** 绘制圆角矩形 */
await dp.draw(async (ctx)=>{ await dp.draw(async (ctx: any) => {
// 设置矩形色彩 ctx.fillStyle = "#ffffff"
ctx.fillStyle = "#ffffff"; ctx.strokeStyle = "#ffffff"
// 设置图形轮廓的颜色。默认情况下线条和填充颜色都是黑色CSS 颜色值 #000000 ctx.lineWidth = st2(1)
ctx.strokeStyle = "#ffffff"; ctx.fillRoundRect(30, 150, 500, 620, 0)
// 这个属性设置当前绘线的粗细。属性值必须为正数。描述线段宽度的数字。 0、 负数、 Infinity 和 NaN 会被忽略。默认值是1.0。
ctx.lineWidth = this.st2(1);
// 进行绘制
ctx.fillRoundRect(30, 150, 500, 620, 0);
// ctx.strokeRoundRect(30, 150, 500, 620, 0);
// ctx.strokeRect(30, 150, 500, 620, 0);
}) })
/** 绘制图片 */ /** 绘制图片 */
dp.draw(async (ctx) => { dp.draw(async (ctx: any) => {
await Promise.all([ await Promise.all([
// 绘制头像face ctx.drawImage(face ? face : myFace, st2(30), st2(30), st2(90), st2(90)),
ctx.drawImage(face?face:this.myFace, this.st2(30), this.st2(30), this.st2(90), this.st2(90)), ctx.drawImage(img, st2(60), st2(170), st2(440), st2(440)),
// 绘制Logo ctx.drawImage(sharingLink.value, st2(375), st2(625), st2(130), st2(130))
// ctx.drawImage( this.logo, this.st2(175), this.st2(0), this.st2(256), this.st2(144)), ])
// 中间图片 })
ctx.drawImage(img, this.st2(60), this.st2(170), this.st2(440), this.st2(440)),
// 二维码
ctx.drawImage(this.sharingLink, this.st2(375), this.st2(625), this.st2(130), this.st2(130))
]);
});
/** 绘制顶部文字(昵称 简述) */ /** 绘制顶部文字(昵称 简述) */
await dp.draw((ctx) => { await dp.draw((ctx: any) => {
ctx.fillStyle = "#666"; ctx.fillStyle = "#666"
ctx.font = `${this.st2(24)}px PingFang SC`; ctx.font = `${st2(24)}px PingFang SC`
ctx.fillText(nickName, this.st2(150), this.st2(65)); ctx.fillText(nickName, st2(150), st2(65))
ctx.fillStyle = "#666"; ctx.fillStyle = "#666"
ctx.font = `${this.st2(24)}px PingFang SC`; ctx.font = `${st2(24)}px PingFang SC`
ctx.fillText(desc, this.st2(150), this.st2(105)); ctx.fillText(desc, st2(150), st2(105))
}); })
/** 绘制中间文字(商品名称 价格) */ /** 绘制中间文字(商品名称 价格) */
await dp.draw((ctx) => { await dp.draw((ctx: any) => {
ctx.fillStyle = "#333"; ctx.fillStyle = "#333"
ctx.font = `bold ${this.st2(24)}px PingFang SC`; ctx.font = `bold ${st2(24)}px PingFang SC`
ctx.textAlign = "left"; ctx.textAlign = "left"
ctx.fillWarpText({ ctx.fillWarpText({
text: title, text: title,
lineHeight: this.st2(32), lineHeight: st2(32),
maxWidth: this.st2(280), maxWidth: st2(280),
x: this.st2(60), x: st2(60),
y: this.st2(710), y: st2(710),
layer: 2, layer: 2,
}); })
ctx.fillStyle = "#ff3c2a"; ctx.fillStyle = "#ff3c2a"
ctx.font = `${this.st2(38)}px PingFang SC`; ctx.font = `${st2(38)}px PingFang SC`
ctx.textAlign = "left"; ctx.textAlign = "left"
ctx.fillText(price, this.st2(60), this.st2(665)); ctx.fillText(price, st2(60), st2(665))
}); })
/** 绘制底部文字 */
// await dp.draw((ctx) => {
// ctx.fillStyle = "#666";
// ctx.font = `${this.st2(24)}px PingFang SC`;
// ctx.fillText("长按图片,识别二维码", this.st2(200), this.st2(866));
// ctx.fillStyle = "#666";
// ctx.font = `${this.st2(24)}px PingFang SC`;
// ctx.fillText("查看商品详情", this.st2(200), this.st2(900));
// });
// 绘制生成本地地址 // 绘制生成本地地址
this.imgUrl = await dp.createImagePath(); imgUrl.value = await dp.createImagePath()
}, }
},
async mounted() { onMounted(() => {
this.init(); init()
}, })
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -28,138 +28,122 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { import { ref, watch, onMounted } from 'vue'
props: {
mode: { const props = withDefaults(defineProps<{
value: Number, mode?: number
default: 1, placeholder?: string
}, value?: string
//HM修改 定义默认搜索关键词(水印文字) radius?: string
placeholder: { isFocusVal?: boolean
value: String, showClear?: boolean
default: "请输入搜索内容", }>(), {
}, mode: 1,
value: { placeholder: "请输入搜索内容",
type: String, value: "",
default: "", radius: "60",
}, isFocusVal: true,
// 默认半径为60 showClear: true,
radius: { })
value: String,
default: 60, const emit = defineEmits(['confirm', 'input', 'search', 'SwitchType'])
},
// 是否获取焦点 const isShowSeachGoods = ref(false)
isFocusVal: { const active = ref(false)
value: Boolean, const inputVal = ref("")
default: true, const isDelShow = ref(false)
}, const isFocus = ref(false)
showClear: { const switchLayout = ref(true)
type: Boolean,
default: true, onMounted(() => {
}, isFocus.value = props.isFocusVal
}, })
data() {
return {
isShowSeachGoods: false, //是否显示查询的商品
active: false, //是否选中
inputVal: "", //Input中内容
isDelShow: false, //是否显示右侧删除icon
isFocus: false, //是否获取焦点
switchLayout: true, //切换当前商品的布局,默认为两列
};
},
mounted() {
this.isFocus = this.isFocusVal;
},
methods: {
// //
out() { const out = () => {
uni.reLaunch({ uni.reLaunch({
url: "/pages/tabbar/home/index", url: "/pages/tabbar/home/index",
}); })
}, }
// 切换排列顺序 // 切换排列顺序
handelListClass() { const handelListClass = () => {
this.switchLayout = !this.switchLayout; switchLayout.value = !switchLayout.value
this.$emit("SwitchType"); emit("SwitchType")
}, }
//HM修改 触发组件confirm事件 //HM修改 触发组件confirm事件
triggerConfirm() { const triggerConfirm = () => {
this.$emit("confirm", false); emit("confirm", false)
uni.hideKeyboard(); uni.hideKeyboard()
}, }
//HM修改 触发组件input事件 //HM修改 触发组件input事件
inputChange(event) { const inputChange = (event: any) => {
var keyword = event.detail.value; var keyword = event.detail.value
this.$emit("input", keyword); emit("input", keyword)
if (this.inputVal) { if (inputVal.value) {
this.isDelShow = true; isDelShow.value = true
} }
}, }
focus() { const focus = () => {
this.active = true; active.value = true
//HM修改 增加获取焦点判断 //HM修改 增加获取焦点判断
if (this.inputVal) { if (inputVal.value) {
this.isDelShow = true; isDelShow.value = true
} }
},
blur() {
this.isFocus = false;
if (!this.inputVal) {
this.active = false;
} }
}, const blur = () => {
clear() { isFocus.value = false
if (!inputVal.value) {
active.value = false
}
}
const clear = () => {
//HM修改 收起键盘 //HM修改 收起键盘
uni.hideKeyboard(); uni.hideKeyboard()
this.isFocus = false; isFocus.value = false
this.inputVal = ""; inputVal.value = ""
this.active = false; active.value = false
//HM修改 清空内容时候触发组件input //HM修改 清空内容时候触发组件input
this.$emit("input", ""); emit("input", "")
//this.$emit('search', '');//HM修改 清空内容时候不进行搜索 //this.$emit('search', '');//HM修改 清空内容时候不进行搜索
}, }
/** /**
* 回退到上一级 * 回退到上一级
*/ */
onClickLeft() { const onClickLeft = () => {
const paths = getCurrentPages(); const paths = getCurrentPages()
console.log(paths) console.log(paths)
if(paths.length > 1){ if(paths.length > 1){
uni.navigateBack(); uni.navigateBack()
}else{ }else{
uni.switchTab({ uni.switchTab({
url:"/pages/tabbar/home/index" url:"/pages/tabbar/home/index"
}) })
} }
}, }
/** /**
* 内容为空时,输入默认关键字 * 内容为空时,输入默认关键字
*/ */
search() { const search = () => {
if (!this.inputVal) { if (!inputVal.value) {
if (this.searchName == "取消") { if (false) { // searchName == "取消" - 兼容旧逻辑
uni.hideKeyboard(); uni.hideKeyboard()
this.isFocus = false; isFocus.value = false
this.active = false; active.value = false
return; return
} }
} }
this.$emit("search", this.inputVal ? this.inputVal : this.placeholder); emit("search", inputVal.value ? inputVal.value : props.placeholder)
}, }
},
watch: {
/** /**
* 监听当前是否有值 是否显示清除图标 * 监听当前是否有值 是否显示清除图标
*/ */
inputVal(newVal) { watch(inputVal, (newVal) => {
newVal ? (this.isDelShow = true) : (this.isDelShow = false); newVal ? (isDelShow.value = true) : (isDelShow.value = false)
}, })
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -28,19 +28,29 @@
</view> </view>
</u-popup> </u-popup>
</template> </template>
<script>
import { h5Copy } from "@/js_sdk/h5-copy/h5-copy.js";
import configs from "@/config/config";
import mpShare from "@/utils/mpShare.js";
import { setClipboard } from "@/utils/filters.js";
export default { <script setup lang="ts">
mixins: [mpShare], import { ref } from 'vue'
data() { import configs from "@/config/config"
return { import mpShare from "@/utils/mpShare.js"
configs, import { setClipboard } from "@/utils/filters.js"
show: true,
list: [ // mixin 处理mpShare 提供小程序分享能力
mpShare
const props = defineProps<{
thumbnail?: string
goodsName?: string
type?: string
goodsId?: string | number
link?: string
}>()
const emit = defineEmits(['close'])
const show = ref(true)
const config = configs
const list = ref([
{ {
color: "#04BE02", color: "#04BE02",
title: "微信好友", title: "微信好友",
@@ -53,93 +63,90 @@ export default {
icon: "weixin-circle-fill", icon: "weixin-circle-fill",
type: 1, type: 1,
}, },
], ])
};
},
// 图片缩略图、 商品名称 、 typegoods,shop,pintuan) 拼团商品分享以及店铺分享
props: ["thumbnail", "goodsName", "type", "goodsId", "link"], const close = () => {
methods: { emit("close")
close() { }
this.$emit("close");
}, const weChatShare = () => {
weChatShare(){ // @ts-ignore
this.$u.mpShare = { const proxy = getCurrentInstance()?.proxy
title: this.shareTitle(), // 默认为小程序名称,可自定义 if (proxy) {
path: '', // 默认为当前页面路径一般无需修改QQ小程序不支持 // @ts-ignore
// 分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径。 proxy.$u.mpShare = {
// 支持PNG及JPG默认为当前页面的截图 title: shareTitle(),
imageUrl: this.thumbnail ||'' path: '',
imageUrl: props.thumbnail || ''
}
}
} }
},
// h5复制链接 // h5复制链接
// #ifdef H5 // #ifdef H5
copyLink() { const copyLink = () => {
let content; let content: string
if (this.link) { if (props.link) {
content = this.configs.shareLink + this.link; content = config.shareLink + props.link
} else { } else {
content = content =
this.configs.shareLink + config.shareLink +
getCurrentPages()[getCurrentPages().length - 1].__page__.fullPath; getCurrentPages()[getCurrentPages().length - 1].__page__.fullPath
} }
setClipboard(content) setClipboard(content)
}, }
// #endif // #endif
shareTitle() { const shareTitle = (): string => {
let shareTitle; let shareTitle: string = ''
if (this.type == "goods") { if (props.type == "goods") {
shareTitle = `[好友推荐]${this.goodsName}快来跟我一起看看吧`; shareTitle = `[好友推荐]${props.goodsName}快来跟我一起看看吧`
} else if (this.type == "shops") { } else if (props.type == "shops") {
shareTitle = `[好友发现]${this.goodsName}快来跟我一起看看吧`; shareTitle = `[好友发现]${props.goodsName}快来跟我一起看看吧`
} else if (this.type == "pintuan") { } else if (props.type == "pintuan") {
shareTitle = `[好友邀请]${this.goodsName}快来跟我一起抢购吧!`; shareTitle = `[好友邀请]${props.goodsName}快来跟我一起抢购吧!`
} else if (this.type == "kanjia") { } else if (props.type == "kanjia") {
shareTitle = `[好友邀请]请快来帮我砍一刀${this.goodsName}`; shareTitle = `[好友邀请]请快来帮我砍一刀${props.goodsName}`
}
return shareTitle
} }
return shareTitle;
},
// #ifdef APP-PLUS // #ifdef APP-PLUS
handleShare(val) { const handleShare = (val: any) => {
console.log("12312312") console.log("12312312")
if (val.type <= 1) { if (val.type <= 1) {
let scene; // "WXSenceTimeline 朋友圈 WXSceneSession 微信好友" let scene: string // "WXSenceTimeline 朋友圈 WXSceneSession 微信好友"
val.type == 1 val.type == 1
? (scene = "WXSenceTimeline") ? (scene = "WXSenceTimeline")
: (scene = "WXSceneSession"); : (scene = "WXSceneSession")
uni.share({ uni.share({
provider: "weixin", provider: "weixin",
scene: scene, scene: scene,
href: configs.shareLink + this.link, href: config.shareLink + props.link,
imageUrl: this.thumbnail, imageUrl: props.thumbnail,
type: 0, type: 0,
summary: this.goodsName, summary: props.goodsName,
title: this.shareTitle(), title: shareTitle(),
success: function (res) { success: function () {
uni.showToast({ uni.showToast({
title: "分享成功!", title: "分享成功!",
duration: 2000, duration: 2000,
icon: "none", icon: "none",
}); })
this.$emit("close"); emit("close")
}, },
fail: function (err) { fail: function () {
uni.showToast({ uni.showToast({
title: "分享失败!", title: "分享失败!",
duration: 2000, duration: 2000,
icon: "none", icon: "none",
}); })
this.$emit("close"); emit("close")
}, },
}); })
}
} }
},
// #endif // #endif
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "./mp-share.scss"; @import "./mp-share.scss";

View File

@@ -1,27 +1,21 @@
<template> <template>
<div> <view>
<u-popup v-model:show="show" mode="bottom" height="800rpx" border-radius="14"> <u-popup v-model:show="show" mode="bottom" height="800rpx" border-radius="14">
<div class="wrapper"> <view class="wrapper">
<view class="down-goods-tips">该商品已下架</view> <view class="down-goods-tips">该商品已下架</view>
<scroll-view scroll-y="true" style="height: 670rpx"> <scroll-view scroll-y="true" style="height: 670rpx">
<goodsRecommend title="其他商品" /> <goodsRecommend title="其他商品" />
</scroll-view> </scroll-view>
</div> </view>
</u-popup> </u-popup>
</div> </view>
</template> </template>
<script> <script setup lang="ts">
import goodsRecommend from "@/components/m-goods-recommend/index.vue"; import { ref } from 'vue'
import goodsRecommend from "@/components/m-goods-recommend/index.vue"
export default { const show = ref(true)
data() {
return {
show: true, // 是否显示
};
},
components: { goodsRecommend },
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -10,198 +10,175 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { import { ref, watch, onMounted, getCurrentInstance } from 'vue'
props: {
maskBg: { const props = withDefaults(defineProps<{
type: String, maskBg?: string
default: "rgba(0,0,0,0)", placement?: string
}, direction?: string
placement: { x?: number
type: String, y?: number
default: "default", //default top-start top-end bottom-start bottom-end modelValue?: boolean
}, popData?: any[]
direction: { theme?: string
type: String, dynamic?: boolean
default: "column", //column row gap?: number
}, triangle?: boolean
x: { }>(), {
type: Number, maskBg: "rgba(0,0,0,0)",
default: 0, placement: "default",
}, direction: "column",
y: { x: 0,
type: Number, y: 0,
default: 0, modelValue: false,
}, popData: () => [],
value: { theme: "light",
type: Boolean, dynamic: false,
default: false, gap: 20,
}, triangle: true,
popData: { })
type: Array,
default: () => [], const emit = defineEmits(['update:modelValue', 'tapPopup'])
},
theme: { const instance = getCurrentInstance()
type: String,
default: "light", //light dark const popupsTop = ref("0rpx")
}, const popupsLeft = ref("0rpx")
dynamic: { const show = ref(false)
type: Boolean, const dynPlace = ref("")
default: false,
}, onMounted(() => {
gap: { popupsPosition()
type: Number, })
default: 20,
}, const tapMask = () => {
triangle: { emit("update:modelValue", !props.modelValue)
type: Boolean, }
default: true,
}, const tapItem = (item: any) => {
}, if (item.disabled) return
data() { emit("tapPopup", item)
return { emit("update:modelValue", !props.modelValue)
popupsTop: "0rpx", }
popupsLeft: "0rpx",
show: false, const getStatusBar = () => {
dynPlace: "", const windowInfo = uni.getWindowInfo()
};
},
mounted() {
this.popupsPosition();
},
methods: {
tapMask() {
this.$emit("input", !this.value);
},
tapItem(item) {
if (item.disabled) return;
this.$emit("tapPopup", item);
this.$emit("input", !this.value);
},
getStatusBar() {
const windowInfo = uni.getWindowInfo();
// #ifdef H5 // #ifdef H5
return Promise.resolve( return Promise.resolve(
(windowInfo.statusBarHeight || 0) + (windowInfo.windowTop || 0) (windowInfo.statusBarHeight || 0) + (windowInfo.windowTop || 0)
); )
// #endif // #endif
// #ifndef H5 // #ifndef H5
return Promise.resolve(windowInfo.statusBarHeight || 0); return Promise.resolve(windowInfo.statusBarHeight || 0)
// #endif // #endif
}, }
async popupsPosition() {
let statusBar = await this.getStatusBar(); const popupsPosition = async () => {
let promise = new Promise((resolve, reject) => { let statusBar = await getStatusBar()
let popupsDom = uni.createSelectorQuery().in(this).select(".popups"); await new Promise<void>((resolve) => {
let popupsDom = uni.createSelectorQuery().in(instance!.proxy).select(".popups")
popupsDom popupsDom
.fields( .fields(
{ {
size: true, size: true,
}, },
(data) => { (data: any) => {
if (!data) { if (!data) {
resolve(); resolve()
return; return
} }
let width = data.width; let width = data.width
let height = data.height; let height = data.height
let y = props.dynamic
? dynamicGetY(props.y, props.gap)
: transformRpx(props.y)
let x = props.dynamic
let y = this.dynamic ? dynamicGetX(props.x, props.gap)
? this.dynamicGetY(this.y, this.gap) : transformRpx(props.x)
: this.transformRpx(this.y);
let x = this.dynamic
? this.dynamicGetX(this.x, this.gap)
: this.transformRpx(this.x);
// #ifdef H5 // #ifdef H5
y = this.dynamic y = props.dynamic
? this.y + statusBar ? props.y + statusBar
: this.transformRpx(this.y + statusBar); : transformRpx(props.y + statusBar)
// #endif // #endif
this.dynPlace = dynPlace.value =
this.placement == "default" props.placement == "default"
? this.getPlacement(x, y) ? getPlacement(x, y)
: this.placement; : props.placement
switch (this.dynPlace) { switch (dynPlace.value) {
case "top-start": case "top-start":
this.popupsTop = `${y + 9}rpx`; popupsTop.value = `${y + 9}rpx`
this.popupsLeft = `${x - 15}rpx`; popupsLeft.value = `${x - 15}rpx`
break; break
case "top-end": case "top-end":
this.popupsTop = `${y + 9}rpx`; popupsTop.value = `${y + 9}rpx`
this.popupsLeft = `${x + 15 - width}rpx`; popupsLeft.value = `${x + 15 - width}rpx`
break; break
case "bottom-start": case "bottom-start":
this.popupsTop = `${y - 18 - height}rpx`; popupsTop.value = `${y - 18 - height}rpx`
this.popupsLeft = `${x - 15}rpx`; popupsLeft.value = `${x - 15}rpx`
break; break
case "bottom-end": case "bottom-end":
this.popupsTop = `${y - 9 - height}rpx`; popupsTop.value = `${y - 9 - height}rpx`
this.popupsLeft = `${x + 15 - width}rpx`; popupsLeft.value = `${x + 15 - width}rpx`
break; break
} }
resolve(); resolve()
} }
) )
.exec(); .exec()
}); })
return promise;
},
getPlacement(x, y) {
const { windowWidth: width, windowHeight: height } = uni.getWindowInfo();
if (x > width / 2 && y > height / 2) {
return "bottom-end";
} else if (x < width / 2 && y < height / 2) {
return "top-start";
} else if (x > width / 2 && y < height / 2) {
return "top-end";
} else if (x < width / 2 && y > height / 2) {
return "bottom-start";
} else if (x > width / 2) {
return "top-end";
} else {
return "top-start";
} }
},
dynamicGetY(y, gap) {
const { windowHeight: height } = uni.getWindowInfo();
y = y < gap ? gap : y;
y = height - y < gap ? height - gap : y;
return y; const getPlacement = (x: number, y: number) => {
}, const { windowWidth: width, windowHeight: height } = uni.getWindowInfo()
dynamicGetX(x, gap) { if (x > width / 2 && y > height / 2) {
const { windowWidth: width } = uni.getWindowInfo(); return "bottom-end"
x = x < gap ? gap : x; } else if (x < width / 2 && y < height / 2) {
x = width - x < gap ? width - gap : x; return "top-start"
return x; } else if (x > width / 2 && y < height / 2) {
}, return "top-end"
transformRpx(params) { } else if (x < width / 2 && y > height / 2) {
const { screenWidth } = uni.getWindowInfo(); return "bottom-start"
return (params * screenWidth) / 375; } else if (x > width / 2) {
}, return "top-end"
}, } else {
watch: { return "top-start"
value: { }
immediate: true, }
handler: async function (newVal, oldVal) {
if (newVal) await this.popupsPosition(); const dynamicGetY = (y: number, gap: number) => {
this.show = newVal; const { windowHeight: height } = uni.getWindowInfo()
}, y = y < gap ? gap : y
}, y = height - y < gap ? height - gap : y
placement: { return y
immediate: true, }
handler(newVal, oldVal) {
this.dynPlace = newVal; const dynamicGetX = (x: number, gap: number) => {
}, const { windowWidth: width } = uni.getWindowInfo()
}, x = x < gap ? gap : x
}, x = width - x < gap ? width - gap : x
}; return x
}
const transformRpx = (params: number) => {
const { screenWidth } = uni.getWindowInfo()
return (params * screenWidth) / 375
}
watch(() => props.modelValue, async (newVal) => {
if (newVal) await popupsPosition()
show.value = newVal
}, { immediate: true })
watch(() => props.placement, (newVal) => {
dynPlace.value = newVal
}, { immediate: true })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -11,29 +11,21 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { import { computed } from 'vue'
name: 'UTimeLineItem',
props: { const props = defineProps<{
nodeTop: { nodeTop?: string | number
type: [String, Number], bgColor?: string
default: '' }>()
},
bgColor: { const nodeStyle = computed(() => {
type: String, if (props.nodeTop === '' || props.nodeTop === null || props.nodeTop === undefined) {
default: '#ffffff'
}
},
computed: {
nodeStyle() {
if (this.nodeTop === '' || this.nodeTop === null || this.nodeTop === undefined) {
return {} return {}
} }
const top = typeof this.nodeTop === 'number' ? `${this.nodeTop}rpx` : this.nodeTop const top = typeof props.nodeTop === 'number' ? `${props.nodeTop}rpx` : props.nodeTop
return { top } return { top }
} })
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -4,10 +4,8 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { // UTimeLine 组件
name: 'UTimeLine'
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -26,42 +26,28 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { withDefaults(defineProps<{
name: 'uni-load-more', status?: string
props: { showIcon?: boolean
status: { showText?: boolean
//上拉的状态more-loading前loading-loading中noMore-没有更多了 color?: string
type: String, contentText?: {
default: 'more' contentdown: string
}, contentrefresh: string
showIcon: { contentnomore: string
type: Boolean, }
default: true }>(), {
}, status: 'more',
showText: { showIcon: true,
type: Boolean, showText: true,
default: true color: '#777777',
}, contentText: () => ({
color: {
type: String,
default: '#777777'
},
contentText: {
type: Object,
default() {
return {
contentdown: '上拉显示更多', contentdown: '上拉显示更多',
contentrefresh: '正在加载...', contentrefresh: '正在加载...',
contentnomore: '没有更多数据了' contentnomore: '没有更多数据了',
}; }),
} })
}
},
data() {
return {};
}
};
</script> </script>
<style> <style>

View File

@@ -10,149 +10,123 @@
</view> </view>
</view> </view>
</template> </template>
<script>
/**
* NumberBox 数字输入框
* @description 带加减按钮的数字输入框
* @tutorial https://ext.dcloud.net.cn/plugin?id=31
* @property {Number} value 输入框当前值
* @property {Number} min 最小值
* @property {Number} max 最大值
* @property {Number} step 每次点击改变的间隔大小
* @property {String} background 背景色
* @property {String} color 字体颜色(前景色)
* @property {Boolean} disabled = [true|false] 是否为禁用状态
* @event {Function} change 输入框值改变时触发的事件,参数为输入框当前的 value
* @event {Function} focus 输入框聚焦时触发的事件,参数为 event 对象
* @event {Function} blur 输入框失焦时触发的事件,参数为 event 对象
*/
export default { <script setup lang="ts">
name: "UniNumberBox", import { ref, watch } from 'vue'
emits: ['change', 'input', 'update:modelValue', 'blur', 'focus'],
props: { const props = withDefaults(defineProps<{
value: { value?: number | string
type: [Number, String], modelValue?: number | string
default: 1 min?: number
}, max?: number
modelValue: { step?: number
type: [Number, String], background?: string
default: 1 color?: string
}, disabled?: boolean
min: { }>(), {
type: Number, value: 1,
default: 0 modelValue: 1,
}, min: 0,
max: { max: 100,
type: Number, step: 1,
default: 100 background: '#f5f5f5',
}, color: '#333',
step: { disabled: false,
type: Number, })
default: 1
}, const emit = defineEmits<{
background: { change: [value: number]
type: String, input: [value: number]
default: '#f5f5f5' 'update:modelValue': [value: number]
}, blur: [event: Event]
color: { focus: [event: Event]
type: String, }>()
default: '#333'
}, const inputValue = ref(0)
disabled: {
type: Boolean, watch(() => props.value, (val) => {
default: false inputValue.value = +val
})
watch(() => props.modelValue, (val) => {
inputValue.value = +val
})
if (props.value === 1) {
inputValue.value = +props.modelValue
} }
}, if (props.modelValue === 1) {
data() { inputValue.value = +props.value
return {
inputValue: 0
};
},
watch: {
value(val) {
this.inputValue = +val;
},
modelValue(val) {
this.inputValue = +val;
} }
},
created() { function _getDecimalScale() {
if (this.value === 1) { let scale = 1
this.inputValue = +this.modelValue; if (~~props.step !== props.step) {
scale = Math.pow(10, String(props.step).split('.')[1].length)
} }
if (this.modelValue === 1) { return scale
this.inputValue = +this.value;
} }
},
methods: { function _emitValue() {
_calcValue(type) { const val = +inputValue.value
if (this.disabled) { emit('change', val)
return; emit('input', val)
emit('update:modelValue', val)
} }
const scale = this._getDecimalScale();
let value = this.inputValue * scale; function _calcValue(type: 'minus' | 'plus') {
let step = this.step * scale; if (props.disabled) {
if (type === "minus") { return
value -= step;
if (value < (this.min * scale)) {
return;
} }
if (value > (this.max * scale)) { const scale = _getDecimalScale()
value = this.max * scale let value = inputValue.value * scale
const step = props.step * scale
if (type === 'minus') {
value -= step
if (value < props.min * scale) {
return
}
if (value > props.max * scale) {
value = props.max * scale
} }
} }
if (type === "plus") { if (type === 'plus') {
value += step; value += step
if (value > (this.max * scale)) { if (value > props.max * scale) {
return; return
} }
if (value < (this.min * scale)) { if (value < props.min * scale) {
value = this.min * scale value = props.min * scale
} }
} }
this.inputValue = (value / scale).toFixed(String(scale).length - 1); inputValue.value = Number((value / scale).toFixed(String(scale).length - 1))
this.$emit("change", +this.inputValue); _emitValue()
// TODO vue2 兼容
this.$emit("input", +this.inputValue);
// TODO vue3 兼容
this.$emit("update:modelValue", +this.inputValue);
},
_getDecimalScale() {
let scale = 1;
// 浮点型
if (~~this.step !== this.step) {
scale = Math.pow(10, String(this.step).split(".")[1].length);
} }
return scale;
}, function _onBlur(event: any) {
_onBlur(event) { emit('blur', event)
this.$emit('blur', event) let value = event.detail.value
let value = event.detail.value;
if (!value) { if (!value) {
// this.inputValue = 0; return
return;
} }
value = +value; value = +value
if (value > this.max) { if (value > props.max) {
value = this.max; value = props.max
} else if (value < this.min) { } else if (value < props.min) {
value = this.min; value = props.min
} }
const scale = this._getDecimalScale(); const scale = _getDecimalScale()
this.inputValue = value.toFixed(String(scale).length - 1); inputValue.value = Number(value.toFixed(String(scale).length - 1))
this.$emit("change", +this.inputValue); _emitValue()
this.$emit("input", +this.inputValue);
},
_onFocus(event) {
this.$emit('focus', event)
} }
function _onFocus(event: Event) {
emit('focus', event)
} }
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$box-height: 48rpx; $box-height: 48rpx;
$bg: #f5f5f5; $bg: #f5f5f5;
@@ -203,9 +177,7 @@
} }
.uni-numbox--text { .uni-numbox--text {
// fix nvue
line-height: 40rpx; line-height: 40rpx;
font-size: 40rpx; font-size: 40rpx;
font-weight: 300; font-weight: 300;
color: $color; color: $color;

View File

@@ -1,111 +1,99 @@
<template></template> <template></template>
<script>
import { getAddressCode } from "@/api/address"; <script setup lang="ts">
import { onMounted } from 'vue'
import { getAddressCode } from '@/api/address'
import config from '@/config/config' import config from '@/config/config'
export default {
data() { const emit = defineEmits<{
return { callback: [payload: Record<string, any>]
config close: []
}; }>()
},
mounted() { onMounted(() => {
this.init(); init()
}, })
methods: {
// 初始化地图并且调用 function initMap() {
initMap() {
let that = this;
uni.chooseLocation({ uni.chooseLocation({
success: function (res) { success(res) {
/**获取地址详情地址 */ posToCity(res.latitude, res.longitude).then((val) => {
that.posToCity(res.latitude, res.longitude).then((val) => {
/**获取地址code */
getAddressCode( getAddressCode(
val.regeocode.addressComponent.citycode, val.regeocode.addressComponent.citycode,
val.regeocode.addressComponent.township val.regeocode.addressComponent.township,
).then((code) => { ).then((code) => {
that.$emit("callback", { ...val, ...res, ...code }); emit('callback', { ...val, ...res, ...code })
that.$emit("close"); emit('close')
}); })
}); })
}, },
fail(e) { fail(e) {
console.log(e) console.log(e)
that.$emit("close"); emit('close')
},
});
}, },
})
}
// 根据当前客户端判断展示不同类型数据 function init() {
init() {
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
this.wechatMap(); wechatMap()
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
this.initMap(); initMap()
// #endif // #endif
}, }
// 如果是微信小程序单独走微信小程序授权模式 function wechatMap() {
wechatMap() {
let that = this;
uni.authorize({ uni.authorize({
scope: "scope.userLocation", scope: 'scope.userLocation',
success() { success() {
// 允许授权 initMap()
that.initMap();
}, },
fail() { fail() {
//拒绝授权
uni.showModal({ uni.showModal({
content: "检测到您没打开获取地址功能权限,是否去设置打开?", content: '检测到您没打开获取地址功能权限,是否去设置打开?',
confirmText: "确认", confirmText: '确认',
cancelText: "取消", cancelText: '取消',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
// 打开设置好后重新刷新地图
uni.openSetting({ uni.openSetting({
success: (res) => { success: () => {
that.initMap(); initMap()
}, },
}); })
} else { } else {
// 取消后关闭 emit('close')
that.$emit("close");
return false;
} }
}, },
}); })
return false;
}, },
}); })
}, }
// 获取城市的数据
posToCity(latitude, longitude) { function posToCity(latitude: number, longitude: number) {
return new Promise((resolve, reject) => { return new Promise<any>((resolve, reject) => {
uni.request({ uni.request({
url: `https://restapi.amap.com/v3/geocode/regeo`, url: 'https://restapi.amap.com/v3/geocode/regeo',
method: "GET", method: 'GET',
data: { data: {
key: config.aMapKey, //web服务的key key: config.aMapKey,
location: `${longitude},${latitude}`, location: `${longitude},${latitude}`,
}, },
success: ({ data }) => { success: ({ data }: any) => {
const { status, info } = data; const { status, info } = data
if (status === "1") { if (status === '1') {
resolve(data); resolve(data)
} else { } else {
reject(info); reject(info)
} }
}, },
fail: (err) => { fail: (err) => {
reject(err); reject(err)
}, },
}); })
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>

View File

@@ -1,9 +1,9 @@
<template> <template>
<view> <view>
<view <view
v-if="!hid" v-if="!state.hid"
class="flex-row-center" class="flex-row-center"
:style="{ top: scHight }" :style="{ top: state.scHight }"
style="width: 750rpx; position: fixed; z-index: 100; left: 0" style="width: 750rpx; position: fixed; z-index: 100; left: 0"
> >
<view <view
@@ -14,35 +14,35 @@
class="flex" class="flex"
style="width: 100%" style="width: 100%"
animation="false" animation="false"
:style="{ height: originalHeight }" :style="{ height: state.originalHeight }"
> >
<movable-view <movable-view
scale-value="1" scale-value="1"
animation="false" animation="false"
damping="5000" damping="5000"
:x="moveX" :x="state.moveX"
:style="{ :style="{
height: sliderHeight, height: state.sliderHeight,
width: sliderWidth, width: state.sliderWidth,
'z-index': 101, 'z-index': 101,
}" }"
direction="horizontal" direction="horizontal"
> >
<image <image
:src="imgbk" :src="state.imgbk"
class="image" class="image"
mode="aspectFit" mode="aspectFit"
:style="{ :style="{
height: sliderHeight, height: state.sliderHeight,
width: sliderWidth, width: state.sliderWidth,
'margin-top': imgbKH, 'margin-top': state.imgbKH,
}" }"
></image> ></image>
</movable-view> </movable-view>
<image <image
:src="img" :src="state.img"
mode="aspectFit" mode="aspectFit"
:style="{ height: originalHeight, width: originalWidth }" :style="{ height: state.originalHeight, width: state.originalWidth }"
style="border-radius: 10rpx" style="border-radius: 10rpx"
></image> ></image>
</movable-area> </movable-area>
@@ -61,7 +61,7 @@
scale-value="1" scale-value="1"
animation="false" animation="false"
damping="50" damping="50"
:x="movePv" :x="state.movePv"
class="flex-row-center" class="flex-row-center"
style=" style="
border-radius: 50%; border-radius: 50%;
@@ -78,14 +78,14 @@
<u-icon <u-icon
:color="mainColor" :color="mainColor"
size="40" size="40"
v-if="endLoad" v-if="state.endLoad"
name="arrow-right" name="arrow-right"
></u-icon> ></u-icon>
<u-icon :color="mainColor" size="40" v-else name="reload"></u-icon> <u-icon :color="mainColor" size="40" v-else name="reload"></u-icon>
</movable-view> </movable-view>
<text style="padding-left: 140rpx" :style="{ color: col }">{{ <text style="padding-left: 140rpx" :style="{ color: state.col }">{{
hasImg state.hasImg
}}</text> }}</text>
</movable-area> </movable-area>
<view class="flex-row-around padding-top" style="width: 100%"> <view class="flex-row-around padding-top" style="width: 100%">
@@ -106,173 +106,178 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import api from "@/config/api.js"; import { reactive, computed } from 'vue'
import storage from "@/utils/storage.js"; import { useStore } from '@/store'
import uuid from "@/utils/uuid.modified.js"; import api from '@/config/api.js'
const phone = uni.getSystemInfoSync(); import storage from '@/utils/storage.js'
const l = phone.screenWidth / 750; import uuid from '@/utils/uuid.modified.js'
export default {
name: "verification", const emit = defineEmits(['send'])
created() { const props = withDefaults(defineProps<{
// 可自行调整 height?: string
this.scHight = phone.screenHeight / 2 - 200 + "px"; width?: string
this.getCode(); left?: string
}, top?: string
props: { business?: string
height: { }>(), {
type: String, height: '80rpx',
default: "80rpx", width: '350rpx',
}, left: '180rpx',
width: { top: '30rpx',
type: String, business: 'LOGIN'
default: "350rpx", })
},
left: { const store = useStore()
type: String, const phone = uni.getSystemInfoSync()
default: "180rpx", const l = phone.screenWidth / 750
},
top: { const mainColor = computed(() => store.getters.mainColor)
type: String, const state = reactive({
default: "30rpx",
},
business: {
type: String,
default: "LOGIN",
},
},
data() {
return {
mainColor: this.$mainColor,
flage: false, flage: false,
key: "", //key key: '', // key
vsrtx: "点击进行验证", //按钮提示语 vsrtx: '点击进行验证', // 按钮提示语
vsr: false, // vsr: false,
hid: true, hid: true,
col: "#838383", col: '#838383',
movePv: 0, movePv: 0,
hasImg: "拖动滑块已完成拼图", hasImg: '拖动滑块已完成拼图',
spcode: "", spcode: '',
tl: 0, tl: 0,
moveCode: 0, moveCode: 0,
// X轴移动距离 // X轴移动距离
moveX: 0, moveX: 0,
// 模版高度 // 模版高度
originalHeight: "", originalHeight: '',
// 模版宽度 // 模版宽度
originalWidth: "", originalWidth: '',
// 拼图高度 // 拼图高度
sliderHeight: "", sliderHeight: '',
// 平涂宽度 // 平涂宽度
sliderWidth: "", sliderWidth: '',
scHight: 0, scHight: 0,
// 原图 // 原图
img: "", img: '',
// 拼图 // 拼图
imgbk: "", imgbk: '',
endLoad: true, endLoad: true,
imgbKH: "", imgbKH: ''
}; })
},
methods: { // 可自行调整
show() { state.scHight = phone.screenHeight / 2 - 200 + 'px'
this.hid = false; getCode()
},
hide() { function show() {
if (!this.vsr) { state.hid = false
// vsr判断是否验证成功成功隐藏验证框
this.hid = !this.hid;
} }
},
error() { function hide() {
this.vsr = false; if (!state.vsr) {
this.hid = false; // vsr判断是否验证成功成功隐藏验证框
this.moveX = 0; state.hid = !state.hid
this.moveCode = 0; }
}, }
function error() {
state.vsr = false
state.hid = false
state.moveX = 0
state.moveCode = 0
}
// 获取验证图片 // 获取验证图片
getCode() { function getCode() {
this.col = "#b3afae"; state.col = '#b3afae'
this.hasImg = "图片加载中..."; state.hasImg = '图片加载中...'
if (!storage.getUuid()) { if (!storage.getUuid()) {
storage.setUuid(uuid.v1()); storage.setUuid(uuid.v1())
} }
uni.request({ uni.request({
url: api.common + "/common/slider/" + this.business, url: api.common + '/common/slider/' + props.business,
header: { header: {
uuid: storage.getUuid(), uuid: storage.getUuid()
}, },
success: (res) => { success: (res: any) => {
this.col = "#838383"; state.col = '#838383'
this.hasImg = "拖动滑块以完成拼图"; state.hasImg = '拖动滑块以完成拼图'
var data = res.data.result; const data = res.data.result
// base64的图片 // base64的图片
this.img = data.backImage; state.img = data.backImage
this.imgbk = data.slidingImage; state.imgbk = data.slidingImage
// 根据参数动态适应验证图片的高宽 // 根据参数动态适应验证图片的高宽
this.imgbKH = data.randomY * 1.8 + "rpx"; state.imgbKH = data.randomY * 1.8 + 'rpx'
this.originalHeight = data.originalHeight * 1.8 + "rpx"; state.originalHeight = data.originalHeight * 1.8 + 'rpx'
this.originalWidth = data.originalWidth * 1.8 + "rpx"; state.originalWidth = data.originalWidth * 1.8 + 'rpx'
this.sliderHeight = data.sliderHeight * 1.8 + "rpx"; state.sliderHeight = data.sliderHeight * 1.8 + 'rpx'
this.sliderWidth = data.sliderWidth * 1.8 + "rpx"; state.sliderWidth = data.sliderWidth * 1.8 + 'rpx'
// 适应比率,用来适应滑动距离 // 适应比率,用来适应滑动距离
this.tl = 1 / (1.8 * l); state.tl = 1 / (1.8 * l)
// 无用信息 // 无用信息
this.spcode = data.capcode; state.spcode = data.capcode
// 验证令牌 // 验证令牌
this.key = data.key; state.key = data.key
this.$store.state.verificationKey = data.key; store.state.verificationKey = data.key
}, }
}); })
}, }
end(e) {
this.endLoad = false; function end() {
state.endLoad = false
// 验证拼图位置是否正确 // 验证拼图位置是否正确
uni.request({ uni.request({
method: "POST", method: 'POST',
url: url:
api.common + api.common +
"/common/slider/" + '/common/slider/' +
this.business + props.business +
"?xPos=" + '?xPos=' +
parseInt(this.moveCode * this.tl), parseInt(String(state.moveCode * state.tl)),
header: { header: {
uuid: storage.getUuid(), uuid: storage.getUuid()
}, },
success: (res) => { success: (res: any) => {
this.endLoad = true; state.endLoad = true
res.data.result == false if (res.data.result == false) {
? (res.data.result = false) res.data.result = false
: (res.data.result = true); } else {
res.data.result = true
}
if (res.data && res.data.result) { if (res.data && res.data.result) {
// 验证成功后把key发送出去,后端会把验证信息存在缓存里 // 验证成功后把key发送出去,后端会把验证信息存在缓存里
this.$emit("send", this.key); emit('send', state.key)
this.hide(); hide()
this.vsr = true; state.vsr = true
this.vsrtx = "已通过验证"; state.vsrtx = '已通过验证'
} else { } else {
this.getCode(); // 让滑块回到起始位置 getCode() // 让滑块回到起始位置
if (this.movePv == 1) { if (state.movePv == 1) {
this.movePv = 0; state.movePv = 0
} else { } else {
this.movePv = 1; state.movePv = 1
} }
} }
}, },
fail: (res) => { fail: () => {
this.$msg("连接服务器失败"); uni.showToast({ title: '连接服务器失败', icon: 'none' })
}, }
}); })
}, }
// 绑定拼图位置 // 绑定拼图位置
moveChange(e) { function moveChange(e: any) {
this.moveX = e.detail.x; state.moveX = e.detail.x
this.moveCode = e.detail.x; state.moveCode = e.detail.x
}, }
},
}; defineExpose({
show,
hide,
error,
getCode,
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -10,7 +10,7 @@
:password="isPassword" :password="isPassword"
:type="inputType" :type="inputType"
:maxlength="size" :maxlength="size"
@input="input" @input="handleInput"
@focus="inputFocus" @focus="inputFocus"
@blur="inputBlur" @blur="inputBlur"
/> />
@@ -37,7 +37,7 @@
</view> </view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
/** /**
* @description 输入验证码组件 * @description 输入验证码组件
* @property {string} type = [box|middle|bottom] - 显示类型 默认box -eg:bottom * @property {string} type = [box|middle|bottom] - 显示类型 默认box -eg:bottom
@@ -50,175 +50,155 @@
* @property {string} boxActiveColor - 光标聚焦到的框的颜色 默认:#000000 * @property {string} boxActiveColor - 光标聚焦到的框的颜色 默认:#000000
* @event {Function(data)} confirm - 输入完成 * @event {Function(data)} confirm - 输入完成
*/ */
export default { import { ref, watch, onMounted, nextTick, getCurrentInstance } from 'vue'
name: 'xt-verify-code',
emits: ['update:modelValue', 'input', 'confirm'], const emit = defineEmits(['update:modelValue', 'input', 'confirm'])
props: { const props = withDefaults(defineProps<{
modelValue: { modelValue?: string
type: String, value?: string
default: () => '' type?: string
}, inputType?: string
value: { size?: number
type: String, isFocus?: boolean
default: () => '' isPassword?: boolean
}, cursorColor?: string
type: { boxNormalColor?: string
type: String, boxActiveColor?: string
default: () => 'box' }>(), {
}, modelValue: '',
inputType: { value: '',
type: String, type: 'box',
default: () => 'number' inputType: 'number',
}, size: 6,
size: { isFocus: true,
type: Number, isPassword: false,
default: () => 6 cursorColor: '#cccccc',
}, boxNormalColor: '#cccccc',
isFocus: { boxActiveColor: '#000000'
type: Boolean, })
default: () => true
}, const instance = getCurrentInstance()
isPassword: { const codeInput = ref<any>(null)
type: Boolean, const focused = ref(false)
default: () => false const cursorVisible = ref(false)
}, const cursorHeight = ref(35)
cursorColor: { const code = ref('') // 输入的验证码
type: String, const codeCursorLeft = ref<number[]>([]) // 向左移动的距离数组
default: () => '#cccccc'
}, // 初始化
boxNormalColor: { watch([() => props.modelValue, () => props.value], ([modelVal, val]) => {
type: String, code.value = modelVal || val || ''
default: () => '#cccccc' }, { immediate: true })
},
boxActiveColor: { onMounted(() => {
type: String, focused.value = props.isFocus
default: () => '#000000' cursorVisible.value = props.isFocus
init()
if (props.isFocus) {
nextTick(() => {
focusInput()
})
} }
}, })
data() {
return { function focusInput() {
focused: false, focused.value = false
cursorVisible: false, nextTick(() => {
cursorHeight: 35, focused.value = true
code: '', // 输入的验证码
codeCursorLeft: [] // 向左移动的距离数组
};
},
created() {
this.code = this.modelValue || this.value || '';
this.focused = this.isFocus;
this.cursorVisible = this.isFocus;
},
mounted() {
this.init();
if (this.isFocus) {
this.$nextTick(() => {
this.focusInput();
});
}
},
methods: {
focusInput() {
this.focused = false;
this.$nextTick(() => {
this.focused = true;
// #ifdef H5 // #ifdef H5
const inputEl = this.$refs.codeInput; const inputEl = codeInput.value
if (inputEl && typeof inputEl.focus === 'function') { if (inputEl && typeof inputEl.focus === 'function') {
inputEl.focus(); inputEl.focus()
} }
// #endif // #endif
}); })
}, }
/** /**
* @description 初始化 * @description 初始化
*/ */
init() { function init() {
this.getCodeCursorLeft(); getCodeCursorLeft()
this.setCursorHeight(); setCursorHeight()
}, }
/** /**
* @description 获取元素节点 * @description 获取元素节点
* @param {string} elm - 节点的id、class 相当于 document.querySelect的参数 -eg: #id * @param {string} elm - 节点的id、class 相当于 document.querySelect的参数 -eg: #id
* @param {string} type = [single|array] - 单个元素获取多个元素 默认是单个元素 * @param {string} type = [single|array] - 单个元素获取多个元素 默认是单个元素
* @param {Function} callback - 回调函数 * @param {Function} callback - 回调函数
*/ */
getElement(elm, type = 'single', callback) { function getElement(elm: string, type: string = 'single', callback: Function) {
uni uni
.createSelectorQuery() .createSelectorQuery()
.in(this) .in(instance?.proxy)
[type === 'array' ? 'selectAll' : 'select'](elm) [type === 'array' ? 'selectAll' : 'select'](elm)
.boundingClientRect() .boundingClientRect()
.exec(data => { .exec((data: any) => {
callback(data[0]); callback(data[0])
}); })
}, }
/** /**
* @description 计算光标的高度 * @description 计算光标的高度
*/ */
setCursorHeight() { function setCursorHeight() {
this.getElement('.xt__box', 'single', boxElm => { getElement('.xt__box', 'single', (boxElm: any) => {
this.cursorHeight = boxElm.height * 0.6; cursorHeight.value = boxElm.height * 0.6
}); })
}, }
/** /**
* @description 获取光标在每一个box的left位置 * @description 获取光标在每一个box的left位置
*/ */
getCodeCursorLeft() { function getCodeCursorLeft() {
// 获取父级框的位置信息 // 获取父级框的位置信息
this.getElement('#xt__input-ground', 'single', parentElm => { getElement('#xt__input-ground', 'single', (parentElm: any) => {
const parentLeft = parentElm.left; const parentLeft = parentElm.left
// 获取各个box信息 // 获取各个box信息
this.getElement('.xt__box', 'array', elms => { getElement('.xt__box', 'array', (elms: any) => {
this.codeCursorLeft = []; codeCursorLeft.value = []
elms.forEach(elm => { elms.forEach((elm: any) => {
this.codeCursorLeft.push(elm.left - parentLeft + elm.width / 2); codeCursorLeft.value.push(elm.left - parentLeft + elm.width / 2)
}); })
}); })
}); })
}, }
// 输入框输入变化的回调 // 输入框输入变化的回调
input(e) { function handleInput(e: any) {
const value = e.detail.value; const value = e.detail.value
this.code = value; code.value = value
this.cursorVisible = value.length !== this.size; cursorVisible.value = value.length !== props.size
this.$emit('update:modelValue', value); emit('update:modelValue', value)
this.$emit('input', value); emit('input', value)
this.inputSuccess(value); inputSuccess(value)
}, }
// 输入完成回调 // 输入完成回调
inputSuccess(value) { function inputSuccess(value: string) {
if (value.length === this.size) { if (value.length === props.size) {
this.$emit('confirm', value); emit('confirm', value)
} }
}, }
// 输入聚焦 // 输入聚焦
inputFocus() { function inputFocus() {
this.cursorVisible = this.code.length !== this.size; cursorVisible.value = code.value.length !== props.size
}, }
// 输入失去焦点 // 输入失去焦点
inputBlur() { function inputBlur() {
this.cursorVisible = false; cursorVisible.value = false
}, }
codeFormat(val, isPassword) {
let value = ''; function codeFormat(val: string | undefined, isPassword: boolean): string {
let value = ''
if (val) { if (val) {
value = isPassword ? '*' : val; value = isPassword ? '*' : val
} }
return value; return value
} }
},
watch: {
modelValue(val) {
this.code = val || '';
},
value(val) {
this.code = val || '';
}
}
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.xt__verify-code { .xt__verify-code {

View File

@@ -8,9 +8,7 @@ const dev = {
common: "https://common-api.pickmall.cn", common: "https://common-api.pickmall.cn",
buyer: "https://buyer-api.pickmall.cn", buyer: "https://buyer-api.pickmall.cn",
mqtt: "wss://lilishop-mqtt-pull.dllll.xyz/mqtt", mqtt: "wss://lilishop-mqtt-pull.dllll.xyz/mqtt",
common: "http://192.168.31.244:8890",
buyer: "http://192.168.31.244:8888",
im: "http://192.168.0.113:8885",
}; };
// 生产环境 // 生产环境
const prod = { const prod = {

View File

@@ -38,6 +38,12 @@ export function createApp() {
config: { config: {
loadFontOnce: true, loadFontOnce: true,
}, },
props: {
form: {
labelWidth: '180rpx',
labelPosition: 'left',
},
},
}) })
app.config.globalProperties.$store = store app.config.globalProperties.$store = store

View File

@@ -580,6 +580,7 @@
} }
}, },
// #ifndef MP-WEIXIN
{ {
"path": "live/room", "path": "live/room",
"style": { "style": {
@@ -588,6 +589,7 @@
"disableScroll": true "disableScroll": true
} }
}, },
// #endif
{ {
"path": "joinGroup", "path": "joinGroup",
"style": { "style": {
@@ -599,14 +601,17 @@
"bounce": "none" "bounce": "none"
} }
} }
},{ },
// #ifndef MP-WEIXIN
{
"path": "lives", "path": "lives",
"style": { "style": {
"navigationStyle": "custom", "navigationStyle": "custom",
"navigationBarTextStyle": "black" "navigationBarTextStyle": "black"
} }
},{ },
// #endif
{
"path": "bargain/list", "path": "bargain/list",
"style": { "style": {
"navigationStyle": "custom", "navigationStyle": "custom",
@@ -699,6 +704,17 @@
} }
} }
}, },
{
"path": "payment/error",
"style": {
"navigationBarTitleText": "支付失败",
"navigationStyle": "custom",
"navigationBarTextStyle": "black",
"app-plus": {
"popGesture": "none"
}
}
},
{ {
"path": "payment/shareOrderGoods", "path": "payment/shareOrderGoods",
"style": { "style": {

View File

@@ -1,302 +1,262 @@
<template> <template>
<view class="coupon-center"> <view class="coupon-center">
<div class="swiper-box"> <view class="coupon-list">
<div class="swiper-item">
<div class="scroll-v" enableBackToTop="true" scroll-y>
<u-empty mode="coupon" style='margin-top: 20%;' text="没有优惠券了" v-if="whetherEmpty"></u-empty> <u-empty mode="coupon" style='margin-top: 20%;' text="没有优惠券了" v-if="whetherEmpty"></u-empty>
<view v-else class="coupon-item" v-for="(item, index) in couponList" :key="index"> <view v-else class="coupon-card" v-for="(item, index) in couponList" :key="index">
<view class="left"> <view class="coupon-card-left">
<view class="wave-line"> <text class="coupon-price-symbol">¥</text>
<view class="wave" v-for="(item, index) in 12" :key="index"></view> <text class="coupon-price-value">{{ item.couponType == 'DISCOUNT' ? item.couponDiscount + '折' : unitPrice(item.price) }}</text>
</view> </view>
<view class="message"> <view class="coupon-divider"></view>
<view> <view class="coupon-card-right">
<!--判断当前优惠券类型 couponType PRICE || DISCOUNT --> <view class="coupon-info">
<span v-if="item.couponType == 'DISCOUNT'">{{ item.couponDiscount }}</span> <text class="coupon-card-name">{{ item.storeName == 'platform' ? '全平台' : item.storeName + '店铺' }}使用</text>
<span v-else>{{ item.price }}</span> <text class="coupon-card-desc">{{unitPrice(item.consumeThreshold) }}元可用</text>
<text class="coupon-card-time" v-if="item.endTime">有效期至:{{ item.endTime.split(" ")[0] }}</text>
</view> </view>
<view>{{unitPrice(item.consumeThreshold) }}元可用</view> <view class="coupon-claim-btn" @click="receive(item)">
</view> 领取
<view class="circle circle-top"></view>
<view class="circle circle-bottom"></view>
</view>
<view class="right">
<view>
<!-- 根据scopeType 判断是否是 平台品类或店铺 -->
<view class="coupon-title wes-3" v-if="item.scopeType">
<span v-if="item.scopeType == 'ALL' && item.storeId == '0'">全平台</span>
<span v-if="item.scopeType == 'PORTION_GOODS_CATEGORY'">仅限品类</span>
<view v-else>{{ item.storeName == 'platform' ? '全平台' :item.storeName+'店铺' }}使用
</view> </view>
</view> </view>
<view v-if="item.endTime">有效期至:{{ item.endTime.split(" ")[0] }}</view>
</view>
<view class="receive" @click="receive(item)">
<text>点击</text><br />
<text>领取</text>
</view>
<view class="bg-quan"> </view>
</view> </view>
</view> </view>
</div>
</div>
</div>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { receiveCoupons } from '@/api/members.js'
import { getAllCoupons } from '@/api/promotions.js'
import { useStore } from '@/store'
import { unitPrice } from '@/utils/filters.js'
import { import {
receiveCoupons onLoad,
} from "@/api/members.js"; onNavigationBarButtonTap,
import { onPullDownRefresh,
getAllCoupons onReachBottom,
} from "@/api/promotions.js"; } from '@dcloudio/uni-app'
export default { import { getCurrentInstance, ref } from 'vue'
data() {
return { const store = useStore()
loadStatus: "more", //下拉状态 const { proxy } = getCurrentInstance()!
whetherEmpty: false, //是否为空
couponList: [], // 优惠券列表 const loadStatus = ref('more')
params: { const whetherEmpty = ref(false)
const couponList = ref<any[]>([])
const params = ref({
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
}, })
storeId: "", //店铺 id, const storeId = ref('')
couponData: "" const couponData = ref<any>(null)
};
}, onLoad((option) => {
onLoad(option) { storeId.value = option.storeId || ''
this.storeId = option.storeId; getCoupon()
this.getCoupon(); })
},
onReachBottom() { onReachBottom(() => {
loadMore()
})
onPullDownRefresh(() => {
params.value.pageNumber = 1
couponList.value = []
getCoupon()
})
onNavigationBarButtonTap(() => {
uni.navigateTo({
url: '/pages/cart/coupon/couponIntro',
})
})
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
}
function getCoupon() {
uni.showLoading({ title: '加载中' })
const submitData = storeId.value
? { ...params.value, storeId: storeId.value }
: { ...params.value }
this.loadMore()
},
onPullDownRefresh() {
//下拉刷新
this.params.pageNumber = 1;
this.couponList = [];
this.getCoupon();
},
methods: {
/**
* 获取当前优惠券
*/
getCoupon() {
uni.showLoading({
title: "加载中",
});
let submitData = {
...this.params
};
// 判断当前是否有店铺
this.storeId ? (submitData = {
...this.params,
storeId: this.storeId
}) : "",
getAllCoupons(submitData) getAllCoupons(submitData)
.then((res) => { .then((res) => {
if (this.$store.state.isShowToast){ uni.hideLoading() }; hideLoadingIfNeeded()
uni.stopPullDownRefresh(); uni.stopPullDownRefresh()
if (res.data.code == 200) { if (res.data.code == 200) {
// 如果请求成功,展示数据并进行展示 couponData.value = res.data.result
this.couponData = res.data.result if (couponData.value.total == 0) {
if (this.couponData.total == 0) { whetherEmpty.value = true
// 当本次请求数据为空展示空信息
this.whetherEmpty = true;
} else { } else {
this.couponList.push(...this.couponData.records); couponList.value.push(...couponData.value.records)
this.loadStatus = "noMore"; loadStatus.value = 'noMore'
} }
} }
}) })
.catch((err) => { .catch(() => {
if (this.$store.state.isShowToast){ uni.hideLoading() }; hideLoadingIfNeeded()
}); })
}, }
/**
* 领取优惠券 function receive(val: any) {
*/ proxy.$u.throttle(() => {
receive(val) { fetchCoupon(val)
this.$u.throttle(()=>{
this.fetchCoupon(val)
}, 1500) }, 1500)
}
}, function fetchCoupon(val: any) {
fetchCoupon(val){
receiveCoupons(val.id).then((res) => { receiveCoupons(val.id).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
uni.showToast({ uni.showToast({ title: '领取成功', icon: 'none' })
title: "领取成功",
icon: "none",
});
} else { } else {
uni.showToast({ uni.showToast({ title: res.data.message, icon: 'none' })
title: res.data.message, }
icon: "none", })
});
} }
});
},
/** function loadMore() {
* 加载更多 if (couponData.value?.total > params.value.pageNumber * params.value.pageSize) {
*/ params.value.pageNumber++
loadMore() { getCoupon()
if (this.couponData.total > this.params.pageNumber * this.params.pageSize) { }
this.params.pageNumber++;
this.getCoupon();
} }
},
},
onNavigationBarButtonTap(e) {
uni.navigateTo({
url: "/pages/cart/coupon/couponIntro",
});
},
};
</script> </script>
<style>
page {
height: 100%;
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
.coupon-center { .coupon-center {
height: 100%; min-height: 100vh;
background: #f7f8fa;
}
.swiper-box { .coupon-list {
.coupon-item { padding: 24rpx;
}
.coupon-card {
display: flex; display: flex;
align-items: center; align-items: stretch;
height: 220rpx; background: #fff;
margin: 20rpx; border-radius: 24rpx;
margin-bottom: 24rpx;
.left {
height: 100%;
width: 260rpx;
background-color: $light-color;
position: relative; position: relative;
box-shadow: none;
.message { border: 1rpx solid #f0f1f5;
color: $font-color-white;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin-top: 40rpx;
view:nth-child(1) {
font-weight: bold;
font-size: 60rpx;
}
view:nth-child(2) {
font-size: $font-sm;
}
}
.wave-line {
height: 220rpx;
width: 8rpx;
position: absolute;
top: 0;
left: 0;
background-color: $light-color;
overflow: hidden; overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease;
.wave { &:active {
width: 8rpx; transform: scale(0.98);
height: 16rpx;
background-color: #ffffff;
border-radius: 0 16rpx 16rpx 0;
margin-top: 4rpx;
}
} }
.circle { &::before,
width: 40rpx; &::after {
height: 40rpx; content: "";
background-color: $bg-color;
position: absolute; position: absolute;
width: 32rpx;
height: 32rpx;
background: #f7f8fa;
border-radius: 50%; border-radius: 50%;
z-index: 111; left: 204rpx;
}
.circle-top {
top: -20rpx;
right: -20rpx;
}
.circle-bottom {
bottom: -20rpx;
right: -20rpx;
}
}
.right {
display: flex;
justify-content: space-between;
align-items: center;
width: 450rpx;
font-size: $font-sm;
height: 100%;
background-color: #ffffff;
overflow: hidden;
position: relative;
>view:nth-child(1) {
color: #666666;
margin-left: 20rpx;
display: flex;
height: 100%;
flex-direction: column;
justify-content: space-around;
>view:nth-child(1) {
color: #ff6262;
font-size: 30rpx;
}
}
.receive {
color: #ffffff;
background-color: $main-color;
border-radius: 50%;
width: 86rpx;
height: 86rpx;
text-align: center;
margin-right: 30rpx;
vertical-align: middle;
padding-top: 8rpx;
position: relative;
z-index: 2; z-index: 2;
box-shadow: inset 0 0 0 1rpx #eceef2;
} }
.bg-quan { &::before {
width: 244rpx; top: -16rpx;
height: 244rpx; }
border: 6rpx solid $main-color;
border-radius: 50%; &::after {
opacity: 0.1; bottom: -16rpx;
color: $main-color; }
text-align: center; }
padding-top: 30rpx;
font-size: 130rpx; .coupon-card-left {
width: 220rpx;
min-height: 180rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: #ff3b30;
position: relative;
background: linear-gradient(135deg, #fff5f5 0%, #ffecec 100%);
}
.coupon-price-symbol {
font-size: 32rpx;
font-weight: 700;
margin-right: 4rpx;
}
.coupon-price-value {
font-size: 56rpx;
font-weight: 900;
line-height: 1;
letter-spacing: -1rpx;
}
.coupon-divider {
position: absolute; position: absolute;
right: -54rpx; left: 220rpx;
bottom: -60rpx; top: 24rpx;
} bottom: 24rpx;
} width: 0;
} border-left: 2rpx dashed #eceef2;
}
} }
.coupon-title { .coupon-card-right {
width: 260rpx; flex: 1;
padding: 32rpx 32rpx 32rpx 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
background: #fff;
}
.coupon-info {
display: flex;
flex-direction: column;
gap: 12rpx;
flex: 1;
min-width: 0;
}
.coupon-card-name {
font-size: 30rpx;
color: #111;
font-weight: 700;
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.coupon-card-desc {
font-size: 24rpx;
color: #8a8f99;
font-weight: 500;
}
.coupon-card-time {
font-size: 22rpx;
color: #b0b3bf;
}
.coupon-claim-btn {
flex-shrink: 0;
padding: 16rpx 32rpx;
border-radius: 40rpx;
font-size: 26rpx;
font-weight: 700;
color: #fff;
background: linear-gradient(135deg, #ff6b35, #ff4b2b);
box-shadow: 0 8rpx 16rpx rgba(255, 75, 43, 0.25);
&:active {
opacity: 0.9;
}
} }
</style> </style>

View File

@@ -6,9 +6,7 @@
<view class="price" v-if="coupon.couponType == 'PRICE'"><text></text>{{ unitPrice(coupon.price) }}</view> <view class="price" v-if="coupon.couponType == 'PRICE'"><text></text>{{ unitPrice(coupon.price) }}</view>
<view class="price" v-if="coupon.couponType == 'DISCOUNT'">{{ coupon.discount }}</view> <view class="price" v-if="coupon.couponType == 'DISCOUNT'">{{ coupon.discount }}</view>
<view class="text">{{ coupon.consumeThreshold }}元可用</view> <view class="text">{{ coupon.consumeThreshold }}元可用</view>
<view class="bg-quan"> <view class="bg-quan"></view>
</view>
<view class="jiao-1" :class="{ 'used-color': coupon.used_status != 0 }"> <view class="jiao-1" :class="{ 'used-color': coupon.used_status != 0 }">
<text class="text-1">{{ coupon.used_status == 0 ? '新到' : coupon.used_status_text }}</text> <text class="text-1">{{ coupon.used_status == 0 ? '新到' : coupon.used_status_text }}</text>
</view> </view>
@@ -16,38 +14,34 @@
<view class="bottom-view"> <view class="bottom-view">
<view class="text"> 使用范围{{ <view class="text"> 使用范围{{
coupon.scopeType == 'ALL' && coupon.storeId == '0' coupon.scopeType == 'ALL' && coupon.storeId == '0'
? "全平台" ? '全平台'
: coupon.scopeType == "PORTION_GOODS" : coupon.scopeType == 'PORTION_GOODS'
? "部分商品" ? '部分商品'
: coupon.scopeType == "PORTION_GOODS_CATEGORY" : coupon.scopeType == 'PORTION_GOODS_CATEGORY'
? "部分分类商品" ? '部分分类商品'
: coupon.storeName == 'platform' ? '全平台' : coupon.storeName + '' : coupon.storeName == 'platform' ? '全平台' : coupon.storeName + ''
}}使用</view> }}使用</view>
<view class="text"> 有效期至{{ coupon.endTime }}</view> <view class="text"> 有效期至{{ coupon.endTime }}</view>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { import { ref } from 'vue'
data() { import { onLoad } from '@dcloudio/uni-app'
return { import { unitPrice } from '@/utils/filters.js'
coupon: {}, //优惠券数据
}; const coupon = ref<Record<string, any>>({})
},
onLoad(option) { onLoad((option) => {
this.coupon = JSON.parse(decodeURIComponent(option.item)); coupon.value = JSON.parse(decodeURIComponent(option.item))
}, })
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
page, page,
.content { .content {
// background: $main-color;
height: 100%; height: 100%;
} }
.body { .body {

View File

@@ -59,81 +59,59 @@
</view> </view>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { useCoupon } from "@/api/trade.js"; import { ref, computed, watch, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { useCoupon } from '@/api/trade.js'
import { unitPrice } from '@/utils/filters.js'
export default { const store = useStore()
data() {
return {
lightColor: this.$lightColor,
current: 0,
list: [
{
name: "可用优惠券",
},
{
name: "不可用优惠券",
},
],
couponsList: [], //优惠券集合
params: {
//传参
memberCouponStatus: "NEW", //优惠券状态
pageNumber: 1,
pageSize: 10,
scopeId: "", //商品skuid
storeId: "", //店铺id
totalPrice: "", //价格
},
routerVal: "", //上级传参
};
},
onLoad(options) {
this.routerVal = options;
},
watch: {
current(val) {
console.log(this.$store.state.cantUseCoupons);
val == 0
? (this.couponsList = this.$store.state.canUseCoupons)
: (this.couponsList = this.$store.state.cantUseCoupons);
},
},
mounted() { const lightColor = computed(() => store.getters.lightColor)
this.init(); const current = ref(0)
console.log(this.routerVal); const list = [
}, { name: '可用优惠券' },
{ name: '不可用优惠券' },
]
const couponsList = ref<any[]>([])
const routerVal = ref<Record<string, any>>({})
methods: { onLoad((options) => {
/** routerVal.value = options || {}
* 从vuex中拿取优惠券信息 })
*/
init() { watch(current, (val) => {
this.couponsList = this.$store.state.canUseCoupons; couponsList.value = val == 0
}, ? store.state.canUseCoupons
/** : store.state.cantUseCoupons
* 领取优惠券 })
*/
clickWay(coupon) { onMounted(() => {
init()
})
function init() {
couponsList.value = store.state.canUseCoupons
}
function clickWay(coupon: any) {
useCoupon({ useCoupon({
memberCouponId: coupon.id, memberCouponId: coupon.id,
used: !this.routerVal.selectedCoupon.includes(coupon.id), used: !routerVal.value.selectedCoupon.includes(coupon.id),
way: this.routerVal.way, way: routerVal.value.way,
}).then((res) => { }).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.navigateBack(); uni.navigateBack()
} else { } else {
uni.showToast({ uni.showToast({
title: res.data.message, title: res.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}
})
} }
});
},
},
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.desc { .desc {

View File

@@ -1,16 +1,15 @@
<template> <template>
<view class="b-content"> <view class="b-content">
<view class="navbar"> <view class="coupon-tabs">
<!-- 循环出头部tab栏 --> <u-tabs
<view :list="navList"
v-for="(item, index) in navList" keyName="text"
:key="index" :scrollable="false"
class="nav-item" :inactiveStyle="{ color: '#333' }"
@click="handleTabClick(index)" v-model:current="tabCurrentIndex"
><text :class="{ current: tabCurrentIndex === index }">{{ :lineColor="lightColor"
item.text :activeStyle="{ color: lightColor }"
}}</text></view ></u-tabs>
>
</view> </view>
<swiper <swiper
:current="tabCurrentIndex" :current="tabCurrentIndex"
@@ -28,45 +27,27 @@
scroll-y scroll-y
@scrolltolower="loadData" @scrolltolower="loadData"
> >
<!-- 空白页 -->
<u-empty <u-empty
mode="coupon" mode="coupon"
text="暂无优惠券了" text="暂无优惠券了"
v-if="navItem.whetherEmpty" v-if="navItem.whetherEmpty"
></u-empty> ></u-empty>
<!-- 数据 -->
<view <view
class="coupon-item" class="coupon-card"
:class="{ 'coupon-used': navIndex != 0 }" :class="{ 'coupon-used': navIndex != 0, 'coupon-expired': navIndex == 2 }"
v-for="(coupon, index) in navItem.dataList" v-for="(coupon, index) in navItem.dataList"
:key="index" :key="index"
> >
<view class="left"> <view class="coupon-card-left">
<view class="wave-line"> <text class="coupon-price-symbol" v-if="coupon.couponType != 'DISCOUNT'">¥</text>
<view <text class="coupon-price-value">{{ coupon.couponType == 'DISCOUNT' ? coupon.discount + '折' : unitPrice(coupon.price) }}</text>
class="wave"
v-for="(item, index) in 12"
:key="index"
></view>
</view> </view>
<view class="message"> <view class="coupon-divider"></view>
<view class="price" v-if="coupon.couponType == 'DISCOUNT'" <view class="coupon-card-right">
>{{ coupon.discount }}</view <view class="coupon-info">
> <text class="coupon-card-name">{{ coupon.title }}</text>
<view class="price" v-else>{{ coupon.price }}</view> <text class="coupon-card-desc">使用范围{{
<view class="sub-price"
>{{unitPrice(coupon.consumeThreshold) }}可用</view
>
</view>
<view class="circle circle-top"></view>
<view class="circle circle-bottom"></view>
</view>
<view class="right" v-if="coupon">
<view class="content">
<view class="title-1">{{ coupon.title }}</view>
<view class="title-2"
>使用范围{{
coupon.scopeType == "ALL" && coupon.storeId == "0" coupon.scopeType == "ALL" && coupon.storeId == "0"
? "全平台" ? "全平台"
: coupon.scopeType == "PORTION_GOODS" : coupon.scopeType == "PORTION_GOODS"
@@ -76,42 +57,18 @@
: coupon.storeName == "platform" : coupon.storeName == "platform"
? "全平台" ? "全平台"
: coupon.storeName + "" : coupon.storeName + ""
}}使用</view }}使用</text>
> <text class="coupon-card-time" v-if="coupon.endTime">{{ coupon.endTime }}</text>
<view v-if="coupon.endTime">{{ coupon.endTime }}</view>
<view @click="couponDetail(coupon)"
>详细说明
<u-icon
style="float: right; margin-top: 10rpx"
name="arrow-right"
></u-icon>
</view> </view>
<view class="coupon-status-btn" v-if="navIndex == 0" @click="useItNow(coupon)">
立即使用
</view> </view>
<view class="jiao-1" v-if="navIndex == 0"> <view class="coupon-status-btn disabled" v-else-if="navIndex == 1">
<text class="text-1">新到</text> 已使用
<text class="text-2" v-if="coupon.used_status == 1"
>将过期</text
>
</view> </view>
<image <view class="coupon-status-btn disabled" v-else>
class="no-icon" 已过期
v-if="navIndex == 1"
src="@/static/img/used.png"
></image>
<image
class="no-icon"
v-if="navIndex == 2"
src="@/static/img/overdue.png"
></image>
<view
class="receive"
v-if="navIndex == 0"
@click="useItNow(coupon)"
>
<text>立即</text><br />
<text>使用</text>
</view> </view>
<view class="bg-quan"> </view>
</view> </view>
</view> </view>
<uni-load-more :status="navItem.loadStatus"></uni-load-more> <uni-load-more :status="navItem.loadStatus"></uni-load-more>
@@ -121,21 +78,24 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getMemberCoupons } from "@/api/members.js"; import { getMemberCoupons } from '@/api/members.js'
import { useStore } from '@/store'
import { unitPrice } from '@/utils/filters.js'
import { onShow } from '@dcloudio/uni-app'
import { computed, ref, watch } from 'vue'
export default { const store = useStore()
data() {
return { const lightColor = computed(() => store.getters.lightColor)
tabCurrentIndex: 0, //tab栏下标默认为0 未使用 const tabCurrentIndex = ref(0)
navList: [ const navList = ref([
//每个tab存储的信息
{ {
text: "未使用", text: '未使用',
loadStatus: "more", loadStatus: 'more',
dataList: [], dataList: [] as any[],
params: { params: {
memberCouponStatus: "NEW", memberCouponStatus: 'NEW',
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
status: 1, status: 1,
@@ -143,11 +103,11 @@ export default {
whetherEmpty: false, whetherEmpty: false,
}, },
{ {
text: "已使用", text: '已使用',
loadStatus: "more", loadStatus: 'more',
dataList: [], dataList: [] as any[],
params: { params: {
memberCouponStatus: "USED", memberCouponStatus: 'USED',
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
status: 2, status: 2,
@@ -155,317 +115,279 @@ export default {
whetherEmpty: false, whetherEmpty: false,
}, },
{ {
text: "已过期", text: '已过期',
loadStatus: "more", loadStatus: 'more',
dataList: [], dataList: [] as any[],
params: { params: {
memberCouponStatus: "EXPIRE", memberCouponStatus: 'EXPIRE',
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
status: 3, status: 3,
}, },
whetherEmpty: false, whetherEmpty: false,
}, },
], ])
couponList: [], //优惠券列表
};
},
onShow() { onShow(() => {
this.navList[this.tabCurrentIndex].params.pageNumber = 1; navList.value[tabCurrentIndex.value].params.pageNumber = 1
this.navList[this.tabCurrentIndex].dataList = []; navList.value[tabCurrentIndex.value].dataList = []
this.getData(); getData()
}, })
watch: { watch(tabCurrentIndex, (val) => {
/** if (navList.value[val].dataList.length == 0) getData()
* 监听切换顶部tab栏实现刷新数据 })
*/
tabCurrentIndex(val) {
if (this.navList[val].dataList.length == 0) this.getData();
},
},
methods: {
/**
* 顶部tab点击
*/
handleTabClick(index) {
this.tabCurrentIndex = index;
},
/** function hideLoadingIfNeeded() {
* 读取优惠券 if (store.state.isShowToast) uni.hideLoading()
*/ }
getData() {
uni.showLoading({ function handleTabClick(index: number) {
title: "加载中", tabCurrentIndex.value = index
}); }
let index = this.tabCurrentIndex;
getMemberCoupons(this.navList[index].params).then((res) => { function getData() {
uni.stopPullDownRefresh(); uni.showLoading({ title: '加载中' })
const index = tabCurrentIndex.value
getMemberCoupons(navList.value[index].params).then((res) => {
uni.stopPullDownRefresh()
if (res.data.success) { if (res.data.success) {
let data = res.data.result.records; const data = res.data.result.records
if (data.length == 0) { if (data.length == 0) {
if (res.data.pageNumber == 1) { if (res.data.pageNumber == 1) {
this.navList[index].whetherEmpty = true; navList.value[index].whetherEmpty = true
} else { } else {
this.navList[index].loadStatus = "noMore"; navList.value[index].loadStatus = 'noMore'
} }
} else if (data.length < 10) { } else if (data.length < 10) {
this.navList[index].loadStatus = "noMore"; navList.value[index].loadStatus = 'noMore'
this.navList[index].dataList.push(...data); navList.value[index].dataList.push(...data)
} else { } else {
this.navList[index].dataList.push(...data); navList.value[index].dataList.push(...data)
} }
} }
if (this.$store.state.isShowToast){ uni.hideLoading() }; hideLoadingIfNeeded()
}); })
},
/**
* 切换tab
*/
changeTab(e) {
this.tabCurrentIndex = e.target.current;
},
/**
* 加载数据
*/
loadData() {
let index = this.tabCurrentIndex;
if (this.navList[index].loadStatus != "noMore") {
this.navList[index].params.pageNumber++;
this.getData();
} }
},
/** function changeTab(e: any) {
* 立即使用优惠券 tabCurrentIndex.value = e.detail.current
*/ }
useItNow(item) {
function loadData() {
const index = tabCurrentIndex.value
if (navList.value[index].loadStatus != 'noMore') {
navList.value[index].params.pageNumber++
getData()
}
}
function useItNow(item: any) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/navigation/search/searchPage?promotionsId=${item.couponId}&promotionType=COUPON`, url: `/pages/navigation/search/searchPage?promotionsId=${item.couponId}&promotionType=COUPON`,
}); })
}, }
/** function couponDetail(item: any) {
* 优惠券详情
*/
couponDetail(item) {
uni.navigateTo({ uni.navigateTo({
url: url: '/pages/cart/coupon/couponDetail?item=' + encodeURIComponent(JSON.stringify(item)),
"/pages/cart/coupon/couponDetail?item=" + })
encodeURIComponent(JSON.stringify(item)), }
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
page {
height: 100%;
}
$item-color: #fff;
.b-content { .b-content {
background: $page-color-base; background: #f7f8fa;
height: 100%; min-height: 100vh;
}
.coupon-tabs {
background: #fff;
height: 88rpx;
box-shadow: 0 1rpx 8rpx rgba(0, 0, 0, 0.04);
position: relative;
z-index: 2;
}
:deep(.u-tabs),
:deep(.u-tabs__wrapper),
:deep(.u-tabs__wrapper__scroll-view-wrapper),
:deep(.u-tabs__wrapper__scroll-view),
:deep(.u-tabs__wrapper__nav) {
background: #fff;
height: 88rpx;
}
:deep(.u-tabs__wrapper__nav__item) {
min-height: 88rpx;
}
:deep(.u-tabs__wrapper__nav__item__text) {
color: #333;
font-size: 28rpx;
} }
.swiper-box { .swiper-box {
height: calc(100vh - 40px); height: calc(100vh - 88rpx - var(--status-bar-height));
} }
.list-scroll-content { .list-scroll-content {
height: 100%; height: 100%;
width: 100%; width: 100%;
padding: 24rpx;
box-sizing: border-box;
}
.coupon-item { .coupon-card {
display: flex; display: flex;
align-items: center; align-items: stretch;
height: 220rpx;
margin: 20rpx;
.left {
height: 100%;
width: 260rpx;
background-color: $light-color;
position: relative;
.message {
color: $font-color-white;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin-top: 40rpx;
view:nth-child(1) {
font-weight: bold;
font-size: 60rpx;
}
view:nth-child(2) {
font-size: $font-sm;
}
}
.wave-line {
height: 220rpx;
width: 8rpx;
position: absolute;
top: 0;
left: 0;
background-color: $light-color;
overflow: hidden;
.wave {
width: 8rpx;
height: 16rpx;
background-color: #ffffff;
border-radius: 0 16rpx 16rpx 0;
margin-top: 4rpx;
}
}
.circle {
width: 40rpx;
height: 40rpx;
background-color: $bg-color;
position: absolute;
border-radius: 50%;
z-index: 111;
}
.circle-top {
top: -20rpx;
right: -20rpx;
}
.circle-bottom {
bottom: -20rpx;
right: -20rpx;
}
}
.right {
display: flex;
justify-content: space-between;
align-items: center;
width: 450rpx;
font-size: $font-sm;
height: 100%;
background-color: #ffffff;
overflow: hidden;
position: relative;
.content {
color: #666666;
margin-left: 20rpx;
line-height: 2em;
> view:nth-child(1) {
color: #ff6262;
font-size: 30rpx;
}
.title-1,
.title-2,
.title-3 {
font-size: 25rpx;
}
}
.receive {
color: #ffffff;
background-color: $main-color;
border-radius: 50%;
width: 86rpx;
height: 86rpx;
text-align: center;
margin-right: 48rpx;
vertical-align: middle;
padding-top: 8rpx;
position: relative;
z-index: 2;
}
.jiao-1 {
background-color: #ffc71c;
width: 400rpx;
transform: rotate(45deg);
text-align: center;
position: absolute;
color: #ffffff;
right: -130rpx;
top: 0;
.text-1 {
margin-left: 68rpx;
font-size: 28rpx;
}
.text-2 {
margin-left: 68rpx;
font-size: 28rpx;
}
}
.no-icon {
border-radius: 50%;
width: 86rpx;
height: 86rpx;
margin-right: 48rpx;
position: relative;
z-index: 2;
}
.bg-quan {
width: 244rpx;
height: 244rpx;
border: 6rpx solid $main-color;
border-radius: 50%;
opacity: 0.1;
color: $main-color;
text-align: center;
padding-top: 30rpx;
font-size: 130rpx;
position: absolute;
right: -54rpx;
bottom: -60rpx;
}
}
}
}
.navbar {
display: flex;
height: 80rpx;
padding: 0 5px;
background: #fff; background: #fff;
color: $light-color; border-radius: 24rpx;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.06); margin-bottom: 24rpx;
position: relative; position: relative;
z-index: 10; box-shadow: none;
border: 1rpx solid #f0f1f5;
overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease;
.nav-item { &:active {
flex: 1; transform: scale(0.98);
height: 100%;
font-size: 26rpx;
color: $light-color;
position: relative;
text-align: center;
text {
line-height: 80rpx;
} }
.current {
font-weight: bold; &::before,
font-size: 28rpx; &::after {
&:after {
content: ""; content: "";
position: absolute; position: absolute;
bottom: 10rpx; width: 32rpx;
left: 108rpx; height: 32rpx;
width: 30rpx; background: #f7f8fa;
border-bottom: 2px solid $light-color; border-radius: 50%;
left: 204rpx;
z-index: 2;
box-shadow: inset 0 0 0 1rpx #eceef2;
}
&::before {
top: -16rpx;
}
&::after {
bottom: -16rpx;
}
&.coupon-used {
.coupon-card-left {
background: linear-gradient(135deg, #f5f5f5 0%, #eeeeee 100%);
color: #999;
}
.coupon-status-btn {
background: #ccc;
box-shadow: none;
} }
} }
&.coupon-expired {
.coupon-card-left {
background: linear-gradient(135deg, #f5f5f5 0%, #eeeeee 100%);
color: #999;
}
.coupon-status-btn {
background: #ccc;
box-shadow: none;
}
}
}
.coupon-card-left {
width: 220rpx;
min-height: 180rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: #ff3b30;
position: relative;
background: linear-gradient(135deg, #fff5f5 0%, #ffecec 100%);
}
.coupon-price-symbol {
font-size: 32rpx;
font-weight: 700;
margin-right: 4rpx;
}
.coupon-price-value {
font-size: 56rpx;
font-weight: 900;
line-height: 1;
letter-spacing: -1rpx;
}
.coupon-divider {
position: absolute;
left: 220rpx;
top: 24rpx;
bottom: 24rpx;
width: 0;
border-left: 2rpx dashed #eceef2;
}
.coupon-card-right {
flex: 1;
padding: 32rpx 32rpx 32rpx 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
background: #fff;
}
.coupon-info {
display: flex;
flex-direction: column;
gap: 12rpx;
flex: 1;
min-width: 0;
}
.coupon-card-name {
font-size: 30rpx;
color: #111;
font-weight: 700;
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.coupon-card-desc {
font-size: 24rpx;
color: #8a8f99;
font-weight: 500;
}
.coupon-card-time {
font-size: 22rpx;
color: #b0b3bf;
}
.coupon-status-btn {
flex-shrink: 0;
padding: 16rpx 32rpx;
border-radius: 40rpx;
font-size: 26rpx;
font-weight: 700;
color: #fff;
background: linear-gradient(135deg, #ff6b35, #ff4b2b);
&:active {
opacity: 0.9;
}
&.disabled {
background: #ccc;
box-shadow: none;
} }
} }
</style> </style>

View File

@@ -0,0 +1,87 @@
<template>
<view class="error-page">
<u-navbar title="支付失败" :border="false" :fixed="true" :placeholder="true" :auto-back="true"></u-navbar>
<view class="error-content">
<u-icon name="close-circle-fill" color="#f56c6c" size="120"></u-icon>
<text class="error-title">支付失败</text>
<text class="error-desc">{{ errorMessage || '支付过程中出现错误,请重试' }}</text>
<view class="btn-group">
<u-button type="primary" text="返回订单" @click="goBack"></u-button>
<u-button type="warning" text="去支付" @click="rePay"></u-button>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
const errorMessage = ref('')
const orderSn = ref('')
onLoad((options: any) => {
if (options) {
errorMessage.value = options.message || ''
orderSn.value = options.orderSn || ''
}
})
function goBack() {
uni.navigateBack({
fail: () => {
uni.switchTab({ url: '/pages/tabbar/user/my' })
}
})
}
function rePay() {
if (orderSn.value) {
uni.navigateTo({
url: `/pages/cart/payment/payOrder?orderSn=${orderSn.value}`
})
} else {
goBack()
}
}
</script>
<style lang="scss" scoped>
.error-page {
min-height: 100vh;
background: #fff;
}
.error-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 200rpx 40rpx;
}
.error-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-top: 40rpx;
}
.error-desc {
font-size: 28rpx;
color: #999;
margin-top: 20rpx;
text-align: center;
}
.btn-group {
display: flex;
gap: 24rpx;
margin-top: 60rpx;
width: 100%;
:deep(.u-button) {
flex: 1;
}
}
</style>

View File

@@ -66,410 +66,264 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import * as API_Trade from "@/api/trade"; import { ref, getCurrentInstance, onMounted } from 'vue'
import { onLoad, onBackPress } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import * as API_Trade from '@/api/trade'
import { payCallback } from '@/api/members' import { payCallback } from '@/api/members'
export default { import { unitPrice } from '@/utils/filters.js'
data() {
return {
//路径传参
routerVal: "",
//收银台参数
cashierParams: "",
//支付方式集合
payList: "",
//支付sn
sn: "",
//订单类型
orderType: "",
//支付异常
exception: {},
//支付表单
payForm: {},
//支付类型 APP/WECHAT_MP/H5/NATIVE app/微信小程序/h5/二维码
paymentType: "",
// 支付客户端 APP/NATIVE/JSAPI/H5
paymentClient: "",
//余额
walletValue: 0.0,
// 支付倒计时(毫秒)
autoCancelTime: 0,
}; const store = useStore()
}, const { proxy } = getCurrentInstance()!
onLoad(val) {
this.routerVal = val;
//初始化参数 const routerVal = ref<Record<string, string>>({})
const cashierParams = ref<Record<string, any>>({ price: 0 })
const payList = ref<string[]>([])
const sn = ref('')
const orderType = ref('')
const paymentType = ref('')
const paymentClient = ref('')
const walletValue = ref(0)
const autoCancelTime = ref(0)
onLoad((val) => {
routerVal.value = val || {}
// #ifdef APP-PLUS // #ifdef APP-PLUS
this.paymentType = "APP"; paymentType.value = 'APP'
this.paymentClient = "APP"; paymentClient.value = 'APP'
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
this.paymentType = "WECHAT_MP"; paymentType.value = 'WECHAT_MP'
this.paymentClient = "MP"; paymentClient.value = 'MP'
// #endif // #endif
// #ifdef H5 // #ifdef H5
this.paymentType = "H5"; paymentType.value = 'H5'
//如果是微信浏览器则使用公众号支付否则使用h5 paymentClient.value = isWeiXin() ? 'JSAPI' : 'H5'
// 区别是h5是通过浏览器外部调用微信app进行支付而JSAPI则是 在微信浏览器内部,或者小程序 调用微信支付
this.paymentClient = this.isWeiXin() ? "JSAPI" : "H5";
// #endif // #endif
})
onBackPress((e) => {
if (e.from == 'backbutton') {
// if (routerVal.value.recharge_sn) {
}, uni.switchTab({ url: '/pages/tabbar/user/my' })
onBackPress(e) {
if (e.from == "backbutton") {
if(this.routerVal.recharge_sn){
uni.switchTab({
url: '/pages/tabbar/user/my'
});
}
else{
uni.navigateTo({
url: "/pages/order/myOrder?status=0",
});
}
return true; //阻止默认返回行为
}
},
mounted() {
this.cashierData();
},
methods: {
/**
* 支付成功后跳转
*/
callback(paymentMethod){
uni.navigateTo({
url: "/pages/cart/payment/success?paymentMethod=" +
paymentMethod +
"&payPrice=" +
this.cashierParams.price+
"&orderType="+this.orderType
});
},
/**
* 获取收银详情
*/
cashierData() {
let parms = {};
if (this.routerVal.recharge_sn) {
// 判断当前是否是充值
this.sn = this.routerVal.recharge_sn;
this.orderType = "RECHARGE";
} else if (this.routerVal.trade_sn) {
this.sn = this.routerVal.trade_sn;
this.orderType = "TRADE";
} else { } else {
this.sn = this.routerVal.order_sn; uni.navigateTo({ url: '/pages/order/myOrder?status=0' })
this.orderType = "ORDER";
} }
parms.sn = this.sn; return true
parms.orderType = this.orderType; }
parms.clientType = this.paymentType; return false
})
onMounted(() => {
cashierData()
})
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
}
function callback(paymentMethod: string) {
uni.navigateTo({
url:
'/pages/cart/payment/success?paymentMethod=' +
paymentMethod +
'&payPrice=' +
cashierParams.value.price +
'&orderType=' +
orderType.value,
})
}
function cashierData() {
const parms: Record<string, string> = {}
if (routerVal.value.recharge_sn) {
sn.value = routerVal.value.recharge_sn
orderType.value = 'RECHARGE'
} else if (routerVal.value.trade_sn) {
sn.value = routerVal.value.trade_sn
orderType.value = 'TRADE'
} else {
sn.value = routerVal.value.order_sn
orderType.value = 'ORDER'
}
parms.sn = sn.value
parms.orderType = orderType.value
parms.clientType = paymentType.value
API_Trade.getCashierData(parms).then((res) => { API_Trade.getCashierData(parms).then((res) => {
if (res.data.success) { if (res.data.success) {
this.cashierParams = res.data.result; cashierParams.value = res.data.result
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
this.payList = res.data.result.support.filter((item) => { payList.value = res.data.result.support.filter((item: string) => item != 'ALIPAY')
return item != "ALIPAY";
});
// #endif // #endif
if (routerVal.value.recharge_sn) {
payList.value = res.data.result.support.filter((item: string) => item != 'WALLET')
} else {
payList.value = res.data.result.support
}
if(this.routerVal.recharge_sn){ // #ifdef H5
this.payList = res.data.result.support.filter((item) => { const ua = window.navigator.userAgent.toLowerCase()
return item != "WALLET"; if (ua.match(/MicroMessenger/i) == 'micromessenger') {
payList.value = res.data.result.support.filter((item: string) => item != 'ALIPAY')
if (orderType.value == 'RECHARGE') {
payList.value = res.data.result.support.filter((item: string) => item == 'WECHAT')
}
}
// #endif
walletValue.value = res.data.result.walletValue
const cancelAt = Number(res.data.result.autoCancel)
autoCancelTime.value = cancelAt > 0 ? Math.max(cancelAt - Date.now(), 0) : 0
} else if (res.data.code == 32000) {
setTimeout(() => {
uni.redirectTo({ url: '/pages/order/myOrder?status=0' })
}, 500)
}
}) })
} }
else{
this.payList = res.data.result.support;
}
// #ifdef H5
//判断是否微信浏览器
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
this.payList = res.data.result.support.filter((item) => { function awaitPay(payment: string) {
return item != "ALIPAY"; proxy.$u.throttle(() => {
}); pay(payment)
// 充值的话仅保留微信支付
if(this.orderType == "RECHARGE"){
this.payList = res.data.result.support.filter((item) => {
return item == "WECHAT";
});
}
}
// #endif
this.walletValue = res.data.result.walletValue;
const cancelAt = Number(res.data.result.autoCancel);
this.autoCancelTime = cancelAt > 0 ? Math.max(cancelAt - Date.now(), 0) : 0;
}
else if(res.data.code == 32000){
setTimeout(()=>{
uni.redirectTo({
url: `/pages/order/myOrder?status=0`
});
},500)
}
});
},
awaitPay(payment){
this.$u.throttle(()=>{
this.pay(payment)
}, 2000) }, 2000)
}, }
padTime(val) { function padTime(val: number) {
return String(val ?? 0).padStart(2, '0'); return String(val ?? 0).padStart(2, '0')
}, }
onPayTimeout() { function onPayTimeout() {
uni.showToast({ uni.showToast({ title: '支付超时,请重新下单', icon: 'none' })
title: '支付超时,请重新下单',
icon: 'none',
});
setTimeout(() => { setTimeout(() => {
uni.redirectTo({ uni.redirectTo({ url: '/pages/order/myOrder?status=0' })
url: '/pages/order/myOrder?status=0', }, 1500)
}); }
}, 1500);
},
//订单支付 function goPayError(message = '支付失败,如果您已支付,请勿反复支付') {
async pay(payment) { const query = [`orderSn=${encodeURIComponent(sn.value)}`, `message=${encodeURIComponent(message)}`]
uni.navigateTo({ url: `/pages/cart/payment/error?${query.join('&')}` })
}
// 支付编号 async function pay(payment: string) {
const sn = this.sn; const params = {
// 交易类型【交易号|订单号】 sn: sn.value,
const orderType = this.orderType; orderType: orderType.value,
clientType: paymentType.value,
}
const paymentMethod = payment
const client = paymentClient.value
const clientType = this.paymentType; uni.showLoading({ title: '正在唤起支付...', mask: true })
let params = {
sn,
orderType,
clientType,
};
//支付方式 WECHAT/ALIPAY
const paymentMethod = payment;
// 客户端类型 APP/NATIVE/JSAPI/H5
const paymentClient = this.paymentClient;
uni.showLoading({
title: "正在唤起支付...",
mask:true
});
// #ifdef APP-PLUS // #ifdef APP-PLUS
//APP pay await API_Trade.initiatePay(paymentMethod, client, params).then((signXml) => {
// 初始化支付签名 hideLoadingIfNeeded()
await API_Trade.initiatePay(paymentMethod, paymentClient, params).then(
(signXml) => {
if (this.$store.state.isShowToast){ uni.hideLoading() };
//如果支付异常
if (!signXml.data.success) { if (!signXml.data.success) {
uni.showToast({ uni.showToast({ title: signXml.data.message, duration: 2000 })
title: signXml.data.message, return
duration: 2000
});
return;
} }
const payForm = signXml.data.result
let payForm = signXml.data.result; const provider = paymentMethod === 'WECHAT' ? 'wxpay' : 'alipay'
if (paymentMethod === 'WALLET') {
let paymentType = paymentMethod === "WECHAT" ? "wxpay" : "alipay"; uni.showToast({ icon: 'none', title: '支付成功!' })
callback(paymentMethod)
if(paymentMethod === "WALLET"){ } else {
uni.showToast({
icon: "none",
title: "支付成功!",
});
this.callback(paymentMethod)
}
else{
uni.requestPayment({ uni.requestPayment({
provider: paymentType, provider,
orderInfo: payForm || '', orderInfo: payForm || '',
success: (e) => { success: () => {
uni.showToast({ uni.showToast({ icon: 'none', title: '支付成功!' })
icon: "none", callback(paymentMethod)
title: "支付成功!",
});
this.callback(paymentMethod)
}, },
fail: (e) => { fail: () => {
console.log(this); goPayError()
this.exception = e;
uni.showModal({
content: "支付失败,如果您已支付,请勿反复支付",
showCancel: false,
});
}, },
}); })
} }
} })
);
//APP pay
// #endif // #endif
// #ifdef H5 // #ifdef H5
//H5 pay await API_Trade.initiatePay(paymentMethod, client, params).then((res) => {
await API_Trade.initiatePay(paymentMethod, paymentClient, params).then( const response = res.data
(res) => { if (paymentMethod !== 'ALIPAY' && !response.success) {
let response = res.data; uni.showToast({ title: response.message, duration: 2000, icon: 'none' })
//如果非支付宝支付才需要进行判定因为支付宝h5支付是直接输出的没有返回所谓的消息状态 return
if(paymentMethod !== "ALIPAY"){
//如果支付异常
if (!response.success) {
uni.showToast({
title: response.message,
duration: 2000,
icon:"none"
});
return;
} }
} if (paymentMethod === 'ALIPAY') {
if (paymentMethod === "ALIPAY") { document.write(response)
document.write(response); } else if (paymentMethod === 'WECHAT') {
} else if (paymentMethod === "WECHAT") { if (isWeiXin()) {
if (this.isWeiXin()) { WeixinJSBridge.invoke('getBrandWCPayRequest', response.result, (payRes: any) => {
//微信公众号支付 if (payRes.err_msg == 'get_brand_wcpay_request:ok') {
WeixinJSBridge.invoke( uni.showToast({ icon: 'none', title: '支付成功!' })
"getBrandWCPayRequest", callback(paymentMethod)
response.result,
(res) => {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok但并不保证它绝对可靠。
uni.showToast({
icon: "none",
title: "支付成功!",
});
this.callback(paymentMethod)
} else { } else {
uni.showModal({ goPayError()
content: "支付失败,如果您已支付,请勿反复支付",
showCancel: false,
});
} }
}
);
if (this.$store.state.isShowToast){ uni.hideLoading() };
} else {
window.location.href = JSON.parse(response.result).h5_url;
const searchParams = {
...params,
price:this.cashierParams,
}
const timer = setInterval(()=>{
payCallback(searchParams).then(res=>{
if(res.data.result){
clearTimeout(timer);
uni.navigateTo({
url:"/pages/order/myOrder"
}) })
hideLoadingIfNeeded()
} else {
window.location.href = JSON.parse(response.result).h5_url
const searchParams = { ...params, price: cashierParams.value }
const timer = setInterval(() => {
payCallback(searchParams).then((cbRes) => {
if (cbRes.data.result) {
clearInterval(timer)
uni.navigateTo({ url: '/pages/order/myOrder' })
} }
}) })
}, 3000) }, 3000)
hideLoadingIfNeeded()
if (this.$store.state.isShowToast){ uni.hideLoading() };
} }
} else if (paymentMethod === "WALLET") { } else if (paymentMethod === 'WALLET') {
uni.showToast({ uni.showToast({ title: response.message, icon: 'none' })
title: response.message, if (response.success) callback(paymentMethod)
icon: "none",
});
if (response.success) {
this.callback(paymentMethod)
} }
} })
}
);
//H5pay
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
//微信小程序 await API_Trade.initiatePay(paymentMethod, client, params).then((res) => {
await API_Trade.initiatePay(paymentMethod, paymentClient, params).then( const response = res.data.result
(res) => {
let response = res.data.result;
//如果支付异常
if (!res.data.success) { if (!res.data.success) {
uni.showModal({ uni.showModal({ content: res.data.message, showCancel: false })
content: res.data.message, return
showCancel: false,
})
return;
} }
if (paymentMethod === "WECHAT") { if (paymentMethod === 'WECHAT') {
uni.requestPayment({ uni.requestPayment({
provider: "wxpay", provider: 'wxpay',
appid: response.appid, appid: response.appid,
timeStamp: response.timeStamp, timeStamp: response.timeStamp,
nonceStr: response.nonceStr, nonceStr: response.nonceStr,
package: response.package, package: response.package,
signType: response.signType, signType: response.signType,
paySign: response.paySign, paySign: response.paySign,
success: (e) => { success: () => {
console.log(e); uni.showToast({ icon: 'none', title: '支付成功!' })
uni.showToast({ callback(paymentMethod)
icon: "none",
title: "支付成功!",
});
this.callback(paymentMethod)
}, },
fail: (e) => { fail: () => {
console.log(e); goPayError()
this.exception = e;
uni.showModal({
content: "支付失败,如果您已支付,请勿反复支付",
showCancel: false,
});
}, },
}); })
} else { } else {
uni.showToast({ uni.showToast({ icon: 'none', title: '支付成功!' })
icon: "none", callback(paymentMethod)
title: "支付成功!",
});
this.callback(paymentMethod)
} }
} })
);
// #endif // #endif
},
isWeiXin() {
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == "micromessenger") {
return true;
} else {
return false;
} }
},
}, function isWeiXin() {
}; const ua = window.navigator.userAgent.toLowerCase()
return ua.match(/MicroMessenger/i) == 'micromessenger'
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.method_icon { .method_icon {

View File

@@ -49,7 +49,13 @@
<!-- 倒计时 --> <!-- 倒计时 -->
<div class="count-down" v-if="!isOver && master.toBeGroupedNum"> <div class="count-down" v-if="!isOver && master.toBeGroupedNum">
<u-count-down bg-color="#ededed" :hide-zero-day="true" @end="isOver" :timestamp="timeStamp"></u-count-down> <u-count-down
v-if="timeStamp > 0"
bgColor="#ededed"
:time="timeStamp * 1000"
format="HH:mm:ss"
@finish="onCountDownEnd"
></u-count-down>
</div> </div>
<div class="user-list" v-if="data.pintuanMemberVOS"> <div class="user-list" v-if="data.pintuanMemberVOS">
@@ -59,173 +65,184 @@
</div> </div>
</div> </div>
<popupGoods :addr="addr" ref="popupGoods" :buyMask="maskFlag" @closeBuy="closePopupBuy" :goodsDetail="goodsDetail" :goodsSpec="goodsSpec" v-if="goodsDetail.id " @handleClickSku="getGoodsDetail" /> <popupGoods
<shares @close="closeShare" :link="'/pages/cart/payment/shareOrderGoods?sn='+this.routers.sn+'&sku='+this.routers.sku+'&goodsId='+this.routers.goodsId" type="pintuan" :addr="addr"
:thumbnail="data.promotionGoods.thumbnail" :goodsName="data.promotionGoods.goodsName" v-if="shareFlag " /> ref="popupGoodsRef"
:buyMask="maskFlag"
@closeBuy="closePopupBuy"
:goodsDetail="goodsDetail"
:goodsSpec="goodsSpec"
v-if="goodsDetail.id"
@handleClickSku="getGoodsDetail"
/>
<shares
@close="closeShare"
:link="shareLink"
type="pintuan"
:thumbnail="data.promotionGoods.thumbnail"
:goodsName="data.promotionGoods.goodsName"
v-if="shareFlag"
/>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getGoods } from "@/api/goods.js"; import { ref, computed, watch, onMounted } from 'vue'
import { getPinTuanShare } from "@/api/order"; import { onLoad } from '@dcloudio/uni-app'
import shares from "@/components/m-share/index"; import { useStore } from '@/store'
import storage from "@/utils/storage.js"; import { getGoods } from '@/api/goods.js'
import popupGoods from "@/components/m-buy/goods"; //购物车商品的模块 import { getPinTuanShare } from '@/api/order'
import shares from '@/components/m-share/index'
import storage from '@/utils/storage.js'
import popupGoods from '@/components/m-buy/goods'
import { unitPrice } from '@/utils/filters.js'
export default { const store = useStore()
data() {
return { const popupGoodsRef = ref<any>(null)
flag: false, //判断接口是否正常请求 const flag = ref(false)
addr: { const addr = ref({ id: '' })
id: "", const maskFlag = ref(false)
}, const timeStamp = ref(0)
maskFlag: false, //商品弹框 const shareFlag = ref(false)
timeStamp: 0, const data = ref<any>(null)
shareFlag: false, const isMaster = ref(true)
data: "", const selectedGoods = ref<any>(null)
isMaster: true, const routers = ref<Record<string, string>>({})
selectedGoods: "", //选择的商品规格昵称 const goodsDetail = ref<any>({})
routers: "", //传参数据 const goodsSpec = ref<any>(null)
goodsDetail: "", //商品详情 const master = ref<any>(null)
goodsSpec: "", const PromotionList = ref<any>(null)
master: "", // 团长 const isGroup = ref(false)
PromotionList: "", //优惠集合 const isOver = ref(false)
isGroup: false, //是否拼团 const isBuy = ref(false)
isOver: false, //是否结束活动
isBuy: false, //当前用户是是否购买 const shareLink = computed(() => {
}; const { sn, sku, goodsId } = routers.value
}, return `/pages/cart/payment/shareOrderGoods?sn=${sn}&sku=${sku}&goodsId=${goodsId}`
components: { })
shares,
popupGoods, watch(isGroup, (val) => {
},
watch: {
isGroup(val) {
if (val) { if (val) {
let timer = setInterval(() => { const timer = setInterval(() => {
this.$refs.popupGoods.buyType = "PINTUAN"; if (popupGoodsRef.value) {
clearInterval(timer); popupGoodsRef.value.buyType = 'PINTUAN'
}, 100);
} else {
this.$refs.popupGoods.buyType = "";
} }
}, clearInterval(timer)
}, }, 100)
onLoad(options) { } else if (popupGoodsRef.value) {
this.routers = options; popupGoodsRef.value.buyType = ''
}, }
mounted() { })
this.init(this.routers.sn, this.routers.sku);
}, onLoad((options) => {
methods: { routers.value = options || {}
closeShare() { })
this.shareFlag = false;
}, onMounted(() => {
// 这里的话得先跳到商品详情才能购买商品 init(routers.value.sn, routers.value.sku)
toBuy() { })
this.maskFlag = true;
this.$refs.popupGoods.parentOrder = { function hideLoadingIfNeeded() {
...this.master, if (store.state.isShowToast) uni.hideLoading()
orderSn: this.routers.sn, }
};
this.$refs.popupGoods.isMask = true; function closeShare() {
this.$refs.popupGoods.isClose = true; shareFlag.value = false
this.$refs.popupGoods.buyType = "PINTUAN"; }
},
// 分享 function onCountDownEnd() {
share() { isOver.value = true
this.shareFlag = true; }
},
closePopupBuy(val) { function toBuy() {
this.maskFlag = false; maskFlag.value = true
}, if (!popupGoodsRef.value) return
// 实例化本页面 popupGoodsRef.value.parentOrder = {
async init(sn, sku) { ...master.value,
let res = await getPinTuanShare(sn, sku); orderSn: routers.value.sn,
}
popupGoodsRef.value.isMask = true
popupGoodsRef.value.isClose = true
popupGoodsRef.value.buyType = 'PINTUAN'
}
function share() {
shareFlag.value = true
}
function closePopupBuy() {
maskFlag.value = false
}
async function init(sn: string, sku: string) {
const res = await getPinTuanShare(sn, sku)
if (res.data.success && res.data.result.promotionGoods) { if (res.data.success && res.data.result.promotionGoods) {
this.flag = true; flag.value = true
this.data = res.data.result; data.value = res.data.result
this.selectedGoods = res.data.result.promotionGoods; selectedGoods.value = res.data.result.promotionGoods
let endTime = Date.parse( const endTime = Date.parse(
res.data.result.promotionGoods.endTime.replace(/-/g, "/") res.data.result.promotionGoods.endTime.replace(/-/g, '/')
); )
// 获取当前剩余的拼团商品时间 const endTimestamp = Date.parse(new Date(endTime) as any) / 1000
let timeStamp = Date.parse(new Date(endTime)) / 1000; const dateTime = Date.parse(new Date() as any) / 1000
timeStamp.value = parseInt(String(endTimestamp - dateTime))
isOver.value = timeStamp.value <= 0
// 获取当前时间时间戳 master.value =
let dateTime = Date.parse(new Date()) / 1000;
this.timeStamp = parseInt(timeStamp - dateTime);
this.timeStamp <= 0 ? (this.isOver = true) : (this.isOver = false);
// 获取剩余拼团人数
this.master =
res.data.result.pintuanMemberVOS.length != 0 && res.data.result.pintuanMemberVOS.length != 0 &&
res.data.result.pintuanMemberVOS.filter((item) => { res.data.result.pintuanMemberVOS.filter((item: any) => item.orderSn == '')[0]
return item.orderSn == "";
})[0];
// 获取当前是否是拼团本人
if ( if (
storage.getUserInfo(this.routers.sku, this.routers.goodsId).id == storage.getUserInfo(routers.value.sku, routers.value.goodsId).id ==
this.master.memberId master.value.memberId
) { ) {
this.isMaster = true; isMaster.value = true
} else { } else {
this.isMaster = false; isMaster.value = false
// 获取商品详情 getGoodsDetail({
this.getGoodsDetail({ id: routers.value.sku,
id: this.routers.sku, goodsId: routers.value.goodsId,
goodsId: this.routers.goodsId, })
});
} }
// 获取当前商品是否已经购买
if (storage.getUserInfo().id) { if (storage.getUserInfo().id) {
let isBuy = res.data.result.pintuanMemberVOS.filter((item) => { const bought = res.data.result.pintuanMemberVOS.filter(
return item.memberId == storage.getUserInfo().id; (item: any) => item.memberId == storage.getUserInfo().id
}); )
isBuy.length != 0 ? (this.isBuy = true) : (this.isBuy = false); isBuy.value = bought.length != 0
} }
} else { } else {
uni.showToast({ uni.showToast({
title: "当前拼团单有误!请联系管理员重试", title: '当前拼团单有误!请联系管理员重试',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}
} }
},
// 获取商品详情
getGoodsDetail(val) {
let { id, goodsId } = val;
uni.showLoading({
title: "加载中",
mask: true,
});
getGoods(id, goodsId).then((response) => {
this.goodsDetail = response.data.result.data;
this.selectedGoods = response.data.result.data;
this.goodsSpec = response.data.result.specs;
if (this.$store.state.isShowToast){ uni.hideLoading() };
this.PromotionList = response.data.result.promotionMap;
// 判断是否拼团活动 如果有则显示拼团活动信息 function getGoodsDetail(val: { id: string; goodsId: string }) {
this.PromotionList && const { id, goodsId } = val
Object.keys(this.PromotionList).forEach((item) => { uni.showLoading({ title: '加载中', mask: true })
if (item.indexOf("PINTUAN") == 0) { getGoods(id, goodsId).then((response) => {
this.isGroup = true; goodsDetail.value = response.data.result.data
selectedGoods.value = response.data.result.data
goodsSpec.value = response.data.result.specs
hideLoadingIfNeeded()
PromotionList.value = response.data.result.promotionMap
if (PromotionList.value) {
Object.keys(PromotionList.value).forEach((item) => {
if (item.indexOf('PINTUAN') == 0) {
isGroup.value = true
}
})
}
})
}
function handleClickHome() {
uni.switchTab({ url: '/pages/tabbar/home/index' })
} }
});
});
},
handleClickHome() {
uni.switchTab({
url: "/pages/tabbar/home/index",
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -5,7 +5,7 @@
{{unitPrice(Number(payPrice)) }} {{unitPrice(Number(payPrice)) }}
</div> </div>
<div class="pay-btns"> <div class="pay-btns">
<div v-show="!from" @click="checkOrder">查看{{ this.orderType == "RECHARGE" ? '余额' : '订单' }}</div> <div v-show="!from" @click="checkOrder">查看{{ orderType == "RECHARGE" ? '余额' : '订单' }}</div>
<div @click="navigateTo('/pages/tabbar/home/index', 'switch')">回到首页</div> <div @click="navigateTo('/pages/tabbar/home/index', 'switch')">回到首页</div>
</div> </div>
</div> </div>
@@ -24,73 +24,55 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import goodsRecommend from "@/components/m-goods-recommend"; import { ref } from 'vue'
export default { import { onLoad } from '@dcloudio/uni-app'
data() { import goodsRecommend from '@/components/m-goods-recommend'
return { import { unitPrice } from '@/utils/filters.js'
checked: false,
paymentMethod: "",
from: "", const paymentMethod = ref('')
payPrice: 0, const from = ref('')
goodsList: [], const payPrice = ref<number | string>(0)
activeColor: this.$mainColor, const orderType = ref('')
};
},
components: {
goodsRecommend,
},
onLoad(options) {
this.paymentMethod = options.paymentMethod || "";
this.from = options.from || "";
this.payPrice = options.payPrice || 0;
this.orderType = options.orderType;
}, onLoad((options) => {
methods: { paymentMethod.value = options.paymentMethod || ''
paymentTypeFilter(val) { from.value = options.from || ''
payPrice.value = options.payPrice || 0
orderType.value = options.orderType || ''
})
function paymentTypeFilter(val: string) {
switch (val) { switch (val) {
case "WECHAT": case 'WECHAT':
return "微信"; return '微信'
case "ALIPAY": case 'ALIPAY':
return "支付宝"; return '支付宝'
case "WALLET": case 'WALLET':
return "余额支付"; return '余额支付'
default: default:
return ""; return ''
} }
},
checkOrder() {
/**
* 查看订单
* 1.充值跳转到明细里面
* 2.支付跳转到订单详情
*/
if (this.orderType == "RECHARGE") {
uni.reLaunch({
url: `/pages/mine/deposit/operation`,
});
} else {
this.navigateTo("/pages/order/myOrder?status=0");
} }
},
navigateTo(url, type) { function checkOrder() {
if (type === "switch") { if (orderType.value == 'RECHARGE') {
uni.switchTab({ uni.reLaunch({
url, url: '/pages/mine/deposit/operation',
}); })
} else { } else {
uni.redirectTo({ navigateTo('/pages/order/myOrder?status=0')
url,
});
} }
}, }
},
}; function navigateTo(url: string, type?: string) {
</script> if (type === 'switch') {
<style scoped lang="scss"> uni.switchTab({ url })
} else {
uni.redirectTo({ url })
}
}
</script><style scoped lang="scss">
.subscribe { .subscribe {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;

View File

@@ -2,21 +2,16 @@
<default-page v-if="type" :type="type" title="您的设备已断网" :isBtn="false" /> <default-page v-if="type" :type="type" title="您的设备已断网" :isBtn="false" />
</template> </template>
<script> <script setup lang="ts">
import defaultPage from '@/components/default-page/default-page.vue'; import { ref } from 'vue'
export default { import { onLoad } from '@dcloudio/uni-app'
components: { import defaultPage from '@/components/default-page/default-page.vue'
defaultPage
},
data() {
return {
type: undefined
}
},
onLoad(options) {
} const type = ref<string>()
}
onLoad(() => {
type.value = 'msg'
})
</script> </script>
<style> <style>

View File

@@ -1,7 +1,14 @@
<template> <template>
<view class="add-address"> <view class="add-address">
<u-form :model="form" ref="uForm" error-type="toast" :rules="rules"> <up-form
<u-form-item label="收货人" label-width="130" prop="name" :border-bottom="true"> :model="form"
ref="uForm"
error-type="toast"
:rules="rules"
label-position="left"
label-width="180rpx"
>
<up-form-item label="收货人" label-width="180rpx" prop="name" :border-bottom="true">
<u-input <u-input
v-model="form.name" v-model="form.name"
border="none" border="none"
@@ -9,9 +16,9 @@
clearable clearable
placeholder="请输入收货人姓名" placeholder="请输入收货人姓名"
/> />
</u-form-item> </up-form-item>
<u-form-item label="手机号码" label-width="130" prop="mobile" :border-bottom="true"> <up-form-item label="手机号码" label-width="180rpx" prop="mobile" :border-bottom="true">
<u-input <u-input
v-model="form.mobile" v-model="form.mobile"
type="number" type="number"
@@ -20,18 +27,18 @@
input-align="right" input-align="right"
placeholder="请输入收货人手机号码" placeholder="请输入收货人手机号码"
/> />
</u-form-item> </up-form-item>
<u-form-item label="所在区域" label-width="130" prop="___path" :border-bottom="true"> <up-form-item label="所在区域" label-width="180rpx" prop="___path" :border-bottom="true">
<view class="form-value" @click="showPicker"> <view class="form-value" @click="showPicker">
{{ form.___path || '请选择所在地区' }} {{ form.___path || '请选择所在地区' }}
</view> </view>
<template #right> <template #right>
<u-icon name="arrow-right" color="#ccc" size="16"></u-icon> <u-icon name="arrow-right" color="#ccc" size="16"></u-icon>
</template> </template>
</u-form-item> </up-form-item>
<u-form-item class="detailAddress" label="详细地址" label-width="130" prop="detail" :border-bottom="true"> <up-form-item class="detailAddress" label="详细地址" label-width="180rpx" prop="detail" :border-bottom="true">
<u-input <u-input
type="textarea" type="textarea"
v-model="form.detail" v-model="form.detail"
@@ -40,16 +47,16 @@
border="none" border="none"
placeholder="街道楼牌号等" placeholder="街道楼牌号等"
/> />
</u-form-item> </up-form-item>
<u-form-item label="地址别名" label-width="130" :border-bottom="false"> <up-form-item label="地址别名" label-width="180rpx" :border-bottom="false">
<u-input <u-input
v-model="form.alias" v-model="form.alias"
border="none" border="none"
input-align="right" input-align="right"
placeholder="请输入地址别名" placeholder="请输入地址别名"
/> />
</u-form-item> </up-form-item>
<view class="default-row"> <view class="default-row">
<u-checkbox <u-checkbox
@@ -63,7 +70,7 @@
</view> </view>
<view class="saveBtn" @click="save">保存</view> <view class="saveBtn" @click="save">保存</view>
</u-form> </up-form>
<m-city <m-city
:provinceData="list" :provinceData="list"
@@ -76,266 +83,208 @@
<uniMap v-if="mapFlag" @close="closeMap" @callback="callBackAddress" /> <uniMap v-if="mapFlag" @close="closeMap" @callback="callBackAddress" />
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { addAddress, editAddress, getAddressDetail } from "@/api/address.js"; import { ref, reactive, computed, getCurrentInstance } from 'vue'
import city from "@/components/m-city/m-city.vue"; import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import uniMap from "@/components/uniMap"; import { useStore } from '@/store'
import permision from "@/js_sdk/wa-permission/permission.js"; import { addAddress as addAddressApi, editAddress, getAddressDetail } from '@/api/address.js'
export default { import MCity from '@/components/m-city/m-city.vue'
components: { import uniMap from '@/components/uniMap'
"m-city": city, import permision from '@/js_sdk/wa-permission/permission.js'
uniMap,
},
onShow() {
// 判断当前系统权限定位是否开启
},
methods: {
// 关闭地图
closeMap() {
this.mapFlag = false;
},
// 打开地图并访问权限
clickUniMap() {
// #ifdef APP-PLUS
if (plus.os.name == "iOS") {
// ios系统
permision.judgeIosPermission("location")
? (this.mapFlag = true)
: this.refuseMap();
} else {
// 安卓
this.requestAndroidPermission(
"android.permission.ACCESS_FINE_LOCATION"
);
}
// #endif
// #ifndef APP-PLUS const store = useStore()
this.mapFlag = true; const { proxy } = getCurrentInstance()!
// #endif
const lightColor = computed(() => store.getters.lightColor)
const mapFlag = ref(false)
const routerVal = ref<Record<string, string>>({})
const uForm = ref<any>(null)
const cityPicker = ref<any>(null)
const form = reactive<Record<string, any>>({
detail: '',
name: '',
mobile: '',
consigneeAddressIdPath: [],
consigneeAddressPath: [],
___path: '',
isDefault: false,
})
const list = ref([
{
id: '',
localName: '请选择',
children: [],
}, },
])
// 如果拒绝权限 提示区设置 const rules = {
refuseMap() {
uni.showModal({
title: "温馨提示",
content: "您已拒绝定位,请开启",
confirmText: "去设置",
success(res) {
if (res.confirm) {
//打开授权设置
// #ifndef MP-WEIXIN
uni.getSystemInfo({
success(res) {
if (res.platform == "ios") {
//IOS
plus.runtime.openURL("app-settings://");
} else if (res.platform == "android") {
//安卓
let main = plus.android.runtimeMainActivity();
let Intent = plus.android.importClass(
"android.content.Intent"
);
let mIntent = new Intent("android.settings.ACTION_SETTINGS");
main.startActivity(mIntent);
}
},
});
// #endif
}
},
});
},
// 获取安卓是否拥有地址权限
async requestAndroidPermission(permisionID) {
var result = await permision.requestAndroidPermission(permisionID);
if (result == 1) {
this.mapFlag = true;
} else {
this.refuseMap();
}
},
// 选择地址后数据的回调
callBackAddress(val) {
console.log(val)
uni.showLoading({
title: "加载中",
});
if (val.regeocode && val) {
let address = val.regeocode;
this.form.detail = address.formatted_address; //地址详情
this.form.___path = val.data.result.name;
this.form.consigneeAddressIdPath = val.data.result.id; // 地址id分割
this.form.consigneeAddressPath = val.data.result.name; //地址名称, ''分割
this.form.lat = val.latitude; //纬度
this.form.lon = val.longitude; //经度
uni.hideLoading();
}
this.mapFlag = !this.mapFlag; //关闭地图
},
// 保存当前 地址
save() {
this.$refs.uForm.validate().then(() => {
const params = { ...this.form };
delete params.___path;
if (Array.isArray(params.consigneeAddressIdPath)) {
params.consigneeAddressIdPath = params.consigneeAddressIdPath.join(",");
}
if (Array.isArray(params.consigneeAddressPath)) {
params.consigneeAddressPath = params.consigneeAddressPath.join(",");
}
if (!params.id) {
addAddress(params).then((res) => {
if (res.data.success) {
uni.navigateBack();
} else {
uni.showToast({
title: res.data.message || "保存失败",
icon: "none",
});
}
});
} else {
delete params.updateBy;
delete params.updateTime;
editAddress(params).then((res) => {
if (res.data.success) {
uni.navigateBack();
} else {
uni.showToast({
title: res.data.message || "保存失败",
icon: "none",
});
}
});
}
}).catch(() => {});
},
// 三级地址联动回调
getpickerParentValue(e) {
// 将需要绑定的地址设置为空,并赋值
this.form.consigneeAddressIdPath = [];
this.form.consigneeAddressPath = [];
let name = "";
e.forEach((item, index) => {
if (item.id) {
// 遍历数据
this.form.consigneeAddressIdPath.push(item.id);
this.form.consigneeAddressPath.push(item.localName);
name += item.localName;
this.form.___path = name;
}
if (index == e.length - 1) {
//如果是最后一个
let _town = item.children.filter((_child) => {
return _child.id == item.id;
});
this.form.lat = _town[0].center.split(",")[1];
this.form.lon = _town[0].center.split(",")[0];
}
});
},
// 显示三级地址联动
showPicker() {
this.$refs.cityPicker.show();
},
},
mounted() {},
data() {
return {
lightColor: this.$lightColor, //高亮颜色
mapFlag: false, // 地图选择开
routerVal: "",
form: {
detail: "", //地址详情
name: "", //收货人姓名
mobile: "", //手机号码
consigneeAddressIdPath: [], //地址id
consigneeAddressPath: [], //地址名字
___path: "", //所在区域
isDefault: false, //是否默认地址
},
// 表单提交校验规则
rules: {
name: [ name: [
{ {
required: true, required: true,
message: "收货人姓名不能为空", message: '收货人姓名不能为空',
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
mobile: [ mobile: [
{ {
required: true, required: true,
message: "手机号码不能为空", message: '手机号码不能为空',
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
{ {
validator: (rule, value, callback) => { validator: (_rule: unknown, value: string) => proxy.$u.test.mobile(value),
return this.$u.test.mobile(value); message: '手机号码不正确',
}, trigger: ['change', 'blur'],
message: "手机号码不正确",
trigger: ["change", "blur"],
}, },
], ],
___path: [ ___path: [
{ {
required: true, required: true,
message: "请选择所在区域", message: '请选择所在区域',
trigger: ["change"], trigger: ['change'],
}, },
], ],
detail: [ detail: [
{ {
required: true, required: true,
message: "请填写详细地址", message: '请填写详细地址',
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
}, }
list: [
{ onShow(() => {})
id: "",
localName: "请选择", onLoad((option) => {
children: [], uni.showLoading({ title: '加载中' })
}, routerVal.value = option || {}
],
};
},
onLoad(option) {
uni.showLoading({
title: "加载中",
});
this.routerVal = option;
// 如果当前是编辑地址,则需要查询出地址详情信息
if (option.id) { if (option.id) {
getAddressDetail(option.id).then((res) => { getAddressDetail(option.id).then((res) => {
const params = res.data.result; const params = res.data.result
params.___path = params.consigneeAddressPath; params.___path = params.consigneeAddressPath
this["form"] = params; Object.assign(form, params)
if (store.state.isShowToast) uni.hideLoading()
if (this.$store.state.isShowToast){ uni.hideLoading() }; })
}); }
uni.hideLoading()
})
onReady(() => {
uForm.value?.setRules(rules)
})
function closeMap() {
mapFlag.value = false
}
function refuseMap() {
uni.showModal({
title: '温馨提示',
content: '您已拒绝定位,请开启',
confirmText: '去设置',
success(res) {
if (res.confirm) {
// #ifndef MP-WEIXIN
uni.getSystemInfo({
success(sysRes) {
if (sysRes.platform == 'ios') {
plus.runtime.openURL('app-settings://')
} else if (sysRes.platform == 'android') {
const main = plus.android.runtimeMainActivity()
const Intent = plus.android.importClass('android.content.Intent')
const mIntent = new Intent('android.settings.ACTION_SETTINGS')
main.startActivity(mIntent)
} }
uni.hideLoading();
}, },
// 初始化rules必须要在onReady生命周期因为onLoad生命周期组件可能尚未创建完毕 })
onReady() { // #endif
this.$refs.uForm.setRules(this.rules); }
}, },
}; })
}
async function requestAndroidPermission(permisionID: string) {
const result = await permision.requestAndroidPermission(permisionID)
if (result == 1) {
mapFlag.value = true
} else {
refuseMap()
}
}
function callBackAddress(val: any) {
uni.showLoading({ title: '加载中' })
if (val.regeocode && val) {
const address = val.regeocode
form.detail = address.formatted_address
form.___path = val.data.result.name
form.consigneeAddressIdPath = val.data.result.id
form.consigneeAddressPath = val.data.result.name
form.lat = val.latitude
form.lon = val.longitude
uni.hideLoading()
}
mapFlag.value = !mapFlag.value
}
function save() {
uForm.value?.validate().then(() => {
const params = { ...form }
delete params.___path
if (Array.isArray(params.consigneeAddressIdPath)) {
params.consigneeAddressIdPath = params.consigneeAddressIdPath.join(',')
}
if (Array.isArray(params.consigneeAddressPath)) {
params.consigneeAddressPath = params.consigneeAddressPath.join(',')
}
if (!params.id) {
addAddressApi(params).then((res) => {
if (res.data.success) {
uni.navigateBack()
} else {
uni.showToast({ title: res.data.message || '保存失败', icon: 'none' })
}
})
} else {
delete params.updateBy
delete params.updateTime
editAddress(params).then((res) => {
if (res.data.success) {
uni.navigateBack()
} else {
uni.showToast({ title: res.data.message || '保存失败', icon: 'none' })
}
})
}
}).catch(() => {})
}
function getpickerParentValue(e: any[]) {
form.consigneeAddressIdPath = []
form.consigneeAddressPath = []
let name = ''
e.forEach((item, index) => {
if (item.id) {
form.consigneeAddressIdPath.push(item.id)
form.consigneeAddressPath.push(item.localName)
name += item.localName
form.___path = name
}
if (index == e.length - 1) {
const _town = item.children.filter((_child: any) => _child.id == item.id)
form.lat = _town[0].center.split(',')[1]
form.lon = _town[0].center.split(',')[0]
}
})
}
function showPicker() {
cityPicker.value?.show()
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
page { page {

View File

@@ -42,126 +42,95 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import * as API_Trade from "@/api/trade"; import { ref } from 'vue'
import * as API_Address from "@/api/address.js"; import { onLoad, onShow, onPullDownRefresh } from '@dcloudio/uni-app'
export default { import { useStore } from '@/store'
data() { import * as API_Trade from '@/api/trade'
return { import * as API_Address from '@/api/address.js'
addressList: [], //地址列表
showAction: false, //是否显示下栏框
removeList: [
{
text: "确定",
},
],
tips: {
text: "确定要删除该收货人信息吗?",
},
removeId: "", //删除的地址id
routerVal: "",
params: {
pageNumber: 1,
pageSize: 1000,
},
};
},
onPullDownRefresh() {
//下拉刷新
this.addressList = [];
this.getAddressList();
},
onLoad: function (val) {
this.routerVal = val;
},
onShow() {
this.addressList = [];
this.getAddressList();
},
onHide() {},
methods: {
async selectAddressData(val) {
await API_Trade.setAddressId(val.id, this.routerVal.way);
uni.navigateBack({ const store = useStore()
delta: 1,
});
},
//获取地址列表
getAddressList() {
uni.showLoading();
API_Address.getAddressList( const addressList = ref<any[]>([])
this.params.pageNumber, const showAction = ref(false)
this.params.pageSize const removeList = [{ text: '确定' }]
).then((res) => { const tips = { text: '确定要删除该收货人信息吗?' }
res.data.result.records.forEach((item) => { const removeId = ref('')
item.consigneeAddressPath = item.consigneeAddressPath.split(","); const routerVal = ref<Record<string, string>>({})
}); const params = { pageNumber: 1, pageSize: 1000 }
this.addressList = res.data.result.records;
console.log(this.addressList);
if (this.$store.state.isShowToast){ uni.hideLoading() }; onPullDownRefresh(() => {
}); addressList.value = []
}, getAddressList()
//删除地址 })
removeAddress(id) {
this.removeId = id; onLoad((val) => {
this.showAction = true; routerVal.value = val || {}
}, })
deleteAddressMessage() {
API_Address.deleteAddress(this.removeId).then((res) => { onShow(() => {
if (res.statusCode == 200) { addressList.value = []
uni.showToast({ getAddressList()
icon: "none", })
title: "删除成功",
}); function hideLoadingIfNeeded() {
this.getAddressList(); if (store.state.isShowToast) uni.hideLoading()
} else {
uni.showToast({
icon: "none",
title: res.data.message,
duration: 2000,
});
} }
});
}, async function selectAddressData(val: any) {
//新建。编辑地址 await API_Trade.setAddressId(val.id, routerVal.value.way)
addAddress(id) { uni.navigateBack({ delta: 1 })
}
function getAddressList() {
uni.showLoading()
API_Address.getAddressList(params.pageNumber, params.pageSize).then((res) => {
res.data.result.records.forEach((item: any) => {
item.consigneeAddressPath = item.consigneeAddressPath.split(',')
})
addressList.value = res.data.result.records
hideLoadingIfNeeded()
})
}
function removeAddress(id: string) {
removeId.value = id
showAction.value = true
}
function deleteAddressMessage() {
API_Address.deleteAddress(removeId.value).then((res) => {
if (res.statusCode == 200) {
uni.showToast({ icon: 'none', title: '删除成功' })
getAddressList()
} else {
uni.showToast({ icon: 'none', title: res.data.message, duration: 2000 })
}
})
}
function addAddress(id: string) {
if (id) { if (id) {
uni.navigateTo({ uni.navigateTo({
url: url: `/pages/mine/address/add?id=${id}&way=${routerVal.value.way}&type=order`,
"/pages/mine/address/add?id=" + })
id +
"&way=" +
this.routerVal.way +
"&type=order",
});
} else { } else {
uni.navigateTo({ uni.navigateTo({
url: url: `/pages/mine/address/add?way=${routerVal.value.way}&type=order`,
"/pages/mine/address/add?way=" + this.routerVal.way + "&type=order", })
}); }
} }
},
//设为默认地址
setDefault(item) {
delete item.updateBy;
delete item.updateTime;
delete item.deleteFlag;
item.isDefault ? "" : (item.isDefault = !item.isDefault); function setDefault(item: any) {
delete item.updateBy
API_Address.editAddress(item).then((res) => { delete item.updateTime
uni.showToast({ delete item.deleteFlag
title: "设置默认地址成功", if (!item.isDefault) item.isDefault = true
icon: "none", API_Address.editAddress(item).then(() => {
}); uni.showToast({ title: '设置默认地址成功', icon: 'none' })
this.getAddressList(); getAddressList()
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,6 +1,6 @@
<template> <template>
<view class="address"> <view class="address">
<u-empty class="empty" v-if="this.addressList.length === 0" text="暂无收货地址" mode="address"></u-empty> <u-empty class="empty" v-if="addressList.length === 0" text="暂无收货地址" mode="address"></u-empty>
<view class="list" > <view class="list" >
<view class="item c-content" v-for="(item, index) in addressList" :key="index"> <view class="item c-content" v-for="(item, index) in addressList" :key="index">
<view class="basic"> <view class="basic">
@@ -43,116 +43,90 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import * as API_Address from "@/api/address.js"; import { ref } from 'vue'
export default { import { onLoad, onShow, onPullDownRefresh, onBackPress } from '@dcloudio/uni-app'
data() { import { useStore } from '@/store'
return { import { tipsToLogin } from '@/utils/filters.js'
addressList: [], //地址列表 import * as API_Address from '@/api/address.js'
showAction: false, //是否显示下栏框
removeList: [ const store = useStore()
{
text: "确定", const addressList = ref<any[]>([])
}, const showAction = ref(false)
], const removeList = [{ text: '确定' }]
tips: { const tips = { text: '确定要删除该收货人信息吗?' }
text: "确定要删除该收货人信息吗?", const removeId = ref('')
}, const routerVal = ref<Record<string, string>>({})
removeId: "", //删除的地址id const params = { pageNumber: 1, pageSize: 1000 }
routerVal: "",
params: { onBackPress(() => {
pageNumber: 1, uni.switchTab({ url: '/pages/tabbar/user/my' })
pageSize: 1000, return true
}, })
};
}, onLoad((val) => {
// 返回上一级 routerVal.value = val || {}
onBackPress(e) { })
uni.switchTab({
url: "/pages/tabbar/user/my", onPullDownRefresh(() => {
}); addressList.value = []
return true; getAddressList()
}, })
onLoad: function (val) {
this.routerVal = val; onShow(() => {
}, if (tipsToLogin()) {
onPullDownRefresh() { getAddressList()
//下拉刷新
this.addressList = [];
this.getAddressList();
},
/**
* 进入页面检测当前账户是否登录
*/
onShow() {
if (this.tipsToLogin()) {
this.getAddressList();
} }
}, })
methods: {
//获取地址列表
getAddressList() {
uni.showLoading();
API_Address.getAddressList(
this.params.pageNumber,
this.params.pageSize
).then((res) => {
res.data.result.records.forEach((item) => {
item.consigneeAddressPath = item.consigneeAddressPath.split(",");
});
this.addressList = res.data.result.records;
if (this.$store.state.isShowToast){ uni.hideLoading() }; function hideLoadingIfNeeded() {
}); if (store.state.isShowToast) uni.hideLoading()
}, }
//删除地址
removeAddress(id) { function getAddressList() {
this.removeId = id; uni.showLoading()
this.showAction = true; API_Address.getAddressList(params.pageNumber, params.pageSize).then((res) => {
}, res.data.result.records.forEach((item: any) => {
// 删除地址 item.consigneeAddressPath = item.consigneeAddressPath.split(',')
deleteAddressMessage() { })
API_Address.deleteAddress(this.removeId).then((res) => { addressList.value = res.data.result.records
hideLoadingIfNeeded()
})
}
function removeAddress(id: string) {
removeId.value = id
showAction.value = true
}
function deleteAddressMessage() {
API_Address.deleteAddress(removeId.value).then((res) => {
if (res.statusCode == 200) { if (res.statusCode == 200) {
uni.showToast({ uni.showToast({ icon: 'none', title: '删除成功' })
icon: "none", getAddressList()
title: "删除成功",
});
this.getAddressList();
} else { } else {
uni.showToast({ uni.showToast({ icon: 'none', title: res.data.message, duration: 2000 })
icon: "none",
title: res.data.message,
duration: 2000,
});
} }
}); })
}, }
//新建。编辑地址
addAddress(id) { function addAddress(id?: string) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/mine/address/add${id ? "?id=" + id : ""}`, url: `/pages/mine/address/add${id ? '?id=' + id : ''}`,
}); })
}, }
//设为默认地址
setDefault(item) {
delete item.updateBy;
delete item.updateTime;
delete item.deleteFlag;
item.isDefault ? "" : (item.isDefault = !item.isDefault);
function setDefault(item: any) {
delete item.updateBy
delete item.updateTime
delete item.deleteFlag
if (!item.isDefault) item.isDefault = true
API_Address.editAddress(item).then(() => { API_Address.editAddress(item).then(() => {
uni.showToast({ uni.showToast({ title: '设置默认地址成功', icon: 'none' })
title: "设置默认地址成功", getAddressList()
icon: "none", })
}); }
this.getAddressList();
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -20,67 +20,57 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import * as API_Trade from "@/api/trade"; import { ref } from 'vue'
import * as API_Store from "@/api/store.js"; import { onLoad, onShow, onPullDownRefresh } from '@dcloudio/uni-app'
export default { import { useStore } from '@/store'
data() { import * as API_Trade from '@/api/trade'
return { import * as API_Store from '@/api/store.js'
storeAddressList: [], //地址列表
showAction: false, //是否显示下栏框
removeList: [
{
text: "确定",
},
],
tips: {
text: "确定要删除该收货人信息吗?",
},
removeId: "", //删除的地址id
routerVal: "",
params: {
pageNumber: 1,
pageSize: 1000,
},
};
},
onPullDownRefresh() {
//下拉刷新
this.storeAddressList = [];
this.getAddressList();
},
onLoad: function (val) {
this.routerVal = val;
},
onShow() {
this.storeAddressList = [];
this.getAddressList();
},
onHide() {},
methods: {
async selectAddressData(val) {
await API_Trade.setStoreAddressId(val.id, this.routerVal.way);
uni.navigateBack({ const store = useStore()
delta: 1,
});
},
//获取地址列表
getAddressList() {
uni.showLoading();
API_Store.getStoreAddress( const storeAddressList = ref<any[]>([])
this.routerVal.storeId, const showAction = ref(false)
this.params const removeList = [{ text: '确定' }]
).then((res) => { const tips = { text: '确定要删除该收货人信息吗?' }
this.storeAddressList = res.data.result.records; const removeId = ref('')
console.log(this.storeAddressList); const routerVal = ref<Record<string, string>>({})
const params = { pageNumber: 1, pageSize: 1000 }
if (this.$store.state.isShowToast){ uni.hideLoading() }; onPullDownRefresh(() => {
}); storeAddressList.value = []
}, getAddressList()
}, })
};
onLoad((val) => {
routerVal.value = val || {}
})
onShow(() => {
storeAddressList.value = []
getAddressList()
})
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
}
async function selectAddressData(val: any) {
await API_Trade.setStoreAddressId(val.id, routerVal.value.way)
uni.navigateBack({ delta: 1 })
}
function getAddressList() {
uni.showLoading()
API_Store.getStoreAddress(routerVal.value.storeId, params).then((res) => {
storeAddressList.value = res.data.result.records
hideLoadingIfNeeded()
})
}
function deleteAddressMessage() {
// 保留 action-sheet 回调占位,当前页面无删除入口
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -52,84 +52,64 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getUserRecharge, getWalletLog, getUserWallet } from "@/api/members"; import { ref, onMounted } from 'vue'
export default { import { getWalletLog, getUserWallet } from '@/api/members'
data() { import { unitPrice } from '@/utils/filters.js'
return {
walletNum: 0, const walletNum = ref(0)
current: 0, const swiperCurrent = ref(0)
swiperCurrent: 0, const params = ref({
userInfo: "",
params: {
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
order: "desc", order: 'desc',
}, })
depositData: [], const depositData = ref<any[]>([])
rechargeList: "", const list = [{ name: '预存款变动明细' }]
walletLogList: "",
list: [{ name: "预存款变动明细" }], onMounted(async () => {
}; getWallet()
}, const result = await getUserWallet()
watch: { walletNum.value = result.data.result.memberWallet
swiperCurrent(index) { })
this.swiperCurrent = index;
}, function isOutgoing(serviceType: string) {
}, return serviceType === 'WALLET_PAY' || serviceType === 'WALLET_WITHDRAWAL'
async mounted() { }
this.getWallet();
const result = await getUserWallet(); function isIncoming(serviceType: string) {
this.walletNum = result.data.result.memberWallet;
},
methods: {
isOutgoing(serviceType) {
return serviceType === "WALLET_PAY" || serviceType === "WALLET_WITHDRAWAL";
},
isIncoming(serviceType) {
return ( return (
serviceType === "WALLET_REFUND" || serviceType === 'WALLET_REFUND' ||
serviceType === "WALLET_RECHARGE" || serviceType === 'WALLET_RECHARGE' ||
serviceType === "WALLET_COMMISSION" serviceType === 'WALLET_COMMISSION'
); )
},
getMoneyClass(serviceType) {
if (this.isOutgoing(serviceType)) return "out";
if (this.isIncoming(serviceType)) return "in";
return "";
},
formatLogMoney(logItem) {
const amount = this.unitPrice(logItem.money);
if (this.isOutgoing(logItem.serviceType)) return `-${amount}`;
if (this.isIncoming(logItem.serviceType)) return `+${amount}`;
return amount;
},
getRecharge() {
getUserRecharge(this.params).then((res) => {
if (res.data.success && res.data.result.records.length) {
this.depositData.push(...res.data.result.records);
} }
});
}, function getMoneyClass(serviceType: string) {
getWallet() { if (isOutgoing(serviceType)) return 'out'
getWalletLog(this.params).then((res) => { if (isIncoming(serviceType)) return 'in'
if (res.data.success && res.data.result.records.length) { return ''
this.depositData.push(...res.data.result.records); }
function formatLogMoney(logItem: any) {
const amount = unitPrice(logItem.money)
if (isOutgoing(logItem.serviceType)) return `-${amount}`
if (isIncoming(logItem.serviceType)) return `+${amount}`
return amount
}
function getWallet() {
getWalletLog(params.value).then((res) => {
if (res.data.success && res.data.result.records.length) {
depositData.value.push(...res.data.result.records)
}
})
}
function loadMore() {
params.value.pageNumber++
getWallet()
} }
});
},
changed(index) {
this.depositData = [];
this.swiperCurrent = index;
this.params.pageNumber = 1;
this.getWallet();
},
loadMore() {
this.params.pageNumber++;
this.getWallet();
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -12,8 +12,7 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default {};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -38,33 +38,30 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getUserWallet } from "@/api/members"; import { ref } from 'vue'
export default { import { onShow } from '@dcloudio/uni-app'
data() { import { getUserWallet } from '@/api/members'
return { import { isLogin, navigateToLogin, unitPrice } from '@/utils/filters.js'
walletNum: 0,
}; const walletNum = ref(0)
},
async onShow() { onShow(async () => {
if (this.isLogin("auth")) { if (isLogin('auth')) {
let result = await getUserWallet(); const result = await getUserWallet()
this.walletNum = result.data.result.memberWallet; walletNum.value = result.data.result.memberWallet
} else { } else {
this.navigateToLogin("redirectTo"); navigateToLogin('redirectTo')
}
})
function back() {
uni.switchTab({ url: '/pages/tabbar/user/my' })
}
function navigateTo(url: string) {
uni.navigateTo({ url })
} }
},
methods: {
back() {
uni.switchTab({
url: "/pages/tabbar/user/my",
});
},
navigateTo(url) {
uni.navigateTo({ url });
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -19,40 +19,30 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { recharge } from "@/api/members"; import { ref, watch } from 'vue'
export default { import { recharge } from '@/api/members'
data() {
return {
price: "",
flag: true,
};
},
watch: {
price(val) {
this.flag = !(Number(val) > 0);
},
},
methods: {
async handlerRecharge() {
const amount = Number(this.price);
if (!(amount > 0)) {
uni.showToast({
title: "请输入充值金额",
icon: "none",
});
return;
}
const res = await recharge({ price: amount }); const price = ref('')
const flag = ref(true)
watch(price, (val) => {
flag.value = !(Number(val) > 0)
})
async function handlerRecharge() {
const amount = Number(price.value)
if (!(amount > 0)) {
uni.showToast({ title: '请输入充值金额', icon: 'none' })
return
}
const res = await recharge({ price: amount })
if (res.data.success) { if (res.data.success) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/cart/payment/payOrder?orderType=RECHARGE&recharge_sn=${res.data.result.rechargeSn}`, url: `/pages/cart/payment/payOrder?orderType=RECHARGE&recharge_sn=${res.data.result.rechargeSn}`,
}); })
}
} }
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -25,182 +25,149 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getWithdrawApplyPage, getWithdrawApplyWechatTransferInfo } from "@/api/members"; import { ref } from 'vue'
export default { import { onShow } from '@dcloudio/uni-app'
data() { import { getWithdrawApplyPage, getWithdrawApplyWechatTransferInfo } from '@/api/members'
return { import { unitPrice } from '@/utils/filters.js'
loaded: false,
params: { const loaded = ref(false)
const params = ref({
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
order: "desc", order: 'desc',
}, })
records: [], const records = ref<any[]>([])
};
}, onShow(() => {
onShow() { params.value.pageNumber = 1
this.params.pageNumber = 1; records.value = []
this.records = []; loaded.value = false
this.loaded = false; getData()
this.getData(); })
},
methods: { function withdrawStatusText(applyStatus: string) {
withdrawStatusText(applyStatus) {
switch (applyStatus) { switch (applyStatus) {
case "APPLY": case 'APPLY':
return "申请中"; return '申请中'
case "VIA_AUDITING": case 'VIA_AUDITING':
return "审核通过"; return '审核通过'
case "D_VIA_AUDITING": case 'D_VIA_AUDITING':
return "分销提现审核通过"; return '分销提现审核通过'
case "FAIL_AUDITING": case 'FAIL_AUDITING':
return "审核未通过"; return '审核未通过'
case "D_FAIL_AUDITING": case 'D_FAIL_AUDITING':
return "分销提现审核未通过"; return '分销提现审核未通过'
case "WAIT_USER_CONFIRM": case 'WAIT_USER_CONFIRM':
return "等待用户确认"; return '等待用户确认'
case "SUCCESS": case 'SUCCESS':
return "提现成功"; return '提现成功'
case "ERROR": case 'ERROR':
return "提现失败"; return '提现失败'
default: default:
return applyStatus || ""; return applyStatus || ''
} }
},
getData() {
getWithdrawApplyPage(this.params).then((res) => {
this.loaded = true;
if (res.data.success) {
if (res.data.result.records.length != 0) {
this.records.push(...res.data.result.records);
}
}
});
},
loadMore() {
this.params.pageNumber++;
this.getData();
},
confirmWechatReceive(item) {
const id = item && item.id;
if (!id) {
uni.showToast({
title: "缺少提现记录ID",
duration: 2000,
icon: "none",
});
return;
} }
uni.showLoading({ function getData() {
title: "加载中", getWithdrawApplyPage(params.value).then((res) => {
}); loaded.value = true
if (res.data.success && res.data.result.records.length != 0) {
records.value.push(...res.data.result.records)
}
})
}
function loadMore() {
params.value.pageNumber++
getData()
}
function confirmWechatReceive(item: any) {
const id = item && item.id
if (!id) {
uni.showToast({ title: '缺少提现记录ID', duration: 2000, icon: 'none' })
return
}
uni.showLoading({ title: '加载中' })
getWithdrawApplyWechatTransferInfo(id) getWithdrawApplyWechatTransferInfo(id)
.then((res) => { .then((res) => {
if (!res.data || !res.data.success) return; if (!res.data || !res.data.success) return
const info = res.data.result || {}; const info = res.data.result || {}
const mchId = info.mchId; const mchId = info.mchId
const wechatPackage = info.wechatPackage; const wechatPackage = info.wechatPackage
let appId = info.appId; let appId = info.appId
if (typeof wx !== "undefined" && wx.getAccountInfoSync) { if (typeof wx !== 'undefined' && wx.getAccountInfoSync) {
try { try {
const accountInfo = wx.getAccountInfoSync(); const accountInfo = wx.getAccountInfoSync()
const mpAppId = accountInfo && accountInfo.miniProgram && accountInfo.miniProgram.appId; const mpAppId = accountInfo && accountInfo.miniProgram && accountInfo.miniProgram.appId
if (mpAppId) appId = mpAppId; if (mpAppId) appId = mpAppId
} catch (e) {} } catch (e) {}
} }
if (!mchId || !appId || !wechatPackage) { if (!mchId || !appId || !wechatPackage) {
uni.showToast({ uni.showToast({ title: '微信确认参数缺失', duration: 2000, icon: 'none' })
title: "微信确认参数缺失", return
duration: 2000,
icon: "none",
});
return;
} }
const openResultToast = (errMsg) => { const openResultToast = (errMsg?: string) => {
if (errMsg === "requestMerchantTransfer:ok") { if (errMsg === 'requestMerchantTransfer:ok') {
uni.showToast({ uni.showToast({ title: '已唤起确认页面', duration: 2000, icon: 'none' })
title: "已唤起确认页面", return
duration: 2000,
icon: "none",
});
return;
} }
if (errMsg === "requestMerchantTransfer:cancel") { if (errMsg === 'requestMerchantTransfer:cancel') {
uni.showToast({ uni.showToast({ title: '已取消', duration: 2000, icon: 'none' })
title: "已取消", return
duration: 2000,
icon: "none",
});
return;
} }
uni.showToast({ uni.showToast({
title: errMsg ? `唤起失败:${errMsg}` : "唤起失败", title: errMsg ? `唤起失败:${errMsg}` : '唤起失败',
duration: 2500, duration: 2500,
icon: "none", icon: 'none',
}); })
}; }
if (typeof wx !== "undefined" && wx.getSystemInfoSync) { if (typeof wx !== 'undefined' && wx.getSystemInfoSync) {
try { try {
const sys = wx.getSystemInfoSync(); const sys = wx.getSystemInfoSync()
if (sys && sys.platform === "devtools") { if (sys && sys.platform === 'devtools') {
uni.showToast({ uni.showToast({
title: "开发者工具可能不支持,请真机测试", title: '开发者工具可能不支持,请真机测试',
duration: 2500, duration: 2500,
icon: "none", icon: 'none',
}); })
} }
} catch (e) {} } catch (e) {}
} }
if (typeof wx !== "undefined" && wx.canIUse && wx.canIUse("requestMerchantTransfer")) { if (typeof wx !== 'undefined' && wx.canIUse && wx.canIUse('requestMerchantTransfer')) {
wx.requestMerchantTransfer({ wx.requestMerchantTransfer({
mchId, mchId,
appId, appId,
package: wechatPackage, package: wechatPackage,
success: (r) => { success: (r: any) => openResultToast(r && (r.errMsg || r.err_msg)),
openResultToast(r && (r.errMsg || r.err_msg)); fail: (r: any) => openResultToast(r && (r.errMsg || r.err_msg)),
}, })
fail: (r) => { return
openResultToast(r && (r.errMsg || r.err_msg));
},
});
return;
} }
if (typeof WeixinJSBridge !== "undefined" && WeixinJSBridge.invoke) { if (typeof WeixinJSBridge !== 'undefined' && WeixinJSBridge.invoke) {
WeixinJSBridge.invoke( WeixinJSBridge.invoke(
"requestMerchantTransfer", 'requestMerchantTransfer',
{ { mchId, appId, package: wechatPackage },
mchId, (r: any) => openResultToast(r && (r.errMsg || r.err_msg))
appId, )
package: wechatPackage, return
},
(r) => {
openResultToast(r && (r.errMsg || r.err_msg));
}
);
return;
} }
uni.showToast({ uni.showToast({ title: '请在微信内打开确认收款', duration: 2000, icon: 'none' })
title: "请在微信内打开确认收款",
duration: 2000,
icon: "none",
});
}) })
.finally(() => { .finally(() => {
uni.hideLoading(); uni.hideLoading()
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -58,77 +58,68 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getUserWallet, withdrawalApply, withdrawalSettingVO } from "@/api/members"; import { ref, computed, getCurrentInstance, onMounted } from 'vue'
export default { import { getUserWallet, withdrawalApply, withdrawalSettingVO } from '@/api/members'
data() { import { unitPrice } from '@/utils/filters.js'
return {
price: "", const { proxy } = getCurrentInstance()!
walletNum: 0,
minPrice: 0, const price = ref('')
type: "", const walletNum = ref(0)
connectNumber: "", const minPrice = ref(0)
realName: "", const type = ref('')
}; const connectNumber = ref('')
}, const realName = ref('')
computed: {
typeLabel() { const typeLabel = computed(() => {
if (this.type === "ALI") return "支付宝"; if (type.value === 'ALI') return '支付宝'
if (this.type) return "微信"; if (type.value) return '微信'
return "--"; return '--'
}, })
},
async mounted() { onMounted(async () => {
const result = await getUserWallet(); const result = await getUserWallet()
const res = await withdrawalSettingVO(); const res = await withdrawalSettingVO()
this.walletNum = result.data.result.memberWallet; walletNum.value = result.data.result.memberWallet
this.minPrice = res.data.result.minPrice; minPrice.value = res.data.result.minPrice
this.type = res.data.result.type; type.value = res.data.result.type
}, })
methods: {
cashd() { function cashd() {
const amount = Number(this.price); const amount = Number(price.value)
if (!this.$u.test.amount(parseInt(amount))) { if (!proxy.$u.test.amount(parseInt(String(amount)))) {
uni.showToast({ uni.showToast({ title: '请输入正确金额', duration: 2000, icon: 'none' })
title: "请输入正确金额", return
duration: 2000,
icon: "none",
});
return;
} }
const params = { price: amount }; const params: Record<string, any> = { price: amount }
if (this.type === "ALI") { if (type.value === 'ALI') {
if (!this.connectNumber || !this.realName) { if (!connectNumber.value || !realName.value) {
uni.showToast({ uni.showToast({
title: "请输入真实姓名和第三方登录账号", title: '请输入真实姓名和第三方登录账号',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return; return
} }
params.connectNumber = this.connectNumber; params.connectNumber = connectNumber.value
params.realName = this.realName; params.realName = realName.value
} }
withdrawalApply(params).then((res) => { withdrawalApply(params).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({ title: '提现成功!', duration: 2000, icon: 'none' })
title: "提现成功!",
duration: 2000,
icon: "none",
});
setTimeout(() => { setTimeout(() => {
uni.navigateBack({ delta: 1 }); uni.navigateBack({ delta: 1 })
}, 1000); }, 1000)
}
})
}
function handleAll() {
price.value = String(walletNum.value || '')
} }
});
},
handleAll() {
this.price = String(this.walletNum || "");
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,11 +1,10 @@
<template> <template>
<view></view>
</template> </template>
<script>
export default {
} <script setup lang="ts">
// 占位页,暂无业务逻辑
</script> </script>
<style lang="scss" scoped>
<style lang="scss" scoped>
</style> </style>

View File

@@ -3,160 +3,100 @@
<view> <view>
<h4>实名认证请上传真实的个人信息认证通过后将无法修改</h4> <h4>实名认证请上传真实的个人信息认证通过后将无法修改</h4>
<view> <view>
<u-form :model="ruleForm" label-width="200rpx" ref="uForm"> <up-form
<u-form-item label="姓名" prop="name"> :model="formData"
<u-input v-model="ruleForm.name" placeholder="请输入您的真实姓名" /> label-position="left"
</u-form-item> label-width="180rpx"
<u-form-item label="身份证" prop="idNumber"> ref="uFormRef"
<u-input v-model="ruleForm.idNumber" placeholder="请输入身份证号码" /> >
</u-form-item> <up-form-item label="姓名" prop="name">
<u-form-item label="银行开户行" prop="settlementBankBranchName"> <u-input v-model="formData.name" placeholder="请输入您的真实姓名" />
<u-input v-model="ruleForm.settlementBankBranchName" type="text" placeholder="请输入银行开户行" /> </up-form-item>
</u-form-item> <up-form-item label="身份证" prop="idNumber">
<u-form-item label="银行开户名" prop="settlementBankAccountName"> <u-input v-model="formData.idNumber" placeholder="请输入身份证号码" />
<u-input v-model="ruleForm.settlementBankAccountName" type="text" placeholder="请输入银行开户名" /> </up-form-item>
</u-form-item> <up-form-item label="银行开户行" prop="settlementBankBranchName">
<u-form-item label="银行账号" prop="settlementBankAccountNum"> <u-input v-model="formData.settlementBankBranchName" placeholder="请输入银行开户行" />
<u-input v-model="ruleForm.settlementBankAccountNum" type="text" placeholder="请输入银行账号" /> </up-form-item>
</u-form-item> <up-form-item label="银行开户名" prop="settlementBankAccountName">
<!-- <u-form-item label="身份证正面照" prop="name"> <u-input v-model="formData.settlementBankAccountName" placeholder="请输入银行开户名" />
<u-upload></u-upload> </up-form-item>
</u-form-item> <up-form-item label="银行账号" prop="settlementBankAccountNum">
<u-form-item label="身份证反面照" prop="name"> <u-input v-model="formData.settlementBankAccountNum" placeholder="请输入银行账号" />
<u-upload></u-upload> </up-form-item>
</u-form-item> </up-form>
<u-form-item label="手持身份证照" prop="name"> <u-button :customStyle="{ background: lightColor, color: '#fff' }" @click="submitForm">提交</u-button>
<u-upload></u-upload>
</u-form-item> -->
</u-form>
<u-button :customStyle="{'background':$lightColor,'color':'#fff' }" @click="submit">提交</u-button>
</view> </view>
</view> </view>
<view class="tips"> <view class="tips">
<view>您提交的信息正在审核</view> <view>您提交的信息正在审核</view>
<view>提交认证申请后工作人员将在三个工作日进行核对完成审核</view> <view>提交认证申请后工作人员将在三个工作日进行核对完成审核</view>
</view> </view>
</view> </view>
</template> </template>
<script>
import { applyDistribution } from "@/api/goods";
export default {
data() {
return {
ruleForm: {
name: "",
idNumber: "",
settlementBankBranchName: "", // 银行开户行
settlementBankAccountName: "", //银行开户名
settlementBankAccountNum: "", //银行账号
},
rules: {
name: [
{
required: true,
message: "请输入姓名",
// 可以单个或者同时写两个触发验证方式
trigger: "blur",
},
{
// 自定义验证函数,见上说明
validator: (rule, value, callback) => {
// 上面有说返回true表示校验通过返回false表示不通过
// this.$u.test.mobile()就是返回true或者false的
return this.$u.test.chinese(value);
},
message: "姓名输入不正确",
// 触发器可以同时用blur和change
trigger: ["change", "blur"],
},
],
// 银行开户行
settlementBankBranchName: [
{
required: true,
message: "请输入银行开户行",
// 可以单个或者同时写两个触发验证方式
trigger: "blur",
},
], //银行开户名
settlementBankAccountName: [
{
required: true,
message: "银行开户名",
// 可以单个或者同时写两个触发验证方式
trigger: "blur",
},
],
//银行账号
settlementBankAccountNum: [
{
required: true,
message: "请输入银行账号",
// 可以单个或者同时写两个触发验证方式
trigger: "blur",
},
],
idNumber: [
{
required: true,
message: "请输入身份证",
// 可以单个或者同时写两个触发验证方式
trigger: "blur",
},
{
// 自定义验证函数,见上说明
validator: (rule, value, callback) => {
// 上面有说返回true表示校验通过返回false表示不通过
// this.$u.test.mobile()就是返回true或者false的
return this.$u.test.idCard(value);
},
message: "身份证号码不正确",
// 触发器可以同时用blur和change
trigger: ["change", "blur"],
},
],
},
};
},
methods: {
submit() {
this.$refs.uForm.validate((valid) => {
if (valid) {
applyDistribution(this.ruleForm).then((res) => {
if (res.data.success) {
uni.showToast({
title: "认证提交成功!",
duration: 2000,
icon: "none",
});
setTimeout(() => { <script setup lang="ts">
uni.navigateBack(); import { reactive, computed, ref, getCurrentInstance } from 'vue'
}, 500); import { onReady } from '@dcloudio/uni-app'
} else { import { useStore } from '@/store'
uni.showToast({ import { applyDistribution } from '@/api/goods'
title: res.data.message,
duration: 2000, const store = useStore()
icon: "none", const { proxy } = getCurrentInstance()!
});
const lightColor = computed(() => store.getters.lightColor)
const uFormRef = ref<any>(null)
const formData = reactive({
name: '',
idNumber: '',
settlementBankBranchName: '',
settlementBankAccountName: '',
settlementBankAccountNum: '',
})
const rules = {
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' },
{
validator: (_rule: unknown, value: string) => proxy.$u.test.chinese(value),
message: '姓名输入不正确',
trigger: ['change', 'blur'],
},
],
settlementBankBranchName: [{ required: true, message: '请输入银行开户行', trigger: 'blur' }],
settlementBankAccountName: [{ required: true, message: '银行开户名', trigger: 'blur' }],
settlementBankAccountNum: [{ required: true, message: '请输入银行账号', trigger: 'blur' }],
idNumber: [
{ required: true, message: '请输入身份证', trigger: 'blur' },
{
validator: (_rule: unknown, value: string) => proxy.$u.test.idCard(value),
message: '身份证号码不正确',
trigger: ['change', 'blur'],
},
],
} }
});
onReady(() => {
uFormRef.value?.setRules(rules)
})
function submitForm() {
uFormRef.value?.validate().then(() => {
applyDistribution(formData).then((res) => {
if (res.data.success) {
uni.showToast({ title: '认证提交成功!', duration: 2000, icon: 'none' })
setTimeout(() => uni.navigateBack(), 500)
} else { } else {
uni.showToast({ uni.showToast({ title: res.data.message, duration: 2000, icon: 'none' })
title: "请填写有效信息", }
duration: 2000, })
icon: "none", }).catch(() => {
}); uni.showToast({ title: '请填写有效信息', duration: 2000, icon: 'none' })
})
} }
});
},
},
onReady() {
this.$refs.uForm.setRules(this.rules);
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.wrapper { .wrapper {
padding: 32rpx; padding: 32rpx;

View File

@@ -1,26 +1,34 @@
<template> <template>
<view class="log-list"> <view class="log-list">
<!-- 提现记录 --> <view
<view class="log-way" v-if="cashLogData.length != 0" v-for="(item, index) in cashLogData" :key="index"> class="log-way"
v-if="withdrawLogList.length != 0"
v-for="(item, index) in withdrawLogList"
:key="'cash-' + index"
>
<view class="log-item"> <view class="log-item">
<view class="log-item-view"> <view class="log-item-view">
<view class="title">{{ <view class="title">{{
item.distributionCashStatus == "APPLY" item.distributionCashStatus == 'APPLY'
? "待处理" ? '待处理'
: item.distributionCashStatus == "VIA_AUDITING" : item.distributionCashStatus == 'VIA_AUDITING'
? "通过" ? '通过'
: "拒绝" : '拒绝'
}}</view> }}</view>
<view class="price">+{{ unitPrice(item.price) }}</view> <view class="price">+{{ unitPrice(item.price) }}</view>
</view> </view>
<view class="log-item-view"> <view class="log-item-view">
<view>{{ item.createTime }}</view> <view>{{ item.createTime }}</view>
<view></view>
</view> </view>
</view> </view>
</view> </view>
<!-- 分销业绩 -->
<view class="log-way" v-if="achievementData.length != 0" v-for="(item, index) in achievementData" :key="index"> <view
class="log-way"
v-if="achievementList.length != 0"
v-for="(item, index) in achievementList"
:key="'ach-' + index"
>
<view class="log-item"> <view class="log-item">
<view class="log-item-view"> <view class="log-item-view">
<view class="title">{{ item.goodsName }}</view> <view class="title">{{ item.goodsName }}</view>
@@ -38,101 +46,98 @@
</view> </view>
</view> </view>
</view> </view>
<view class="empty" v-if="empty">
<u-loadmore :status="status" :icon-type="iconType" bg-color="#f7f7f7" /> <view class="empty" v-if="isEmpty">
<u-loadmore :status="loadStatus" :icon-type="iconType" bg-color="#f7f7f7" />
</view> </view>
</view> </view>
</template> </template>
<script>
import { cashLog, distributionOrderList } from "@/api/goods";
export default {
data () {
return {
cashLogData: [], //提现记录数据集合
achievementData: [], //分销业绩数据合集,
status: "loadmore",
iconType: "flower",
empty: false,
params: {
pageNumber: 1,
pageSize: 10,
},
type: 0, <script setup lang="ts">
routers: "", import { ref } from 'vue'
achParams: { import { onLoad, onReachBottom } from '@dcloudio/uni-app'
pageNumber: 1, import { useStore } from '@/store'
pageSize: 10, import { cashLog, distributionOrderList } from '@/api/goods'
}, import { unitPrice } from '@/utils/filters.js'
};
},
onLoad (option) {
let title;
option.type == 0 ? (title = "分销业绩") : (title = "提现记录");
const store = useStore()
const withdrawLogList = ref<any[]>([])
const achievementList = ref<any[]>([])
const loadStatus = ref('loadmore')
const iconType = ref('flower')
const isEmpty = ref(false)
const listType = ref(0)
const routeQuery = ref<Record<string, string>>({})
const withdrawParams = ref({ pageNumber: 1, pageSize: 10 })
const achievementParams = ref({ pageNumber: 1, pageSize: 10 })
onLoad((option) => {
const type = Number(option.type ?? 0)
listType.value = type
routeQuery.value = option || {}
uni.setNavigationBarTitle({ uni.setNavigationBarTitle({
title: title, //这是修改后的导航栏文字 title: type === 0 ? '分销业绩' : '提现记录',
}); })
this.routers = option; type === 0 ? fetchAchievementList() : fetchWithdrawLog()
this.type = option.type; })
option.type == 0 ? this.achievement() : this.history();
}, onReachBottom(() => {
mounted () { }, loadStatus.value = 'loading'
onReachBottom () { if (listType.value === 0) {
this.status = "loading"; achievementParams.value.pageNumber++
this.type == 0 ? this.achParams.pageNumber++ : this.params.pageNumber++; fetchAchievementList()
this.type == 0 ? this.achievement() : this.history();
},
methods: {
// 业绩
achievement () {
uni.showLoading({
title: "加载中",
});
distributionOrderList(this.achParams).then((res) => {
if (res.data.success && res.data.result.records.length >= 1) {
this.achievementData.push(...res.data.result.records);
} else { } else {
this.status = "nomore"; withdrawParams.value.pageNumber++
this.empty = true; fetchWithdrawLog()
} }
if (this.$store.state.isShowToast){ uni.hideLoading() }; })
});
}, function hideLoadingIfNeeded() {
// 初始化提现历史 if (store.state.isShowToast) uni.hideLoading()
history () { }
uni.showLoading({
title: "加载中", function fetchAchievementList() {
}); uni.showLoading({ title: '加载中' })
cashLog(this.params).then((res) => { distributionOrderList(achievementParams.value).then((res) => {
if (res.data.success && res.data.result.records.length >= 1) { if (res.data.success && res.data.result.records.length >= 1) {
this.cashLogData.push(...res.data.result.records); achievementList.value.push(...res.data.result.records)
} else { } else {
this.status = "nomore"; loadStatus.value = 'nomore'
this.empty = true; isEmpty.value = true
}
hideLoadingIfNeeded()
})
}
function fetchWithdrawLog() {
uni.showLoading({ title: '加载中' })
cashLog(withdrawParams.value).then((res) => {
if (res.data.success && res.data.result.records.length >= 1) {
withdrawLogList.value.push(...res.data.result.records)
} else {
loadStatus.value = 'nomore'
isEmpty.value = true
}
hideLoadingIfNeeded()
})
} }
if (this.$store.state.isShowToast){ uni.hideLoading() };
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.empty { .empty {
margin: 40rpx 0; margin: 40rpx 0;
} }
.price { .price {
color: $main-color; color: $main-color;
font-weight: bold; font-weight: bold;
} }
.log-list { .log-list {
padding: 0 8rpx; padding: 0 8rpx;
overflow: hidden; overflow: hidden;
margin: 20rpx 0; margin: 20rpx 0;
} }
.log-way { .log-way {
margin: 10rpx 0; margin: 10rpx 0;
overflow: hidden; overflow: hidden;
@@ -140,26 +145,17 @@ export default {
border-radius: 10rpx; border-radius: 10rpx;
padding: 20rpx 0; padding: 20rpx 0;
} }
.title { .title {
font-size: 30rpx; font-size: 30rpx;
font-weight: bold; font-weight: bold;
} }
.log-item-view { .log-item-view {
padding: 8rpx 32rpx; padding: 8rpx 32rpx;
display: flex; display: flex;
font-size: 13px; font-size: 13px;
justify-content: space-between; justify-content: space-between;
} }
.log-item-footer,
.log-item-footer {
padding: 8rpx 32rpx;
display: flex;
font-size: 13px;
justify-content: space-between;
}
.log-item-footers { .log-item-footers {
padding: 8rpx 32rpx; padding: 8rpx 32rpx;
display: flex; display: flex;

View File

@@ -1,18 +1,15 @@
<template> <template>
<view> <view>
<view class="nav-list"> <view class="nav-list">
<view class="total">可提现金额</view> <view class="total">可提现金额</view>
<view class="price">{{ unitPrice(distributionData.canRebate) }}</view> <view class="price">{{ unitPrice(distributionData.canRebate) }}</view>
<view class="frozen" <view class="frozen">冻结金额{{ unitPrice(distributionData.commissionFrozen) }}</view>
>冻结金额{{unitPrice(distributionData.commissionFrozen) }}</view
>
</view> </view>
<view class="nav"> <view class="nav">
<view class="nav-item"> <view class="nav-item">
<u-icon <u-icon
size="50" size="50"
@click="handleClick('/pages/mine/distribution/list?id='+distributionData.id+'&name='+distributionData.memberName)" @click="navigateTo(`/pages/mine/distribution/list?id=${distributionData.id}&name=${distributionData.memberName}`)"
color="#ff6b35" color="#ff6b35"
name="bag-fill" name="bag-fill"
></u-icon> ></u-icon>
@@ -20,72 +17,54 @@
</view> </view>
<view <view
class="nav-item" class="nav-item"
@click="handleClick(`/pages/mine/distribution/history?type=0&id=${distributionData.id}&name=${distributionData.memberName}`)" @click="navigateTo(`/pages/mine/distribution/history?type=0&id=${distributionData.id}&name=${distributionData.memberName}`)"
> >
<u-icon size="50" color="#ff6b35" name="order"></u-icon> <u-icon size="50" color="#ff6b35" name="order"></u-icon>
<view>分销业绩</view> <view>分销业绩</view>
</view> </view>
<view <view class="nav-item" @click="navigateTo('/pages/mine/distribution/history?type=1')">
class="nav-item"
@click="handleClick('/pages/mine/distribution/history?type=1')"
>
<u-icon size="50" color="#ff6b35" name="red-packet-fill"></u-icon> <u-icon size="50" color="#ff6b35" name="red-packet-fill"></u-icon>
<view>提现记录</view> <view>提现记录</view>
</view> </view>
<view <view class="nav-item" @click="navigateTo('/pages/mine/distribution/withdrawal')">
class="nav-item"
@click="handleClick('/pages/mine/distribution/withdrawal')"
>
<u-icon size="50" color="#ffc71c" name="rmb-circle-fill"></u-icon> <u-icon size="50" color="#ffc71c" name="rmb-circle-fill"></u-icon>
<view>提现</view> <view>提现</view>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { ref } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { distribution } from '@/api/goods'
import { unitPrice } from '@/utils/filters.js'
import { distribution } from "@/api/goods"; const store = useStore()
export default { const distributionData = ref<Record<string, any>>({})
data() { onShow(() => {
return { fetchDistributionInfo()
distributionData: "", })
};
}, function hideLoadingIfNeeded() {
methods: { if (store.state.isShowToast) uni.hideLoading()
handleClick(url) { }
uni.navigateTo({
url, function navigateTo(url: string) {
}); uni.navigateTo({ url })
}, }
queryGoods(src) {
uni.navigateTo({ function fetchDistributionInfo() {
url: `/pages/mine/distribution/${src}`, uni.showLoading({ title: '加载中' })
});
},
/**
* 初始化推广商品
*/
init() {
uni.showLoading({
title: "加载中",
});
distribution().then((res) => { distribution().then((res) => {
if (res.data.result) { if (res.data.result) {
this.distributionData = res.data.result; distributionData.value = res.data.result
}
hideLoadingIfNeeded()
})
} }
if (this.$store.state.isShowToast){ uni.hideLoading() };
});
},
},
onShow() {
this.init();
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -124,6 +103,5 @@ export default {
justify-content: center; justify-content: center;
gap: 20rpx; gap: 20rpx;
width: 33%; width: 33%;
// color: #fff;
} }
</style> </style>

View File

@@ -1,104 +1,127 @@
<template> <template>
<view class="wrapper"> <view class="wrapper" :style="themeStyle">
<u-tabs <u-tabs
:list="list" :list="stepList"
:scrollable="false" :scrollable="false"
v-model:current="current" v-model:current="currentStep"
:lineColor="lightColor" :lineColor="lightColor"
:activeStyle="{ color: lightColor }" :activeStyle="{ color: lightColor }"
></u-tabs> ></u-tabs>
<view class="feedBack-box">
<up-form
<!-- 推广人资料 --> :model="formData"
<view class="message"> label-position="top"
<u-form :model="ruleForm" label-width="250rpx" ref="uForm"> ref="uFormRef"
<u-form-item label="会员昵称" prop="name"> >
<u-input v-model="ruleForm.name" /> <up-form-item label="会员昵称" prop="name">
</u-form-item> <u-input
<u-form-item label="账户类型" prop="name"> </u-form-item> border="none"
<u-form-item class="field-input"
label="收款人姓名" v-model="formData.name"
:custom-style="fieldInputStyle"
/>
</up-form-item>
<up-form-item label="账户类型" prop="name"></up-form-item>
<up-form-item label="收款人姓名" prop="name">
<u-input
border="none"
class="field-input"
v-model="formData.name"
placeholder="请输入收款人姓名" placeholder="请输入收款人姓名"
prop="name" :custom-style="fieldInputStyle"
> />
<u-input v-model="ruleForm.name" /> </up-form-item>
</u-form-item> <up-form-item label="收款账号" prop="name">
<u-form-item <u-input
label="收款账号" border="none"
class="field-input"
v-model="formData.name"
placeholder="请输入收款人账号" placeholder="请输入收款人账号"
prop="name" :custom-style="fieldInputStyle"
> />
<u-input v-model="ruleForm.name" /> </up-form-item>
</u-form-item> <up-form-item label="银行名称" prop="name">
<u-form-item <u-input
label="银行名称" border="none"
class="field-input"
v-model="formData.name"
placeholder="请输入开户银行支行名称" placeholder="请输入开户银行支行名称"
prop="name" :custom-style="fieldInputStyle"
> />
<u-input v-model="ruleForm.name" /> </up-form-item>
</u-form-item> </up-form>
</u-form>
<u-button :customStyle="{'background':$lightColor,'color':'#fff' }" @click="submit">提交</u-button>
</view> </view>
<view class="submit" @click="submitForm">提交</view>
</view> </view>
</template> </template>
<script>
export default { <script setup lang="ts">
components: {}, import { ref, reactive, computed } from 'vue'
// 必须要在onReady生命周期因为onLoad生命周期组件可能尚未创建完毕 import { onReady } from '@dcloudio/uni-app'
onReady() { import { useStore } from '@/store'
this.$refs.uForm.setRules(this.rules); import { getThemeStyle } from '@/utils/theme'
}, import { fieldInputStyle } from '@/utils/form-style.js'
data() {
return { const store = useStore()
current:0,
lightColor: this.$lightColor, const themeStyle = computed(() => getThemeStyle(store.state.theme))
list: [ const lightColor = computed(() => store.getters.lightColor)
{ const currentStep = ref(0)
name: "推广人资料", const uFormRef = ref<any>(null)
},
{ const stepList = [
name: "平台审核", { name: '推广人资料' },
}, { name: '平台审核' },
{ { name: '完成' },
name: "完成", ]
},
], const formData = reactive({
ruleForm: { name: '',
name: "", radio: '',
radio: "", })
},
rules: { const rules = {
name: [ name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
{ }
required: true,
message: "请输入姓名", onReady(() => {
// 可以单个或者同时写两个触发验证方式 uFormRef.value?.setRules(rules)
trigger: "blur", })
},
], function submitForm() {
}, uFormRef.value?.validate().catch(() => {
}; uni.showToast({ title: '请填写有效信息', icon: 'none' })
}, })
}; }
</script> </script>
<style lang="scss" scoped>
.menu { <style lang="scss">
height: 88rpx; page {
line-height: 88rpx; background: #f8f8f8;
background: $main-color; }
display: flex; </style>
> .menu-item {
flex: 1; <style lang="scss" scoped>
text-align: center; @import '@/pages/passport/entry/seller/entry-form.scss';
color: $light-color;
} .wrapper {
} box-sizing: border-box;
.active { min-height: 100vh;
color: #fff !important; padding: 20rpx 24rpx 40rpx;
} background: #f8f8f8;
.message { @include seller-entry-form;
padding: 0 32rpx; }
.feedBack-box {
background: #fff;
border-radius: 20rpx;
padding: 32rpx;
margin-top: 20rpx;
}
.submit {
@include seller-entry-submit;
} }
</style> </style>

View File

@@ -58,44 +58,44 @@
<!-- 导航栏 --> <!-- 导航栏 -->
<view class="nav"> <view class="nav">
<view class="nav-item" @click="handleMyGoods(true)" :class="{ checked: params.checked }">已选择</view> <view class="nav-item" @click="toggleGoodsTab(true)" :class="{ checked: queryParams.checked }">已选择</view>
<view class="nav-item" @click="handleMyGoods(false)" :class="{ checked: !params.checked }">未选择</view> <view class="nav-item" @click="toggleGoodsTab(false)" :class="{ checked: !queryParams.checked }">未选择</view>
<!-- <view class="nav-item" @click="popup = !popup">筛选</view> --> <!-- <view class="nav-item" @click="popup = !popup">筛选</view> -->
</view> </view>
<!-- 商品列表 --> <!-- 商品列表 -->
<view class="goods-list"> <view class="goods-list">
<scroll-view class="body-view" scroll-y @scrolltolower="renderDate"> <scroll-view class="body-view" scroll-y @scrolltolower="loadMore">
<block v-for="(item, index) in goodsList" :key="item.id"> <block v-for="(item, index) in goodsList" :key="item.id">
<u-swipe-action v-if="params.checked" class="distribution-swipe"> <u-swipe-action v-if="queryParams.checked" class="distribution-swipe">
<u-swipe-action-item <u-swipe-action-item
:show="item.___selected" :show="item.___selected"
@open="openAction(item)" @open="openSwipeAction(item)"
:name="index" :name="index"
:options="options" :options="swipeOptions"
@click="changeActionTab(item)" @click="confirmUnbindPrompt(item)"
> >
<view class="goods-item"> <view class="goods-item">
<view class="goods-item-img" @click="handleNavgationGoods(item)"> <view class="goods-item-img" @click="navigateToGoods(item)">
<u-image width="176rpx" height="176rpx" :src="item.thumbnail"></u-image> <u-image width="176rpx" height="176rpx" :src="item.thumbnail"></u-image>
</view> </view>
<view class="goods-item-desc"> <view class="goods-item-desc">
<view class="-item-title" @click="handleNavgationGoods(item)"> <view class="-item-title" @click="navigateToGoods(item)">
{{ item.goodsName }} {{ item.goodsName }}
</view> </view>
<view class="-item-price" @click="handleNavgationGoods(item)"> <view class="-item-price" @click="navigateToGoods(item)">
佣金: 佣金:
<span> {{ unitPrice(item.commission) }}</span> <span> {{ unitPrice(item.commission) }}</span>
</view> </view>
<view class="-item-bottom"> <view class="-item-bottom">
<view class="-item-bootom-money" @click="handleNavgationGoods(item)"> <view class="-item-bootom-money" @click="navigateToGoods(item)">
<view class="-item-yj"> <view class="-item-yj">
<span>{{ unitPrice(item.price) }}</span> <span>{{ unitPrice(item.price) }}</span>
</view> </view>
</view> </view>
<view> <view>
<view class="click" @click="handleLink(item)">分销商品</view> <view class="click" @click="shareDistributionGoods(item)">分销商品</view>
</view> </view>
</view> </view>
</view> </view>
@@ -104,25 +104,25 @@
</u-swipe-action> </u-swipe-action>
<view v-else class="goods-item"> <view v-else class="goods-item">
<view class="goods-item-img" @click="handleNavgationGoods(item)"> <view class="goods-item-img" @click="navigateToGoods(item)">
<u-image width="176rpx" height="176rpx" :src="item.thumbnail"></u-image> <u-image width="176rpx" height="176rpx" :src="item.thumbnail"></u-image>
</view> </view>
<view class="goods-item-desc"> <view class="goods-item-desc">
<view class="-item-title" @click="handleNavgationGoods(item)"> <view class="-item-title" @click="navigateToGoods(item)">
{{ item.goodsName }} {{ item.goodsName }}
</view> </view>
<view class="-item-price" @click="handleNavgationGoods(item)"> <view class="-item-price" @click="navigateToGoods(item)">
佣金: 佣金:
<span> {{ unitPrice(item.commission) }}</span> <span> {{ unitPrice(item.commission) }}</span>
</view> </view>
<view class="-item-bottom"> <view class="-item-bottom">
<view class="-item-bootom-money" @click="handleNavgationGoods(item)"> <view class="-item-bootom-money" @click="navigateToGoods(item)">
<view class="-item-yj"> <view class="-item-yj">
<span>{{ unitPrice(item.price) }}</span> <span>{{ unitPrice(item.price) }}</span>
</view> </view>
</view> </view>
<view> <view>
<view class="click" @click="handleClickGoods(item)">立即选取</view> <view class="click" @click="selectGoods(item)">立即选取</view>
</view> </view>
</view> </view>
</view> </view>
@@ -136,210 +136,164 @@
</view> </view>
</view> </view>
<canvas class="canvas-hide" canvas-id="qrcode" /> <canvas class="canvas-hide" canvas-id="qrcode" />
<drawCanvas ref="drawCanvas" v-if="showFlag" :res="res" /> <drawCanvas ref="drawCanvasRef" v-if="showPoster" :res="posterData" />
<u-modal v-model:show="deleteShow" :confirm-style="{'color':lightColor}" @confirm="delectConfirm" show-cancel-button :content="deleteContent" :async-close="true"></u-modal> <u-modal
v-model:show="showUnbindModal"
:confirm-style="{ color: lightColor }"
@confirm="confirmUnbind"
show-cancel-button
:content="unbindModalContent"
:async-close="true"
></u-modal>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { ref, computed } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { import {
distributionGoods, distributionGoods,
checkedDistributionGoods, checkedDistributionGoods,
getMpCode, getMpCode,
} from "@/api/goods"; } from '@/api/goods'
import drawCanvas from '@/components/m-canvas'
import { unitPrice } from '@/utils/filters.js'
import drawCanvas from "@/components/m-canvas"; const store = useStore()
export default { const lightColor = computed(() => store.getters.lightColor)
data() { const swipeOptions = computed(() => [
return {
lightColor: this.$lightColor,
deleteContent: "解绑该商品?", //删除显示的信息
// 商品栏右侧滑动按钮
options: [
{ {
text: "解绑", text: '解绑',
style: { style: { backgroundColor: lightColor.value },
backgroundColor: this.$lightColor, //高亮颜色
}, },
}, ])
],
showFlag: false, //分销分享开关 const unbindModalContent = '解绑该商品?'
empty: false, const showPoster = ref(false)
popup: false, //弹出层开关 const showUnbindModal = ref(false)
active_color: this.$mainColor, const routeQuery = ref<Record<string, string>>({})
current: 0, const selectedGoods = ref<any>(null)
params: { const drawCanvasRef = ref<any>(null)
const queryParams = ref({
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
checked: true, checked: true,
}, })
goodsList: [], const goodsList = ref<any[]>([])
// 分销分享 实例 const posterData = ref({
res: {
container: { container: {
width: 600, width: 600,
height: 960, height: 960,
background: "#fff", background: '#fff',
title: "分享背景", title: '分享背景',
}, },
// 分销分享
bottom: { bottom: {
img: "", img: '',
code: "", code: '',
price: 0, price: 0,
desc: '',
}, },
}, })
routers: "", onLoad((options) => {
deleteShow: false, //删除模态框 routeQuery.value = options || {}
goodsVal: false, //分销商铺信息 })
};
},
components: {
drawCanvas,
},
onLoad(options) {
this.routers = options;
},
watch: {},
onShow() {
this.goodsList = [];
this.init();
},
methods: {
/**
* 滑动删除
*/
changeActionTab(val) {
this.deleteShow = true;
this.goodsVal = val;
},
/** onShow(() => {
* 点击解绑商品 goodsList.value = []
*/ queryParams.value.pageNumber = 1
delectConfirm() { fetchGoodsList()
checkedDistributionGoods({ id: this.goodsVal.id, checked: false }).then( })
(res) => {
function confirmUnbindPrompt(item: any) {
showUnbindModal.value = true
selectedGoods.value = item
}
function confirmUnbind() {
checkedDistributionGoods({ id: selectedGoods.value.id, checked: false }).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({ title: '此商品解绑成功', duration: 2000 })
title: "此商品解绑成功", showUnbindModal.value = false
duration: 2000, goodsList.value = []
}); queryParams.value.pageNumber = 1
this.deleteShow = false; fetchGoodsList()
this.goodsList = [];
this.init();
} }
})
} }
);
},
/** function openSwipeAction(item: any) {
* 左滑打开删除 goodsList.value.forEach((row) => {
*/ row.___selected = false
openAction(val) { })
this.goodsList.forEach((item) => { item.___selected = true
item["___selected"] = false; }
});
val["___selected"] = true;
},
/** function navigateToGoods(item: any) {
* 查看图片
*/
handleNavgationGoods(val) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${val.skuId}&goodsId=${val.goodsId}`, url: `/pages/product/goods?id=${item.skuId}&goodsId=${item.goodsId}`,
}); })
}, }
async handleLink(goods) { async function shareDistributionGoods(goods: any) {
uni.showToast({ uni.showToast({ title: '请请按住保存图片', duration: 2000, icon: 'none' })
title: "请请按住保存图片", const page = 'pages/product/goods'
duration: 2000, const scene = `${goods.skuId},${goods.goodsId},${routeQuery.value.id}`
icon: "none", const result = await getMpCode({ page, scene })
});
let page = `pages/product/goods`;
let scene = `${goods.skuId},${goods.goodsId},${this.routers.id}`;
let result = await getMpCode({ page, scene });
if (result.data.success) { if (result.data.success) {
let callback = result.data.result; const callback = result.data.result
this.res.container.title = `${goods.goodsName}`; posterData.value.container.title = `${goods.goodsName}`
this.res.bottom.code = `data:image/png;base64,${callback}`; posterData.value.bottom.code = `data:image/png;base64,${callback}`
this.res.bottom.price = this.unitPrice( posterData.value.bottom.price = unitPrice(goods.price, '¥')
goods.price, posterData.value.bottom.desc = `${goods.goodsName}`
"¥" posterData.value.bottom.img = `${goods.thumbnail}`
); if (showPoster.value) {
this.res.bottom.desc = `${goods.goodsName}`; drawCanvasRef.value?.init()
this.res.bottom.img = `${goods.thumbnail}`;
if (this.showFlag) {
this.$refs.drawCanvas.init();
} }
this.showFlag = true; showPoster.value = true
} else { } else {
uni.showToast({ uni.showToast({ title: '制作二维码失败!请稍后重试', duration: 2000, icon: 'none' })
title: `制作二维码失败!请稍后重试`, }
duration: 2000,
icon: "none",
});
} }
},
change(index) { function toggleGoodsTab(isSelected: boolean) {
this.current = index; goodsList.value = []
}, queryParams.value.checked = isSelected
// 点击我的选品库 queryParams.value.pageNumber = 1
handleMyGoods(flag) { fetchGoodsList()
this.goodsList = []; }
this.params.checked = flag;
this.init();
},
// 选择商品 function selectGoods(item: any) {
handleClickGoods(val) { checkedDistributionGoods({ id: item.id, checked: true }).then((res) => {
checkedDistributionGoods({ id: val.id, checked: true }).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({ title: '已添加到我的选品库', duration: 2000, icon: 'none' })
title: "已添加到我的选品库",
duration: 2000,
icon: "none",
});
setTimeout(() => { setTimeout(() => {
this.goodsList = []; goodsList.value = []
this.init(); queryParams.value.pageNumber = 1
}, 500); fetchGoodsList()
}, 500)
}
})
} }
});
},
init() { function fetchGoodsList() {
distributionGoods(this.params).then((res) => { distributionGoods(queryParams.value).then((res) => {
if (res.data.success && res.data.result.records.length >= 1) { if (res.data.success && res.data.result.records.length >= 1) {
res.data.result.records.forEach((item) => { res.data.result.records.forEach((item: any) => {
item["___selected"] = false; item.___selected = false
}); })
this.goodsList.push(...res.data.result.records); goodsList.value.push(...res.data.result.records)
} }
if (this.goodsList.length === 0) { })
this.empty = true;
} }
});
},
/** function loadMore() {
* 底部加载数据 queryParams.value.pageNumber += 1
*/ fetchGoodsList()
renderDate() { }
this.params.pageNumber += 1;
this.init();
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,129 +1,182 @@
<template> <template>
<view> <view class="wrapper" :style="themeStyle">
<view class="withdrawal-list"> <view class="feedBack-box">
<view class="title">提现金额</view> <view class="box-title">提现金额</view>
<view class="content"> <view class="amount-row">
<view class="price"> <text class="currency"></text>
<span> </span> <u-input
<u-input v-model="price" placeholder="" type="number" /> v-model="price"
type="digit"
border="none"
placeholder="请输入提现金额"
class="amount-input"
/>
</view> </view>
<view class="amount-extra">
<view class="all"> <view class="all-btn" @click="fillAllAmount">全部</view>
<view @click="handleAll" :style="{ color: $mainColor }">全部</view> <view class="balance-tip">
<view style="font-size: 24rpx; color: #999" 可提现金额
>可提现金额<span>{{unitPrice(distributionData.canRebate) }}</span <text class="balance-value">{{ unitPrice(distributionData.canRebate) }}</text>
></view
>
</view> </view>
</view> </view>
</view> </view>
<view class="submit" @click="cashd">提现</view> <view class="submit" @click="submitWithdraw">提现</view>
</view> </view>
</template> </template>
<script>
import { distribution, cash } from "@/api/goods";
export default {
data() {
return {
price: 0,
distributionData: "",
};
},
mounted() {
this.init();
},
methods: {
cashd() {
this.price = this.price + "";
<script setup lang="ts">
import { ref, computed, getCurrentInstance, onMounted } from 'vue'
import { useStore } from '@/store'
import { distribution, cash } from '@/api/goods'
import { unitPrice } from '@/utils/filters.js'
import { getThemeStyle } from '@/utils/theme'
if (this.$u.test.amount(parseInt(this.price))) { const store = useStore()
cash({ price: this.price }).then((res) => { const { proxy } = getCurrentInstance()!
if(res.data.success){
uni.showToast({ const themeStyle = computed(() => getThemeStyle(store.state.theme))
title: '提现成功!', const price = ref('')
duration: 2000, const distributionData = ref<Record<string, any>>({})
icon:"none"
}); onMounted(() => {
setTimeout(()=>{ fetchDistributionInfo()
uni.navigateBack({ })
delta: 1
}); function hideLoadingIfNeeded() {
},1000) if (store.state.isShowToast) uni.hideLoading()
} }
});
} else { function fetchDistributionInfo() {
uni.showToast({ uni.showLoading({ title: '加载中' })
title: "请输入正确金额",
duration: 2000,
icon: "none",
});
}
},
handleAll() {
this.price = this.distributionData.canRebate;
},
/**
* 初始化推广商品
*/
init() {
uni.showLoading({
title: "加载中",
});
distribution().then((res) => { distribution().then((res) => {
if (res.data.result) { if (res.data.result) {
this.distributionData = res.data.result; distributionData.value = res.data.result
}
hideLoadingIfNeeded()
})
} }
if (this.$store.state.isShowToast){ uni.hideLoading() };
});
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .u-input__input,
.u-input {
font-size: 80rpx !important;
height: 102rpx !important;
function submitWithdraw() {
const amount = String(price.value ?? '')
if (proxy.$u.test.amount(parseInt(amount))) {
cash({ price: amount }).then((res) => {
if (res.data.success) {
uni.showToast({ title: '提现成功!', duration: 2000, icon: 'none' })
setTimeout(() => {
uni.navigateBack({ delta: 1 })
}, 1000)
} }
::v-deep .u-input__input{ })
height: 100%; } else {
font-size: 80rpx; uni.showToast({ title: '请输入正确金额', duration: 2000, icon: 'none' })
}
.content {
display: flex;
> .price {
width: 60%;
margin: 20rpx 0;
font-size: 80rpx;
display: flex;
}
> .all {
justify-content: center;
width: 40%;
display: flex;
flex-direction: column;
align-items: flex-end;
} }
} }
.withdrawal-list {
margin: 20rpx 0; function fillAllAmount() {
background: #fff; price.value = distributionData.value.canRebate ?? ''
padding: 16rpx 32rpx;
} }
.title { </script>
font-size: 35rpx;
} <style lang="scss">
.submit { page {
margin: 80rpx auto; background: #f8f8f8;
width: 94%; }
background: $light-color; </style>
height: 90rpx;
color: #fff; <style lang="scss" scoped>
border-radius: 10rpx; @import '@/pages/passport/entry/seller/entry-form.scss';
text-align: center;
line-height: 90rpx; .wrapper {
box-sizing: border-box;
min-height: 100vh;
padding: 20rpx 24rpx 40rpx;
background: #f8f8f8;
}
.feedBack-box {
background: #fff;
border-radius: 20rpx;
padding: 32rpx;
}
.box-title {
font-size: 30rpx;
font-weight: 600;
color: #333;
line-height: 1.4;
}
.amount-row {
display: flex;
flex-direction: row;
align-items: center;
margin-top: 24rpx;
padding: 16rpx 24rpx;
background: #fafafa;
border-radius: 12rpx;
}
.currency {
flex-shrink: 0;
margin-right: 16rpx;
font-size: 56rpx;
font-weight: 600;
line-height: 1;
color: #333;
}
.amount-input {
flex: 1;
min-width: 0;
}
:deep(.amount-input .u-input) {
padding: 0 !important;
}
:deep(.amount-input .u-input__content) {
background: transparent !important;
}
:deep(.amount-input .u-input__content__field-wrapper__field) {
height: 72rpx !important;
min-height: 72rpx !important;
font-size: 56rpx !important;
font-weight: 600 !important;
color: #333 !important;
}
:deep(.amount-input .u-input__content__field-wrapper__field--placeholder) {
font-size: 32rpx !important;
font-weight: 400 !important;
color: #c0c4cc !important;
}
.amount-extra {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 24rpx;
}
.all-btn {
font-size: 28rpx;
color: var(--theme-light, #ff6b35);
}
.balance-tip {
font-size: 24rpx;
color: #999;
}
.balance-value {
margin: 0 4rpx;
color: #333;
}
.submit {
@include seller-entry-submit;
} }
</style> </style>

View File

@@ -1,60 +1,40 @@
<template> <template>
<div class="wrapper"> <div class="wrapper">
<u-parse :lazy-load="true" :selectable="true" :content="res.content" v-if="res"></u-parse> <u-parse :lazy-load="true" :selectable="true" :content="article.content" v-if="article"></u-parse>
</div> </div>
</template> </template>
<script>
import { getArticleDetailByType } from "@/api/article";
export default {
data() {
return {
res: "",
way: {
USER_AGREEMENT: {
title: "服务协议",
type: "USER_AGREEMENT",
},
PRIVACY_POLICY: {
title: "隐私政策",
type: "PRIVACY_POLICY",
},
LICENSE_INFORMATION: {
title: "证照信息",
type: "LICENSE_INFORMATION",
},
ABOUT: {
title: "关于我们",
type: "ABOUT",
},
STORE_REGISTER: {
title: "店铺入驻协议",
type: "STORE_REGISTER",
},
},
};
},
mounted() {},
onLoad(option) {
console.log(this.way)
uni.setNavigationBarTitle({
title: this.way[option.type].title,
});
this.init(option);
},
methods: { <script setup lang="ts">
init(option) { import { ref } from 'vue'
getArticleDetailByType(this.way[option.type].type).then((res) => { import { onLoad } from '@dcloudio/uni-app'
if (res.data.success) { import { getArticleDetailByType } from '@/api/article'
this.res = res.data.result;
console.log(res) const ARTICLE_TYPE_MAP: Record<string, { title: string; type: string }> = {
USER_AGREEMENT: { title: '服务协议', type: 'USER_AGREEMENT' },
PRIVACY_POLICY: { title: '隐私政策', type: 'PRIVACY_POLICY' },
LICENSE_INFORMATION: { title: '证照信息', type: 'LICENSE_INFORMATION' },
ABOUT: { title: '关于我们', type: 'ABOUT' },
STORE_REGISTER: { title: '店铺入驻协议', type: 'STORE_REGISTER' },
}
const article = ref<any>(null)
onLoad((option) => {
const meta = ARTICLE_TYPE_MAP[option.type]
if (!meta) return
uni.setNavigationBarTitle({ title: meta.title })
fetchArticle(meta.type)
})
function fetchArticle(type: string) {
getArticleDetailByType(type).then((res) => {
if (res.data.success) {
article.value = res.data.result
}
})
} }
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.wrapper { .wrapper {
padding: 16rpx; padding: 16rpx;

View File

@@ -196,515 +196,356 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
// rpx和px的比率 import { ref, nextTick, getCurrentInstance } from 'vue'
var l
// 可用窗口高度
var wh
// 顶部空盒子的高度
var mgUpHeight
import { import {
getTalkMessage, onLoad,
onHide,
onUnload,
onPullDownRefresh,
onPageScroll,
} from '@dcloudio/uni-app'
import {
getTalkMessage as fetchTalkMessageApi,
getTalkByUser, getTalkByUser,
jumpObtain jumpObtain,
} from "@/api/im.js"; } from '@/api/im.js'
import SocketService from "@/utils/socket_service.js"; import SocketService from '@/utils/socket_service.js'
import storage from "@/utils/storage.js"; import storage from '@/utils/storage.js'
import { import { beautifyTime, unitPrice } from '@/utils/filters.js'
beautifyTime
} from "@/utils/filters.js"
import config from '@/config/config.js' import config from '@/config/config.js'
import { textReplaceEmoji, emojistwo } from '@/utils/emojis.js'; import { textReplaceEmoji, emojistwo } from '@/utils/emojis.js'
export default {
// 页面卸载后清除imGoodId
onUnload () {
// #ifdef H5
uni.setStorageSync("imGoodId", '');
// #endif
if (this.socketOpen == true) { // rpx和px的比率
uni.closeSocket(); let l: number
} // 可用窗口高度
}, let wh: number
onLoad (options) { // 顶部空盒子的高度
// 没有goodsid则不显示 发送商品弹窗 let mgUpHeight: number
this.showHideModel = options.goodsid
// 发送后刷新页面不显示 发送商品弹窗 local里面imGoodId不为空显示
// #ifdef H5
this.localImGoodsId = uni.getStorageSync("imGoodId");
// #endif
this.resolve = options
// 请求商品信息
if (this.resolve.goodsid) {
this.commodityDetails()
}
var query = uni.getSystemInfoSync() const { proxy } = getCurrentInstance()!
l = query.screenWidth / 750 const socketOpen = ref(false)
wh = query.windowHeight const showHideModel = ref<string | undefined>(undefined)
this.scrollHeight = (query.windowHeight - 44) + "px" const localImGoodsId = ref('')
this.user = storage.getUserInfo() const showHide = ref(true)
this.toUser = storage.getTalkToUser() const anData = ref<Record<string, any>>({})
const animationData = ref<Record<string, any>>({})
if (options.talkId) { const msgList = ref<any[]>([])
this.params.talkId = options.talkId; const oldHeight = ref(0)
this.getTalkMessage() const params = ref({
} else {
this.getTalk(options.userId)
}
// this.ws.connect();
this.socket();
},
// 页面隐藏
onHide () {
uni.closeSocket();
},
onUnload () {
uni.closeSocket();
},
onPullDownRefresh () {
this.params.pageNumber = this.params.pageNumber + 1
this.getTalkMessage()
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
data () {
return {
textReplaceEmoji,
emojistwo,
socketOpen: false, //是否连接
storage,
fixed: 'fixed',
bottom: '50px',
width: '100%',
showHideModel: undefined,
localImGoodsId: '',
showHide: true,
msgLoad: false,
anData: {},
animationData: {},
msgList: [],
oldHeight: 0,
params: { //搜索条件
talkId: '', talkId: '',
pageSize: 10, pageSize: 10,
pageNumber: 1, pageNumber: 1,
}, })
goToIndex: 0, // 前往位置 const msg = ref('')
msg: "", const go = ref(0)
go: 0, const user = ref<Record<string, any>>({})
newMessageNum: 0, const toUser = ref<Record<string, any>>({})
user: {}, const scrollHeight = ref(0)
toUser: {}, const ws = new SocketService()
scrollHeight: 0, const resolve = ref<Record<string, any>>({})
ws: new SocketService(), const goodListData = ref<Record<string, any>>({})
resolve: {}, const reconnectCount = ref(0)
goodListData: {}, const inputHeight = ref(0)
count: 0, //判断socket断开连接请求次数 const isShow = ref(false)
inputHeight:0,
isShow:false,
onLoad((options: Record<string, string | undefined> = {}) => {
showHideModel.value = options.goodsid
// #ifdef H5
localImGoodsId.value = uni.getStorageSync('imGoodId')
// #endif
resolve.value = options
if (resolve.value.goodsid) {
commodityDetails()
} }
},
onPageScroll (e) {
const query = uni.getSystemInfoSync()
l = query.screenWidth / 750
wh = query.windowHeight
scrollHeight.value = query.windowHeight - 44 + 'px'
user.value = storage.getUserInfo()
toUser.value = storage.getTalkToUser()
if (options.talkId) {
params.value.talkId = options.talkId
fetchTalkMessages()
} else {
getTalk(options.userId!)
}
socket()
})
onHide(() => {
uni.closeSocket()
})
onUnload(() => {
// #ifdef H5
uni.setStorageSync('imGoodId', '')
// #endif
uni.closeSocket()
})
onPullDownRefresh(() => {
params.value.pageNumber = params.value.pageNumber + 1
fetchTalkMessages()
setTimeout(() => {
uni.stopPullDownRefresh()
}, 1000)
})
onPageScroll(() => {
// #ifdef APP-PLUS // #ifdef APP-PLUS
uni.hideKeyboard() uni.hideKeyboard()
this.isShow = false isShow.value = false
// #endif // #endif
}, })
methods: {
navigateToBottom(){ function navigateToBottom() {
// #ifdef H5 // #ifdef H5
this.isShow = true isShow.value = true
this.$refs.inputRef.focus() ;(proxy as any).$refs.inputRef?.focus()
// #endif // #endif
// #ifdef APP-PLUS // #ifdef APP-PLUS
this.$nextTick(() => { nextTick(() => {
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: 5000000, scrollTop: 5000000,
duration: 50, duration: 50,
success: () => { success: () => {
setTimeout(() => { setTimeout(() => {
this.isShow = true isShow.value = true
}, 200); }, 200)
;
}, },
fail: () => {}, fail: () => {},
complete: () => {} complete: () => {},
}); })
}); })
// #endif // #endif
}
}, function eventHandle() {
inputHeight.value = 0
isShow.value = false
}
eventHandle(){ function inputBindFocus(e: any) {
this.inputHeight = 0
this.isShow = false
},
inputBindFocus(e){
if (e.detail.height) { if (e.detail.height) {
// #ifdef APP-PLUS // #ifdef APP-PLUS
// 判断是否是ios
if (uni.getSystemInfoSync().platform == 'ios') { if (uni.getSystemInfoSync().platform == 'ios') {
this.inputHeight = e.detail.height - 40 //这个高度就是软键盘的高度 inputHeight.value = e.detail.height - 40
} else { } else {
this.inputHeight = e.detail.height inputHeight.value = e.detail.height
} }
// #endif // #endif
// #ifndef APP-PLUS // #ifndef APP-PLUS
this.inputHeight = e.detail.height //这个高度就是软键盘的高度 inputHeight.value = e.detail.height
// #endif // #endif
} }
},
sendMessage () {
if (this.msg == "") {
return 0;
} }
if (this.socketOpen == false) {
function sendMessage() {
if (msg.value == '') {
return 0
}
if (socketOpen.value == false) {
return return
} }
let msg = { const payload = {
operation_type: "MESSAGE", operation_type: 'MESSAGE',
to: this.toUser.userId, to: toUser.value.userId,
from: this.user.id, from: user.value.id,
message_type: "MESSAGE", message_type: 'MESSAGE',
context: this.msg, context: msg.value,
talk_id: this.params.talkId, talk_id: params.value.talkId,
} }
let data = JSON.stringify(msg); const data = JSON.stringify(payload)
uni.sendSocketMessage({ uni.sendSocketMessage({
data: data, data: data,
});
this.msgList.push({
"text": this.msg,
"my": true,
"messageType": 'MESSAGE'
}) })
let type = 'down'; msgList.value.push({
this.msgGo(type) text: msg.value,
this.msg = "" my: true,
}, messageType: 'MESSAGE',
sendGoodsMessage () { })
let msg = { const type = 'down'
operation_type: "MESSAGE", msgGo(type)
to: this.toUser.userId, msg.value = ''
from: this.user.id,
message_type: "GOODS",
context: this.goodListData,
talk_id: this.params.talkId,
} }
let data = JSON.stringify(msg);
function sendGoodsMessage() {
const payload = {
operation_type: 'MESSAGE',
to: toUser.value.userId,
from: user.value.id,
message_type: 'GOODS',
context: goodListData.value,
talk_id: params.value.talkId,
}
const data = JSON.stringify(payload)
uni.sendSocketMessage({ uni.sendSocketMessage({
data: data data: data,
});
this.msgList.push({
"text": JSON.stringify(this.goodListData),
"my": true,
"messageType": 'GOODS'
}) })
this.showHide = false msgList.value.push({
text: JSON.stringify(goodListData.value),
my: true,
messageType: 'GOODS',
})
showHide.value = false
// #ifdef H5 // #ifdef H5
uni.setStorageSync("imGoodId", 1111111); uni.setStorageSync('imGoodId', 1111111)
// #endif // #endif
this.$nextTick(() => { nextTick(() => {
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: 2000000, scrollTop: 2000000,
duration: 300 duration: 300,
});
}) })
}, })
socket () { }
var _this = this;
uni.closeSocket(); function socket() {
this.socketOpen = false; uni.closeSocket()
socketOpen.value = false
try { try {
//WebSocket的地址 const url = config.baseWsUrl + '/' + storage.getAccessToken()
var url = config.baseWsUrl + '/' + storage.getAccessToken();
// 连接
uni.connectSocket({ uni.connectSocket({
url: url, url: url,
}); })
// 监听WebSocket连接已打开 uni.onSocketOpen(function () {
uni.onSocketOpen(function (res) { socketOpen.value = true
_this.socketOpen = true; })
}); if (!socketOpen.value) {
if (!this.socketOpen) { uni.onSocketError(function (err: any) {
// 监听连接失败 if (reconnectCount.value < 3) {
uni.onSocketError(function (err) {
if (this.count < 3) {
if (err && err.code != 1000) { if (err && err.code != 1000) {
_this.socketOpen = true; socketOpen.value = true
setTimeout(() => { setTimeout(() => {
uni.connectSocket({ uni.connectSocket({
url: url, url: url,
}); })
}, 2000) }, 2000)
} }
} else { } else {
uni.closeSocket(); uni.closeSocket()
} }
this.count++ reconnectCount.value++
}); })
} }
// 监听收到信息
uni.onSocketMessage(function (res) { uni.onSocketMessage(function (res) {
res.data = JSON.parse(res.data) const data = JSON.parse(res.data as string)
console.log(res.data.result); console.log(data.result)
if (res.data.messageResultType == 'MESSAGE') { if (data.messageResultType == 'MESSAGE') {
_this.msgList.push(res.data.result) msgList.value.push(data.result)
console.log(_this.msgList) console.log(msgList.value)
} }
console.log(res.data) console.log(data)
_this.msgGo() msgGo()
}) })
} catch (e) { } catch (e) {
uni.closeSocket(); uni.closeSocket()
} }
// 监听是否断线,断线进行重新连接
uni.onSocketClose((res) => { uni.onSocketClose((res) => {
if (res.code != null && res.code != 1000) { if (res.code != null && res.code != 1000) {
this.socket() socket()
} }
}) })
}, }
beautifyTime,
//订单详情 function linkTosOrders(val: string) {
linkTosOrders (val) { const order = JSON.parse(val)
let order = JSON.parse(val)
uni.navigateTo({ uni.navigateTo({
url: '/pages/order/orderDetail?sn=' + order.sn, url: '/pages/order/orderDetail?sn=' + order.sn,
}); })
}
}, function jumpGoodDesc(item: any) {
// 跳转商品详情页 const info = JSON.parse(item.text)
jumpGoodDesc (item) {
let info = JSON.parse(item.text)
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${info.id}&goodsId=${info.goodsId}`, url: `/pages/product/goods?id=${info.id}&goodsId=${info.goodsId}`,
});
},
//取消发送
cancelModel () {
this.showHide = false
},
// 请求商品详情
commodityDetails () {
jumpObtain(this.resolve.skuid, this.resolve.goodsid).then((res) => {
this.goodListData = res.data.result.data
}) })
},
// 切换输入法时移动输入框(按照官方的上推页面的原理应该会自动适应不同的键盘高度-->官方bug)
goPag (kh) {
this.retractBox(0, 250)
if (this.keyHeight != 0) {
if (kh - this.keyHeight > 0) {
this.retractBox(this.keyHeight - kh, 250)
} }
function cancelModel() {
showHide.value = false
} }
},
// 移动顶部的空盒子 function commodityDetails() {
messageBoxMove (x, t) { jumpObtain(resolve.value.skuid, resolve.value.goodsid).then((res) => {
var animation = uni.createAnimation({ goodListData.value = res.data.result.data
})
}
function messageBoxMove(x: number, t: number) {
const animation = uni.createAnimation({
duration: t, duration: t,
timingFunction: 'linear', timingFunction: 'linear',
}) })
this.animation = animation
animation.height(x).step() animation.height(x).step()
this.anData = animation.export() anData.value = animation.export()
},
// 保持消息体可见
msgGo (type) {
const query = uni.createSelectorQuery()
// 延时100ms保证是最新的高度
setTimeout(() => {
// 获取消息体高度
query.select('#msgList').boundingClientRect(data => {
// 如果超过scorll高度就滚动scorll
if (type == 'up') {
this.go = data.height - this.oldHeight
} else if (type == 'down') {
this.go = data.height - wh + 120
} }
// if (this.oldHeight > 0) {
// this.go = data.height - this.oldHeight function msgGo(type?: string) {
// } else { const query = uni.createSelectorQuery()
// // if (data.height - (wh - 32) > 0) { setTimeout(() => {
// this.go = data.height - wh + 120 query
// } .select('#msgList')
// 保证键盘第一次拉起时消息体能保持可见 .boundingClientRect((data: any) => {
var moveY = wh - data.height if (type == 'up') {
// 超出页面则缩回空盒子 go.value = data.height - oldHeight.value
} else if (type == 'down') {
go.value = data.height - wh + 120
}
const moveY = wh - data.height
if (moveY - mgUpHeight < 0) { if (moveY - mgUpHeight < 0) {
// 小于0则视为0
if (moveY < 0) { if (moveY < 0) {
this.messageBoxMove(0, 200) messageBoxMove(0, 200)
} else { } else {
// 否则缩回盒子对应的高度 messageBoxMove(moveY, 200)
this.messageBoxMove(moveY, 200)
} }
} }
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: this.go, scrollTop: go.value,
duration: 0 duration: 0,
}) })
this.oldHeight = data.height oldHeight.value = data.height
}).exec(); })
.exec()
}, 100) }, 100)
},
// 回答问题的业务逻辑
answer (id) {
// 这里应该传入问题的id,模拟就用index代替了
},
// 不建议输入框聚焦时操作此动画
ckAdd () {
if (!this.showTow) {
this.retractBox(-180, 350)
} else {
this.retractBox(0, 200)
} }
this.showTow = !this.showTow
}, async function fetchTalkMessages() {
hideKey () { let type = ''
uni.hideKeyboard() await fetchTalkMessageApi(params.value).then((res) => {
},
// 拉起/收回附加栏
retractBox (x, t) {
var animation = uni.createAnimation({
duration: t,
timingFunction: 'ease',
})
this.animation = animation
animation.translateY(x).step()
this.animationData = animation.export()
},
async getTalkMessage () {
let type = '';
await getTalkMessage(this.params).then(res => {
if (res.data.success) { if (res.data.success) {
if (this.msgList.length >= 10) { if (msgList.value.length >= 10) {
this.msgList.unshift(...res.data.result) msgList.value.unshift(...res.data.result)
type = 'up' type = 'up'
} else { } else {
this.msgList.unshift(...res.data.result) msgList.value.unshift(...res.data.result)
type = 'down' type = 'down'
} }
this.msgList.forEach(item => { msgList.value.forEach((item) => {
if (item.fromUser === this.user.id) { if (item.fromUser === user.value.id) {
item.my = true item.my = true
} }
}) })
} }
}) })
console.log(this.msgList); console.log(msgList.value)
this.msgGo(type) msgGo(type)
},
// 上拉加载
touchMoreMessage (e) {
if (e.target.scrollTop == 0) {
this.params.pageNumber = this.params.pageNumber + 1
this.getTalkMessage()
} }
},
async getTalk (userId) { function getTalk(userId: string) {
getTalkByUser(userId).then(res => { getTalkByUser(userId).then((res) => {
if (res.data.success) { if (res.data.success) {
this.toUser = res.data.result toUser.value = res.data.result
this.params.talkId = res.data.result.id params.value.talkId = res.data.result.id
this.getTalkMessage() fetchTalkMessages()
} }
}) })
},
// 处理消息时间是否显示
compareTime (index, datetime) {
if (datetime == undefined) {
return false;
}
if (typeof datetime == "number") {
datetime = this.unixToDate(datetime, "yyyy-MM-dd hh:mm");
}
if (this.msgList[index].is_revoke == 1) {
return false;
}
if (datetime) {
datetime = datetime.replace(/-/g, "/");
}
let time = Math.floor(Date.parse(datetime) / 1000);
let currTime = Math.floor(new Date().getTime() / 1000);
// 当前时间5分钟内时间不显示
if (currTime - time < 300) return false;
// 判断是否是最后一条消息,最后一条消息默认显示时间
if (index == this.msgList.length - 1) {
return true;
}
let nextDate
if (this.msgList[index + 1] && this.msgList[index + 1].createTime) {
nextDate = this.msgList[index + 1].createTime.replace(/-/g, "/");
if (nextDate - datetime < 300) return false;
}
return !(
this.unixToDate(new Date(datetime), "{y}-{m}-{d} {h}:{i}") ==
this.unixToDate(new Date(nextDate), "{y}-{m}-{d} {h}:{i}")
);
},
/**
* 将unix时间戳转换为指定格式
* @param unix 时间戳【秒】
* @param format 转换格式
* @returns {*|string}
*/
unixToDate (unix, format) {
if (!unix) return unix;
let _format = format || "yyyy-MM-dd hh:mm:ss";
const d = new Date(unix);
const o = {
"M+": d.getMonth() + 1,
"d+": d.getDate(),
"h+": d.getHours(),
"m+": d.getMinutes(),
"s+": d.getSeconds(),
"q+": Math.floor((d.getMonth() + 3) / 3),
S: d.getMilliseconds(),
};
if (/(y+)/.test(_format))
_format = _format.replace(
RegExp.$1,
(d.getFullYear() + "").substr(4 - RegExp.$1.length)
);
for (const k in o)
if (new RegExp("(" + k + ")").test(_format))
_format = _format.replace(
RegExp.$1,
RegExp.$1.length === 1 ?
o[k] :
("00" + o[k]).substr(("" + o[k]).length)
);
return _format;
},
}
} }
</script> </script>

View File

@@ -9,12 +9,12 @@
:border="false" :border="false"
:auto-back="true" :auto-back="true"
></u-navbar> ></u-navbar>
<scroll-view class="list-scroll-content" scroll-y @scrolltolower="loadData(tabIndex)"> <scroll-view class="list-scroll-content" scroll-y @scrolltolower="fetchTalkList">
<!-- 消息列表 --> <!-- 消息列表 -->
<div class="iconBox"> <div class="iconBox">
<view class="icon-list"> <view class="icon-list">
<view class="icon-item" @click="cleanUnread()"> <view class="icon-item" @click="clearUnreadMessages()">
<div class="bag bag1"> <div class="bag bag1">
<u-icon name="trash" size="50" color="#fff"></u-icon> <u-icon name="trash" size="50" color="#fff"></u-icon>
</div> </div>
@@ -28,7 +28,7 @@
</view> </view>
</view> </view>
</div> </div>
<u-search class="nav-search" v-model="userName" clearabled @change="userTalkList()" placeholder="搜索用户" <u-search class="nav-search" v-model="userName" clearabled @change="fetchTalkList()" placeholder="搜索用户"
:show-action="false"></u-search> :show-action="false"></u-search>
<view class="talk-view" :key="index" v-for="(item, index) in talkList"> <view class="talk-view" :key="index" v-for="(item, index) in talkList">
<view> <view>
@@ -65,85 +65,80 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getTalkList, clearmeaager } from "@/api/im.js"; import { ref } from 'vue'
import storage from "@/utils/storage.js"; import { onShow, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
import { beautifyTime } from "@/utils/filters.js" import { useStore } from '@/store'
export default { import { getTalkList, clearmeaager } from '@/api/im.js'
data () { import storage from '@/utils/storage.js'
return { import { beautifyTime } from '@/utils/filters.js'
storage,
count: {
loadStatus: "more",
},
talkList: [], //聊天列表
userName: '',
pointData: {}, //累计获取 未输入 集合
};
},
onShow () { const store = useStore()
this.userTalkList();
}, const talkList = ref<any[]>([])
onPullDownRefresh () { const userName = ref('')
this.userTalkList()
console.log('下拉事件'); onShow(() => {
setTimeout(function () { fetchTalkList()
uni.stopPullDownRefresh(); })
}, 1000);
}, onPullDownRefresh(() => {
/** fetchTalkList()
* 触底加载 console.log('下拉事件')
*/ setTimeout(() => {
onReachBottom () { uni.stopPullDownRefresh()
this.userTalkList(); }, 1000)
}, })
methods: {
beautifyTime, onReachBottom(() => {
onclickToTalkInfo (val) { fetchTalkList()
})
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
}
function onclickToTalkInfo(val: any) {
storage.setTalkToUser(val) storage.setTalkToUser(val)
uni.navigateTo({ uni.navigateTo({
url: url: '/pages/mine/im/index?talkId=' + val.id,
"/pages/mine/im/index?talkId=" + val.id, })
}); }
},
/** function fetchTalkList() {
* 获取聊天列表 const params = {
*/ userName: userName.value,
userTalkList () {
let params = {
userName: this.userName,
} }
uni.showLoading({ uni.showLoading({
title: "加载中", title: '加载中',
}); })
getTalkList(params).then((res) => { getTalkList(params).then((res) => {
if (this.$store.state.isShowToast){ uni.hideLoading() }; hideLoadingIfNeeded()
if (res.data.success) { if (res.data.success) {
this.talkList = res.data.result; talkList.value = res.data.result
console.log(this.talkList, 'this.talkListthis.talkList'); console.log(talkList.value, 'this.talkListthis.talkList')
}
});
},
navigateTo (url) {
uni.navigateTo({
url,
});
},
cleanUnread () {
clearmeaager().then((res) => {
console.log(res);
if (res.data.code == 200) {
this.userTalkList();
uni.showToast({
icon: "none",
title: res.data.message,
});
} }
}) })
}, }
},
}; function navigateTo(url: string) {
uni.navigateTo({
url,
})
}
function clearUnreadMessages() {
clearmeaager().then((res) => {
console.log(res)
if (res.data.code == 200) {
fetchTalkList()
uni.showToast({
icon: 'none',
title: res.data.message,
})
}
})
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,8 +1,8 @@
<template> <template>
<view class="container"> <view class="container">
<view class="list-cell b-b m-t" hover-class="cell-hover" :hover-stay-time="50"> <view class="list-cell b-b m-t" hover-class="cell-hover" :hover-stay-time="50">
<u-row gutter="12" justify="start" @click="navigateTo('/pages/msgTips/sysMsg/index')"> <u-row gutter="12" justify="start" @click="navigateTo('/pages/mine/msgTips/sysMsg/index')">
<u-col span="2" class="uCol" style="text-align:center;"> <u-col span="2" class="uCol" style="text-align: center">
<image class="img" src="/static/mine/setting.png"></image> <image class="img" src="/static/mine/setting.png"></image>
</u-col> </u-col>
<u-col span="7"> <u-col span="7">
@@ -11,173 +11,88 @@
</u-col> </u-col>
<u-col span="3"> <u-col span="3">
<view class="cell-more"> <view class="cell-more">
<u-tag size="mini" v-if="no_read.system_num>0" shape="circle" mode="dark" type="error" :text="no_read.system_num"></u-tag> <u-tag
size="mini"
v-if="unreadCount.system_num > 0"
shape="circle"
mode="dark"
type="error"
:text="String(unreadCount.system_num)"
></u-tag>
<span class="yticon icon-you"></span> <span class="yticon icon-you"></span>
</view> </view>
</u-col> </u-col>
</u-row> </u-row>
</view> </view>
<!-- <view class="list-cell b-b m-t" hover-class="cell-hover" :hover-stay-time="50">
<u-row gutter="12" justify="start" @click="navigateTo('/pages/msgTips/packagemsg/index')">
<u-col span="2" class="uCol" style="text-align:center;">
<image class="img" src="/static/mine/logistics.png"></image>
</u-col>
<u-col span="7">
<p class="tit_title">物流消息</p>
<p class="tit_tips">查看物流消息</p>
</u-col>
<u-col span="3">
<view class="cell-more">
<u-tag v-if="no_read.logistics_num>0" shape="circle" mode="dark" type="warning" :text="no_read.logistics_num"></u-tag>
<span class="yticon icon-you"></span>
</view>
</u-col>
</u-row>
</view> -->
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { import { ref } from 'vue'
mapMutations import { onLoad } from '@dcloudio/uni-app'
} from "vuex"; import { getNoReadMessageNum } from '@/api/members.js'
import * as API_Message from "@/api/members.js";
export default { const unreadCount = ref<Record<string, number>>({ system_num: 0 })
data() {
return { onLoad(() => {
no_read: '' fetchUnreadCount()
}; })
},
onLoad() { function navigateTo(url: string) {
this.GET_NoReadMessageNum(); uni.navigateTo({ url })
}, }
methods: {
...mapMutations(["logout"]), function fetchUnreadCount() {
navigateTo(url) { getNoReadMessageNum().then((response) => {
uni.navigateTo({ unreadCount.value = response.data || { system_num: 0 }
url
});
},
/** 获取未读消息数量信息 */
GET_NoReadMessageNum() {
API_Message.getNoReadMessageNum().then(response => {
this.no_read = response.data
}) })
} }
}
};
</script> </script>
<style scoped lang='scss'> <style scoped lang="scss">
.uCol { .uCol {
display: flex; display: flex;
justify-content: center !important; justify-content: center !important;
} }
.img { .img {
width: 60rpx; width: 60rpx;
height: 60rpx; height: 60rpx;
} }
.container { .container {
background: #f9f9f9; background: #f9f9f9;
} }
::v-deep .u-col-2 { ::v-deep .u-col-2 {
height: 60px; height: 60px;
line-height: 60px; line-height: 60px;
text-align: center !important; text-align: center !important;
} }
.qicon {
text-align: center;
display: block;
font-size: 20px;
}
.redBox {
display: inline-block;
text-align: center;
line-height: 1.5em;
font-size: 12px;
min-width: 1.5em;
min-height: 1.5em;
background: #ed6533;
border-radius: 50%;
color: #fff;
}
.tit_title { .tit_title {
color: $u-main-color; color: $u-main-color;
} }
.tit_tips { .tit_tips {
color: $u-tips-color; color: $u-tips-color;
} }
.u-col-3 { .u-col-3 {
text-align: right !important; text-align: right !important;
padding-right: 20rpx !important; padding-right: 20rpx !important;
} }
.list-cell { .list-cell {
background: #fff; background: #fff;
align-items: baseline; align-items: baseline;
padding: 20rpx 0; padding: 20rpx 0;
line-height: 60rpx; line-height: 60rpx;
background: #fff;
justify-content: center; justify-content: center;
&.log-out-btn {
margin-top: 40rpx;
.cell-tit {
color: $uni-color-primary;
text-align: center;
margin-right: 0;
}
}
&.cell-hover { &.cell-hover {
background: #fafafa; background: #fafafa;
} }
&.b-b:after {
left: 30rpx;
}
&.m-t { &.m-t {
margin-top: 16rpx; margin-top: 16rpx;
} }
.cell-more { .cell-more {
/* margin-top: 10rpx; */
height: 60rpx; height: 60rpx;
text-align: right; text-align: right;
/* display: flex;
justify-content: center; //这个是X轴居中
align-items: center; //这个是 Y轴居中 */
font-size: $font-lg; font-size: $font-lg;
color: $font-color-light; color: $font-color-light;
/* width: 100rpx; */
}
.cell-tit {
flex: 1;
font-size: $font-base + 2rpx;
color: $font-color-dark;
margin-right: 10rpx;
}
.cell-tip {
font-size: $font-base;
color: $font-color-light;
} }
} }
</style> </style>

View File

@@ -1,11 +1,20 @@
<template> <template>
<view class="container " style="font-size: 13px;"> <view class="container" style="font-size: 13px">
<block v-for="(row, index) in messageList" :key="index"> <block v-for="(row, index) in messageList" :key="index">
<view class="msgItem"> <view class="msgItem">
<div class="msgMsg"> <div class="msgMsg">
<div class="bagbar">{{$u.timeFormat(row.send_time, 'yyyy-mm-dd')}}</div> <div class="bagbar">{{ formatSendTime(row.send_time) }}</div>
</div> </div>
<u-card @click="goDetail(row.sn,row.logi_id,row.ship_no)" :title="title" title-color="#666666" title-size="24" sub-title-color="#666666" sub-title-size="24" :border="false" :sub-title=row.status> <u-card
@click="navigateToLogisticsDetail(row.sn, row.logi_id, row.ship_no)"
:title="pageTitle"
title-color="#666666"
title-size="24"
sub-title-color="#666666"
sub-title-size="24"
:border="false"
:sub-title="row.status"
>
<template #body> <template #body>
<view class="msg-body"> <view class="msg-body">
<image class="msgImg" :src="row.goods_img" mode=""></image> <image class="msgImg" :src="row.goods_img" mode=""></image>
@@ -22,67 +31,73 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import * as API_Message from "@/api/message.js"; import { ref, getCurrentInstance } from 'vue'
export default { import { onLoad, onReachBottom } from '@dcloudio/uni-app'
data() { import { useStore } from '@/store'
return { import * as API_Message from '@/api/message.js'
messageList: [],
title: "物流更新通知", const store = useStore()
subTitle: "运输中", const { proxy } = getCurrentInstance()!
loadStatus:'more',
params: { const messageList = ref<any[]>([])
pageNumber: 1, const pageTitle = '物流更新通知'
pageSize: 10, const loadStatus = ref('more')
}, const queryParams = ref({ pageNumber: 1, pageSize: 10 })
loadStatus:'more'
}; onLoad(() => {
}, fetchLogisticsList(true)
onLoad(){ })
this.GET_LogisticsList(true);
}, onReachBottom(() => {
onReachBottom() { queryParams.value.pageNumber++
this.params.pageNumber++ fetchLogisticsList(false)
this.GET_LogisticsList(false) })
},
methods: { function hideLoadingIfNeeded() {
goDetail(sn,logi_id,ship_no){ if (store.state.isShowToast) uni.hideLoading()
}
function formatSendTime(time: number) {
return proxy.$u.timeFormat(time, 'yyyy-mm-dd')
}
function extractRecords(res: any) {
if (Array.isArray(res?.result?.records)) return res.result.records
if (Array.isArray(res?.result)) return res.result
if (Array.isArray(res?.data)) return res.data
return []
}
function navigateToLogisticsDetail(sn: string, logiId: string, shipNo: string) {
uni.navigateTo({ uni.navigateTo({
url:'/pages/msgTips/packagemsg/logisticsDetail?order_sn=' + sn +'&logi_id='+logi_id+'&ship_no='+ship_no, url: `/pages/mine/msgTips/packageMsg/logisticsDetail?order_sn=${sn}&logi_id=${logiId}&ship_no=${shipNo}`,
}) })
}, }
//获取物流消息
GET_LogisticsList(reset){ function fetchLogisticsList(reset: boolean) {
if (reset) { if (reset) {
this.params.pageNumber = 1 queryParams.value.pageNumber = 1
messageList.value = []
loadStatus.value = 'more'
} }
uni.showLoading({ uni.showLoading({ title: '加载中' })
title:"加载中" API_Message.getLogisticsMessages(queryParams.value).then((response) => {
}) hideLoadingIfNeeded()
API_Message.getLogisticsMessages(this.params).then(async response => { const records = extractRecords(response.data)
if (this.$store.state.isShowToast){ uni.hideLoading() } if (records.length) {
const { data } = response messageList.value.push(...records)
if (!data || !data.length) { } else {
this.messageList.push(...data.data) loadStatus.value = 'noMore'
} }
}) })
} }
}
};
</script> </script>
<style scoped lang='scss'> <style scoped lang="scss">
.ddnumber {
color: $u-tips-color;
font-size: 24rpx;
}
.msg-body { .msg-body {
display: flex; display: flex;
background-color: rgba(102, 110, 232, 0.0470588235294118); background-color: rgba(102, 110, 232, 0.0470588235294118);
.msgImg { .msgImg {
width: 160rpx; width: 160rpx;
height: 160rpx; height: 160rpx;
@@ -93,7 +108,6 @@ export default {
margin-top: 60rpx; margin-top: 60rpx;
} }
} }
} }
.bagbar { .bagbar {
display: inline; display: inline;
@@ -103,13 +117,8 @@ export default {
padding: 10rpx 20rpx; padding: 10rpx 20rpx;
background: $u-info-disabled; background: $u-info-disabled;
} }
.storeImg {
width: 100%;
height: 100rpx;
margin-right: 20rpx;
}
.container { .container {
background: #F9F9F9; background: #f9f9f9;
min-height: 100vh; min-height: 100vh;
} }
.msgMsg { .msgMsg {
@@ -123,8 +132,4 @@ view{
font-size: 13px; font-size: 13px;
color: #666666; color: #666666;
} }
u-card{
font-size: 13px;
color: #666666;
}
</style> </style>

View File

@@ -2,21 +2,23 @@
<view class="logistics-detail"> <view class="logistics-detail">
<view class="card"> <view class="card">
<view class="card-title"> <view class="card-title">
<span>{{ logiList.shipper }}</span>快递 <span>{{ logiList.logisticCode }}</span> <span>{{ logisticsInfo.shipper }}</span>快递 <span>{{ logisticsInfo.logisticCode }}</span>
</view> </view>
<view class="time-line"> <view class="time-line">
<u-time-line v-if="logiList.traces && logiList.traces.length != 0"> <u-time-line v-if="logisticsInfo.traces && logisticsInfo.traces.length != 0">
<u-time-line-item nodeTop="2" v-for="(item, index) in logiList.traces" :key="index"> <u-time-line-item nodeTop="2" v-for="(item, index) in logisticsInfo.traces" :key="index">
<!-- 此处自定义了左边内容用一个图标替代 --> <template #node>
<template v-slot:node > <view
<view v-if="index == logiList.traces.length - 1" class="u-node" :style="{ background: $lightColor }" style="padding: 0 4px"> v-if="index == logisticsInfo.traces.length - 1"
<!-- 此处为uView的icon组件 --> class="u-node"
:style="{ background: lightColor }"
style="padding: 0 4px"
>
<u-icon name="pushpin-fill" color="#fff" :size="24"></u-icon> <u-icon name="pushpin-fill" color="#fff" :size="24"></u-icon>
</view> </view>
</template> </template>
<template v-slot:content> <template #content>
<view> <view>
<!-- <view class="u-order-title">待取件</view> -->
<view class="u-order-desc">{{ item.AcceptStation }}</view> <view class="u-order-desc">{{ item.AcceptStation }}</view>
<view class="u-order-time">{{ item.AcceptTime }}</view> <view class="u-order-time">{{ item.AcceptTime }}</view>
</view> </view>
@@ -29,32 +31,26 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getExpress } from "@/api/trade.js"; import { ref, computed } from 'vue'
export default { import { onLoad } from '@dcloudio/uni-app'
data() { import { useStore } from '@/store'
return { import { getExpress } from '@/api/trade.js'
express: "",
resData: {
title: "物流详情",
},
logiList: "", const store = useStore()
activeStep: 0,
}; const lightColor = computed(() => store.getters.lightColor)
}, const logisticsInfo = ref<Record<string, any>>({})
methods: {
init(sn) { onLoad((option) => {
getExpress(sn).then((res) => { fetchLogistics(option.order_sn)
this.logiList = res.data.result; })
});
}, function fetchLogistics(orderSn: string) {
}, getExpress(orderSn).then((res) => {
onLoad(option) { logisticsInfo.value = res.data.result || {}
let sn = option.order_sn; })
this.init(sn); }
},
};
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -79,9 +75,6 @@ export default {
padding: 16rpx 32rpx; padding: 16rpx 32rpx;
} }
} }
.u-order-title {
font-weight: bold;
}
.u-order-desc { .u-order-desc {
font-size: 26rpx; font-size: 26rpx;
color: #666; color: #666;

View File

@@ -30,20 +30,11 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { mapMutations } from "vuex"; // 占位页,后续接入客服消息
export default {
data() {
return {};
},
methods: {
...mapMutations(["logout"]),
}
};
</script> </script>
<style scoped lang='scss'> <style scoped lang="scss">
.msgTime { .msgTime {
font-size: 13px; font-size: 13px;
} }
@@ -56,11 +47,6 @@ page {
vertical-align: middle; vertical-align: middle;
border-radius: 0.4em; border-radius: 0.4em;
} }
.qicon {
text-align: center;
display: block;
font-size: 20px;
}
.redBox { .redBox {
padding: 10rpx 12rpx; padding: 10rpx 12rpx;
display: inline-block; display: inline-block;
@@ -71,7 +57,6 @@ page {
height: 1em; height: 1em;
background: #ed6533; background: #ed6533;
border-radius: 50%; border-radius: 50%;
color: #fff; color: #fff;
} }
.tit_title, .tit_title,
@@ -97,20 +82,9 @@ page {
position: relative; position: relative;
background: #fff; background: #fff;
justify-content: center; justify-content: center;
&.log-out-btn {
margin-top: 40rpx;
.cell-tit {
color: $uni-color-primary;
text-align: center;
margin-right: 0;
}
}
&.cell-hover { &.cell-hover {
background: #fafafa; background: #fafafa;
} }
&.b-b:after {
left: 30rpx;
}
&.m-t { &.m-t {
margin-top: 16rpx; margin-top: 16rpx;
} }
@@ -119,22 +93,12 @@ page {
margin-top: 10rpx; margin-top: 10rpx;
height: 60rpx; height: 60rpx;
display: flex; display: flex;
justify-content: center; //这个是X轴居中 justify-content: center;
align-items: center; //这个是 Y轴居中 align-items: center;
align-self: baseline; align-self: baseline;
font-size: $font-lg; font-size: $font-lg;
color: $font-color-light; color: $font-color-light;
margin-left: 10rpx; margin-left: 10rpx;
} }
.cell-tit {
flex: 1;
font-size: $font-base + 2rpx;
color: $font-color-dark;
margin-right: 10rpx;
}
.cell-tip {
font-size: $font-base;
color: $font-color-light;
}
} }
</style> </style>

View File

@@ -3,13 +3,11 @@
<block v-for="(row, index) in messageList" :key="index"> <block v-for="(row, index) in messageList" :key="index">
<view class="msgItem"> <view class="msgItem">
<div class="is_read"> <div class="is_read">
<!-- {{row.is_read}} -->
<span v-if="row.is_read"></span> <span v-if="row.is_read"></span>
<span v-else class="red">·</span> <span v-else class="red">·</span>
</div> </div>
<div class="msgMsg">{{$u.timeFormat(row.send_time, 'yyyy-mm-dd')}}</div> <div class="msgMsg">{{ formatSendTime(row.send_time) }}</div>
<u-card :title="title" :title-size="35" :border="false"> <u-card :title="pageTitle" :title-size="35" :border="false">
<template #body> <template #body>
<view class="u-body-item u-flex u-row-between u-p-b-0"> <view class="u-body-item u-flex u-row-between u-p-b-0">
<view class="u-body-item-title u-line-2">{{ row.content }}</view> <view class="u-body-item-title u-line-2">{{ row.content }}</view>
@@ -22,61 +20,72 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { mapMutations } from "vuex"; import { ref, getCurrentInstance } from 'vue'
import * as API_Message from "@/api/message.js"; import { onLoad, onReachBottom } from '@dcloudio/uni-app'
export default { import { useStore } from '@/store'
data() { import * as API_Message from '@/api/message.js'
return {
title: "系统消息",
subTitle: "未读",
finished: false,
loadStatus: "more",
params: {
pageNumber: 0,
pageSize: 5
},
messageList: []
};
},
onLoad() {
this.GET_MessageList(true);
},
onReachBottom() {
this.params.pageNumber++;
this.GET_MessageList(false);
},
methods: {
...mapMutations(["logout"]),
/** 获取站内消息 */ const store = useStore()
GET_MessageList(reset) { const { proxy } = getCurrentInstance()!
const pageTitle = '系统消息'
const loadStatus = ref('more')
const queryParams = ref({ pageNumber: 1, pageSize: 5 })
const messageList = ref<any[]>([])
onLoad(() => {
fetchMessageList(true)
})
onReachBottom(() => {
queryParams.value.pageNumber++
fetchMessageList(false)
})
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
}
function formatSendTime(time: number) {
return proxy.$u.timeFormat(time, 'yyyy-mm-dd')
}
function extractRecords(res: any) {
if (Array.isArray(res?.result?.records)) return res.result.records
if (Array.isArray(res?.result)) return res.result
if (Array.isArray(res?.data)) return res.data
return []
}
function fetchMessageList(reset: boolean) {
if (reset) { if (reset) {
this.params.pageNumber = 1; queryParams.value.pageNumber = 1
this.messageList = []; messageList.value = []
loadStatus.value = 'more'
} }
uni.showLoading({ uni.showLoading({ title: '加载中' })
title: "加载中" API_Message.getMessages(queryParams.value).then((response) => {
}); hideLoadingIfNeeded()
API_Message.getMessages(this.params).then(async response => { const res = response.data
if (this.$store.state.isShowToast){ uni.hideLoading() }; const records = extractRecords(res)
const { data } = response; if (records.length) {
if (!data || !data.length) { messageList.value.push(...records)
this.messageList.push(...data.data); markPageMessagesAsRead()
this.handleReadPageMessages(); } else {
loadStatus.value = 'noMore'
} }
}); })
},
/** 设置消息已读 **/
handleReadPageMessages() {
const ids = this.messageList.map(item => item.id).join(",");
API_Message.messageMarkAsRead(ids).then(async () => {});
} }
function markPageMessagesAsRead() {
const ids = messageList.value.map((item) => item.id).join(',')
if (!ids) return
API_Message.messageMarkAsRead(ids)
} }
};
</script> </script>
<style scoped lang='scss'> <style scoped lang="scss">
.is_read { .is_read {
position: absolute; position: absolute;
right: 25px; right: 25px;

View File

@@ -14,7 +14,7 @@
:activeStyle="{ color: lightColor }" :activeStyle="{ color: lightColor }"
class="collect-tabs" class="collect-tabs"
:list="navList" :list="navList"
:scrollable="true" :scrollable="false"
v-model:current="tabCurrentIndex" v-model:current="tabCurrentIndex"
></u-tabs> ></u-tabs>
</view> </view>
@@ -22,25 +22,24 @@
</u-navbar> </u-navbar>
<view class="collect-body"> <view class="collect-body">
<!-- 显示商品栏 --> <!-- 显示商品栏 -->
<view v-if="tabCurrentIndex == 0" class="tab-content"> <view v-if="tabCurrentIndex === 0" class="tab-content">
<scroll-view class="list-scroll-content" scroll-y>
<u-empty style="margin-top: 40rpx" text="暂无收藏商品数据" mode="favor" v-if="goodsEmpty"></u-empty> <u-empty style="margin-top: 40rpx" text="暂无收藏商品数据" mode="favor" v-if="goodsEmpty"></u-empty>
<template v-else> <template v-else>
<u-swipe-action <u-swipe-action
v-for="(item, index) in goodList" v-for="(item, index) in goodsList"
:key="index" :key="item.skuId || item.goodsId || index"
class="collect-swipe" class="collect-swipe"
> >
<u-swipe-action-item <u-swipe-action-item
@open="openLeftChange(item, 'goods')" @open="openSwipeItem(item, 'goods')"
:show="item.selected" :show="item.selected"
:options="LeftOptions" :options="swipeOptions"
@click="clickGoodsSwiperAction(item, index)" @click="removeGoodsCollection(item, index)"
:name="index" :name="index"
> >
<view class="goods" @click="goGoodsDetail(item)"> <view class="goods" @click="goGoodsDetail(item)">
<u-image width="131rpx" height="131rpx" :src="item.image" mode="aspectFit"> <u-image width="131rpx" height="131rpx" :src="item.image" mode="aspectFit">
<template #loading><u-loading></u-loading></template> <template #loading><u-loading-icon></u-loading-icon></template>
</u-image> </u-image>
<view class="goods-intro"> <view class="goods-intro">
<view class="goods-name">{{ item.goodsName }}</view> <view class="goods-name">{{ item.goodsName }}</view>
@@ -51,23 +50,21 @@
</u-swipe-action-item> </u-swipe-action-item>
</u-swipe-action> </u-swipe-action>
</template> </template>
</scroll-view>
</view> </view>
<!-- 显示收藏的店铺栏 --> <!-- 显示收藏的店铺栏 -->
<view v-else class="tab-content"> <view v-else class="tab-content">
<scroll-view class="list-scroll-content" scroll-y>
<u-empty style="margin-top: 40rpx" text="暂无收藏店铺数据" mode="favor" v-if="storeEmpty"></u-empty> <u-empty style="margin-top: 40rpx" text="暂无收藏店铺数据" mode="favor" v-if="storeEmpty"></u-empty>
<template v-else> <template v-else>
<u-swipe-action <u-swipe-action
v-for="(item, index) in storeList" v-for="(item, index) in storeList"
:key="index" :key="item.id || index"
class="collect-swipe" class="collect-swipe"
> >
<u-swipe-action-item <u-swipe-action-item
@open="openLeftChange(item, 'store')" @open="openSwipeItem(item, 'store')"
:show="item.selected" :show="item.selected"
:options="LeftOptions" :options="swipeOptions"
@click="clickStoreSwiperAction(item)" @click="removeStoreCollection(item)"
:name="index" :name="index"
> >
<view class="store" @click="goStoreMainPage(item.id)"> <view class="store" @click="goStoreMainPage(item.id)">
@@ -75,12 +72,12 @@
<view class="store-logo"> <view class="store-logo">
<u-image width="102rpx" height="102rpx" :src="item.storeLogo" :alt="item.storeName" <u-image width="102rpx" height="102rpx" :src="item.storeLogo" :alt="item.storeName"
mode="aspectFit"> mode="aspectFit">
<template #loading><u-loading></u-loading></template> <template #loading><u-loading-icon></u-loading-icon></template>
</u-image> </u-image>
</view> </view>
<view class="store-name"> <view class="store-name">
<view>{{ item.storeName }}</view> <view>{{ item.storeName }}</view>
<u-tag size="mini" type="error" :color="$mainColor" v-if="item.selfOperated" <u-tag size="mini" type="error" :color="mainColor" v-if="item.selfOperated"
text="自营" mode="plain" shape="circle" /> text="自营" mode="plain" shape="circle" />
</view> </view>
<view class="store-collect"> <view class="store-collect">
@@ -91,209 +88,172 @@
</u-swipe-action-item> </u-swipe-action-item>
</u-swipe-action> </u-swipe-action>
</template> </template>
</scroll-view>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { ref, computed } from 'vue'
import { onShow, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { unitPrice } from '@/utils/filters.js'
import { import {
getGoodsCollection, getGoodsCollection,
getStoreCollection, getStoreCollection,
deleteGoodsCollection, deleteGoodsCollection,
deleteStoreCollection, deleteStoreCollection,
} from "@/api/members.js"; } from '@/api/members.js'
export default {
data() { const store = useStore()
return {
lightColor:this.$lightColor, const lightColor = computed(() => store.getters.lightColor)
// 商品左滑侧边栏 const mainColor = computed(() => store.getters.mainColor)
LeftOptions: [{
text: "取消", const swipeOptions = computed(() => [
style: {
backgroundColor: this.$lightColor,
},
}, ],
tabCurrentIndex: 0, //tab的下标默认为0也就是说会默认请求商品
navList: [
//tab显示数据
{ {
name: "商品(0)", text: '取消',
style: { backgroundColor: lightColor.value },
},
])
params: { const tabCurrentIndex = ref(0)
pageNumber: 1, const navList = ref([
pageSize: 10, { name: '商品(0)', params: { pageNumber: 1, pageSize: 10 } },
}, { name: '店铺(0)', params: { pageNumber: 1, pageSize: 10 } },
}, ])
{ const goodsEmpty = ref(false)
name: "店铺(0)", const storeEmpty = ref(false)
const goodsList = ref<any[]>([])
const storeList = ref<any[]>([])
params: { onShow(() => {
pageNumber: 1, reloadOrLoadMore('reload')
pageSize: 10, })
},
},
],
goodsEmpty: false, //商品数据是否为空 onReachBottom(() => {
storeEmpty: false, //店铺数据是否为空 reloadOrLoadMore('next')
goodList: [], //商品集合 })
storeList: [], //店铺集合
};
},
onShow() {
this.fetchReloadOrNextPage('reload')
},
onReachBottom() {
this.fetchReloadOrNextPage('next')
},
methods: { onPullDownRefresh(() => {
// 刷新或者下一页 if (tabCurrentIndex.value === 0) {
fetchReloadOrNextPage(type) { navList.value[0].params.pageNumber = 1
if(type == 'next'){ goodsList.value = []
this.navList[this.tabCurrentIndex].params.pageNumber ++; fetchGoodsList()
if (this.tabCurrentIndex == 0) {
this.getGoodList();
} else { } else {
this.getStoreList(); navList.value[1].params.pageNumber = 1
storeList.value = []
fetchStoreList()
} }
} })
else{
this.navList[0].params.pageNumber = 1;
this.navList[1].params.pageNumber = 1;
this.goodList = [];
this.storeList = [];
this.getGoodList();
this.getStoreList();
}
},
/** function hideLoadingIfNeeded() {
* 打开商品左侧取消收藏 if (store.state.isShowToast) uni.hideLoading()
*/ }
openLeftChange(val, type) {
const way = type === "goods" ? this.goodList : this.storeList;
way.forEach((item) => {
item.selected = false;
});
val.selected = true;
},
/** function reloadOrLoadMore(type: 'reload' | 'next') {
* 点击商品左侧取消收藏 if (type === 'next') {
*/ navList.value[tabCurrentIndex.value].params.pageNumber++
clickGoodsSwiperAction(val) { if (tabCurrentIndex.value === 0) {
fetchGoodsList()
} else {
fetchStoreList()
}
return
}
navList.value[0].params.pageNumber = 1
navList.value[1].params.pageNumber = 1
goodsEmpty.value = false
storeEmpty.value = false
goodsList.value = []
storeList.value = []
fetchGoodsList()
fetchStoreList()
}
function openSwipeItem(val: any, type: 'goods' | 'store') {
const targetList = type === 'goods' ? goodsList.value : storeList.value
targetList.forEach((item) => {
item.selected = false
})
val.selected = true
}
function removeGoodsCollection(val: any) {
deleteGoodsCollection(val.skuId).then((res) => { deleteGoodsCollection(val.skuId).then((res) => {
if (res.statusCode == 200) { if (res.statusCode === 200) {
this.storeList = []; goodsList.value = []
this.goodList = []; navList.value[0].params.pageNumber = 1
this.getGoodList(); fetchGoodsList()
}
})
} }
});
},
/** function removeStoreCollection(val: any) {
* 点击店铺左侧取消收藏
*/
clickStoreSwiperAction(val) {
deleteStoreCollection(val.id).then((res) => { deleteStoreCollection(val.id).then((res) => {
if (res.statusCode == 200) { if (res.statusCode === 200) {
this.storeList = []; storeList.value = []
this.getStoreList(); navList.value[1].params.pageNumber = 1
fetchStoreList()
}
})
} }
});
},
/** function goGoodsDetail(val: any) {
* 查看商品详情
*/
goGoodsDetail(val) {
//商品详情
uni.navigateTo({ uni.navigateTo({
url: "/pages/product/goods?id=" + val.skuId + "&goodsId=" + val.goodsId, url: `/pages/product/goods?id=${val.skuId}&goodsId=${val.goodsId}`,
}); })
}, }
/** function goStoreMainPage(id: string) {
* 查看店铺详情
*/
goStoreMainPage(id) {
//店铺主页
uni.navigateTo({ uni.navigateTo({
url: "/pages/product/shopPage?id=" + id, url: `/pages/product/shopPage?id=${id}`,
}); })
}, }
/** function fetchGoodsList() {
* 获取商品集合 uni.showLoading({ title: '加载中' })
*/ getGoodsCollection(navList.value[0].params, 'GOODS')
getGoodList() { .then((res) => {
uni.showLoading({ hideLoadingIfNeeded()
title: "加载中", uni.stopPullDownRefresh()
});
getGoodsCollection(this.navList[0].params, "GOODS").then((res) => {
if (this.$store.state.isShowToast){ uni.hideLoading() };
uni.stopPullDownRefresh();
if (res.data.success) { if (res.data.success) {
let data = res.data.result; const data = res.data.result
data.selected = false; navList.value[0].name = `商品(${data.total})`
this.navList[0].name = `商品(${data.total})`; goodsEmpty.value = data.total === 0
if (data.records?.length) {
if (data.total == 0) { const records = data.records.map((item: any) => ({ ...item, selected: false }))
this.goodsEmpty = true; goodsList.value.push(...records)
} else if (data.total < 10) {
this.goodsLoad = "noMore";
this.goodList.push(...data.records);
} else {
this.goodList.push(...data.records);
if (data.total.length < 10) this.goodsLoad = "noMore";
} }
} }
}); })
}, .catch(() => {
hideLoadingIfNeeded()
uni.stopPullDownRefresh()
})
}
/** function fetchStoreList() {
* 获取店铺集合 uni.showLoading({ title: '加载中' })
*/ getStoreCollection(navList.value[1].params, 'STORE')
getStoreList() { .then((res) => {
uni.showLoading({ hideLoadingIfNeeded()
title: "加载中", uni.stopPullDownRefresh()
});
getStoreCollection(this.navList[1].params, "STORE").then((res) => {
if (this.$store.state.isShowToast){ uni.hideLoading() };
uni.stopPullDownRefresh();
if (res.data.success) { if (res.data.success) {
let data = res.data.result; const data = res.data.result
data.selected = false; navList.value[1].name = `店铺(${data.total})`
this.navList[1].name = `店铺(${data.total})`; storeEmpty.value = data.total === 0
if (data.total == 0) { if (data.records?.length) {
this.storeEmpty = true; const records = data.records.map((item: any) => ({ ...item, selected: false }))
} else if (data.total < 10) { storeList.value.push(...records)
this.storeList.push(...data.records);
} }
} }
}); })
}, .catch(() => {
}, hideLoadingIfNeeded()
uni.stopPullDownRefresh()
/** })
* 下拉刷新时
*/
onPullDownRefresh() {
if (this.tabCurrentIndex == 0) {
this.navList[0].params.pageNumber = 1;
this.goodList = [];
this.getGoodList();
} else {
this.navList[1].params.pageNumber = 1;
this.storeList = [];
this.getStoreList();
} }
},
};
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -324,15 +284,18 @@
.collect-body { .collect-body {
flex: 1; flex: 1;
min-height: 0; width: 100%;
} }
.tab-content { .tab-content {
height: 100%; width: 100%;
} }
.list-scroll-content { :deep(.u-tabs),
height: 100%; :deep(.u-tabs__wrapper),
:deep(.u-tabs__wrapper__scroll-view-wrapper),
:deep(.u-tabs__wrapper__scroll-view),
:deep(.u-tabs__wrapper__nav) {
width: 100%; width: 100%;
} }

View File

@@ -7,14 +7,14 @@
:auto-back="true" :auto-back="true"
> >
<template #right> <template #right>
<div class="light-color edit" @click="isEdit = !isEdit">{{ !isEdit ? '编辑' : '完成'}}</div> <view class="light-color edit" @click="isEdit = !isEdit">{{ !isEdit ? '编辑' : '完成'}}</view>
</template> </template>
</u-navbar> </u-navbar>
<view class="tracks-tip"> <view class="tracks-tip">
<u-icon name="volume" color="#f9ae3d" size="19"></u-icon> <u-icon name="volume" color="#f9ae3d" size="19"></u-icon>
<text class="tracks-tip-text">右划删除浏览记录</text> <text class="tracks-tip-text">右划删除浏览记录</text>
</view> </view>
<u-empty text="暂无历史记录" style="margin-top:200rpx;" mode="history" v-if="whetherEmpty"></u-empty> <u-empty text="暂无历史记录" style="margin-top:200rpx;" mode="history" v-if="isEmpty"></u-empty>
<view v-else class="tracks-list"> <view v-else class="tracks-list">
<block v-for="(item, index) in trackList" :key="index"> <block v-for="(item, index) in trackList" :key="index">
<view <view
@@ -26,9 +26,9 @@
<u-swipe-action-item <u-swipe-action-item
:show="item.show" :show="item.show"
:name="index" :name="index"
@click="delTracks" @click="deleteTracks"
@open="open" @open="openSwipe"
:options="options" :options="swipeOptions"
> >
<view class="myTracks-item"> <view class="myTracks-item">
<u-checkbox-group v-if="isEdit" class="store-line-check"> <u-checkbox-group v-if="isEdit" class="store-line-check">
@@ -37,7 +37,7 @@
shape="circle" shape="circle"
:active-color="lightColor" :active-color="lightColor"
v-model:checked="item.checked" v-model:checked="item.checked"
@change="checkboxChangeDP(item)" @change="onTrackCheckChange(item)"
></u-checkbox> ></u-checkbox>
</u-checkbox-group> </u-checkbox-group>
<view class="myTracks-item-img" @click.stop="navigateToDetail(item)"> <view class="myTracks-item-img" @click.stop="navigateToDetail(item)">
@@ -56,7 +56,7 @@
</u-swipe-action> </u-swipe-action>
<view class="myTracks-divider"></view> <view class="myTracks-divider"></view>
</block> </block>
<view v-if="isEdit" class="submit" @click="handleClickDeleteSelected"> <view v-if="isEdit" class="submit" @click="deleteSelectedTracks">
删除所选 删除所选
</view> </view>
</view> </view>
@@ -64,172 +64,147 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { import { ref, computed } from 'vue'
myTrackList, import { onShow, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
deleteHistoryListId import { useStore } from '@/store'
} from "@/api/members.js"; import { unitPrice } from '@/utils/filters.js'
import { getStoreBaseInfo } from "@/api/store.js"; import { myTrackList, deleteHistoryListId } from '@/api/members.js'
import { getStoreBaseInfo } from '@/api/store.js'
export default { const store = useStore()
data() { const lightColor = computed(() => store.getters.lightColor)
return {
isEdit:false, const isEdit = ref(false)
whetherEmpty: false, //是否数据为空 const isEmpty = ref(false)
params: { const params = ref({
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
order: "desc", order: 'desc',
sort: "updateTime", sort: 'updateTime',
}, })
lightColor:this.$lightColor, const swipeOptions = [{ text: '删除', style: { backgroundColor: '#dd524d' } }]
options: [{ const trackList = ref<any[]>([])
text: '删除', const storeNameMap = ref<Record<string, string>>({})
style: {
backgroundColor: '#dd524d'
}
}],
trackList: [], //足迹列表
storeNameMap: {},
};
},
/** onReachBottom(() => {
* 滑到底部加载下一页数据 params.value.pageNumber++
*/ fetchTrackList()
onReachBottom() { })
this.params.pageNumber++;
this.getList(); onShow(() => {
}, params.value.pageNumber = 1
onShow() { trackList.value = []
this.params.pageNumber = 1 fetchTrackList()
this.trackList = []; })
this.getList();
}, onPullDownRefresh(() => {
onPullDownRefresh() { params.value.pageNumber = 1
this.trackList = []; trackList.value = []
this.getList(); fetchTrackList()
}, })
methods: {
getStoreName(item) { function getStoreName(item: any) {
return item.storeName || this.storeNameMap[item.storeId] || ""; return item.storeName || storeNameMap.value[item.storeId] || ''
}, }
async enrichStoreNames(records) {
async function enrichStoreNames(records: any[]) {
const storeIds = [ const storeIds = [
...new Set( ...new Set(
records records
.filter((item) => !item.storeName && item.storeId) .filter((item) => !item.storeName && item.storeId)
.map((item) => item.storeId) .map((item) => item.storeId)
), ),
].filter((storeId) => !this.storeNameMap[storeId]); ].filter((storeId) => !storeNameMap.value[storeId])
await Promise.all( await Promise.all(
storeIds.map(async (storeId) => { storeIds.map(async (storeId) => {
try { try {
const res = await getStoreBaseInfo(storeId); const res = await getStoreBaseInfo(storeId)
const name = res.data?.result?.storeName; const name = res.data?.result?.storeName
if (name) { if (name) {
this.storeNameMap[storeId] = name; storeNameMap.value[storeId] = name
} }
} catch (e) { } catch {
// ignore // ignore
} }
}) })
); )
},
checkboxChangeDP(val){
console.log(val)
},
// 删除所选的数据
handleClickDeleteSelected(val){
const ids = this.trackList.filter(item=>item.checked).map(item=>item.goodsId);
if(!ids.length){
uni.showToast({
title:"请选择删除数据",
icon:"none"
})
}else{
this.delTracks(0,ids)
} }
},
/**
* 导航到店铺
*/
navigateToStore(val) {
uni.navigateTo({
url: "/pages/product/shopPage?id=" + val.storeId,
});
},
open(index) {
// 先将正在被操作的swipeAction标记为打开状态否则由于props的特性限制
// 原本为'false',再次设置为'false'会无效
this.trackList[index].show = true;
this.trackList.map((val, idx) => {
if (index != idx) this.trackList[idx].show = false;
})
},
/**
* 跳转详情
*/
navigateToDetail(item) {
uni.navigateTo({
url: "/pages/product/goods?id=" + item.id + "&goodsId=" + item.goodsId,
});
},
/** function onTrackCheckChange(_val: any) {
* 获取我的足迹列表 // 勾选状态由 v-model:checked 维护
*/ }
getList() {
uni.showLoading({ function deleteSelectedTracks() {
title: "加载中", const ids = trackList.value.filter((item) => item.checked).map((item) => item.goodsId)
}); if (!ids.length) {
myTrackList(this.params).then(async (res) => { uni.showToast({ title: '请选择删除数据', icon: 'none' })
uni.stopPullDownRefresh(); return
uni.hideLoading(); }
if (res.statusCode == 200) { deleteTracks(0, ids)
const records = res.data.result.records || []; }
records.forEach((item) => {
item.show = false; function navigateToStore(val: any) {
item.checked = false; uni.navigateTo({ url: `/pages/product/shopPage?id=${val.storeId}` })
}); }
function openSwipe(index: number) {
trackList.value[index].show = true
trackList.value.forEach((val, idx) => {
if (index !== idx) val.show = false
})
}
function navigateToDetail(item: any) {
uni.navigateTo({
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
})
}
function fetchTrackList() {
uni.showLoading({ title: '加载中' })
myTrackList(params.value).then(async (res) => {
uni.stopPullDownRefresh()
uni.hideLoading()
if (res.statusCode === 200) {
const records = res.data.result.records || []
records.forEach((item: any) => {
item.show = false
item.checked = false
})
if (!records.length) { if (!records.length) {
if (this.trackList.length === 0) { if (trackList.value.length === 0) {
this.whetherEmpty = true; isEmpty.value = true
} }
} else { } else {
await this.enrichStoreNames(records); isEmpty.value = false
this.trackList.push(...records); await enrichStoreNames(records)
trackList.value.push(...records)
} }
} }
}); })
}, }
function deleteTracks(e: any, ids?: any) {
/** const index = typeof e === 'object' ? (e.name ?? e.index) : e
* 删除足迹 const goodsId = ids || trackList.value[index]?.goodsId
*/ if (!goodsId) return
delTracks(e, ids) {
const index = typeof e === 'object' ? (e.name ?? e.index) : e;
const goodsId = ids || this.trackList[index]?.goodsId;
if (!goodsId) return;
deleteHistoryListId(goodsId).then((res) => { deleteHistoryListId(goodsId).then((res) => {
if (res.data.code == 200) { if (res.data.code === 200) {
this.trackList = []; trackList.value = []
this.params.pageNumber = 1 params.value.pageNumber = 1
this.getList(); fetchTrackList()
} else { } else {
uni.showToast({ uni.showToast({
title: res.data.message, title: res.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}
})
} }
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -11,16 +11,16 @@
<view class="point-summary"> <view class="point-summary">
<view class="point-summary-item"> <view class="point-summary-item">
<text>累计获得</text> <text>累计获得</text>
<text class="pcolor">{{ pointData.totalPoint || 0 }}</text> <text class="pcolor">{{ pointSummary.totalPoint || 0 }}</text>
</view> </view>
<view class="point-summary-divider"></view> <view class="point-summary-divider"></view>
<view class="point-summary-item"> <view class="point-summary-item">
<text>剩余积分</text> <text>剩余积分</text>
<text class="pcolor">{{ pointData.point || 0 }}</text> <text class="pcolor">{{ pointSummary.point || 0 }}</text>
</view> </view>
</view> </view>
<div class="point-list"> <view class="point-list">
<view class="point-item" v-for="(item, index) in pointList" :key="index"> <view class="point-item" v-for="(item, index) in pointList" :key="index">
<view class="point-item-left"> <view class="point-item-left">
<view class="point-label">{{ item.content }}</view> <view class="point-label">{{ item.content }}</view>
@@ -30,80 +30,76 @@
<text>{{ item.pointType == "INCREASE" ? "+" : "-" }}</text>{{ item.variablePoint }} <text>{{ item.pointType == "INCREASE" ? "+" : "-" }}</text>{{ item.variablePoint }}
</view> </view>
</view> </view>
<uni-load-more :status="count.loadStatus"></uni-load-more> <uni-load-more :status="loadStatus"></uni-load-more>
</div> </view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getPointsData } from "@/api/members.js"; import { ref } from 'vue'
import { getMemberPointSum } from "@/api/members.js"; import { onLoad, onReachBottom } from '@dcloudio/uni-app'
export default { import { useStore } from '@/store'
data() { import { getPointsData, getMemberPointSum } from '@/api/members.js'
return {
count: {
loadStatus: "more",
},
pointList: [], //积分数据集合
params: {
pageNumber: 1,
pageSize: 10,
},
pointData: {}, //累计获取 未输入 集合
};
},
onLoad() { const store = useStore()
this.initPointData();
this.getList();
},
/** const loadStatus = ref('more')
* 触底加载 const pointList = ref<any[]>([])
*/ const params = ref({ pageNumber: 1, pageSize: 10 })
onReachBottom() { const pointSummary = ref<Record<string, any>>({})
this.params.pageNumber++;
this.getList(); onLoad(() => {
}, fetchPointSummary()
methods: { fetchPointLogList()
/** })
* 获取积分数据
*/ onReachBottom(() => {
getList() { params.value.pageNumber++
let params = this.params; fetchPointLogList()
uni.showLoading({ })
title: "加载中",
}); function hideLoadingIfNeeded() {
getPointsData(params).then((res) => { if (store.state.isShowToast) uni.hideLoading()
if (this.$store.state.isShowToast){ uni.hideLoading() }; }
function fetchPointLogList() {
uni.showLoading({ title: '加载中' })
getPointsData(params.value).then((res) => {
hideLoadingIfNeeded()
if (res.data.success) { if (res.data.success) {
let data = res.data.result.records; const data = res.data.result.records || []
if (data.length < 10) { if (data.length < params.value.pageSize) {
this.count["loadStatus"] = "noMore"; loadStatus.value = 'noMore'
this.pointList.push(...data);
} else {
this.pointList.push(...data);
if (data.length < 10) this.count["loadStatus"] = "noMore";
} }
pointList.value.push(...data)
}
})
} }
});
},
/** function fetchPointSummary() {
* 获得累计积分使用
*/
initPointData() {
getMemberPointSum().then((res) => { getMemberPointSum().then((res) => {
this.pointData = res.data.result; pointSummary.value = res.data.result
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss">
page,
.content {
min-height: 100vh;
background: #f9f9f9;
}
.content {
overflow: hidden;
}
.point-list { .point-list {
margin-top: 20rpx; margin-top: 20rpx;
background: #f9f9f9;
min-height: calc(100vh - 390rpx);
padding-bottom: 24rpx;
box-sizing: border-box;
} }
.title { .title {
height: 80rpx; height: 80rpx;
@@ -181,10 +177,6 @@ export default {
} }
} }
.content {
background: #f9f9f9;
}
.more { .more {
text-align: right; text-align: right;
color: $u-tips-color; color: $u-tips-color;
@@ -246,4 +238,8 @@ export default {
margin-bottom: 10rpx; margin-bottom: 10rpx;
color: #666666; color: #666666;
} }
.point-list .uni-load-more {
background: #f9f9f9;
}
</style> </style>

View File

@@ -16,7 +16,7 @@
<u-cell-group class="cell-group" :border="false"> <u-cell-group class="cell-group" :border="false">
<!-- #ifdef APP-PLUS --> <!-- #ifdef APP-PLUS -->
<u-cell v-if="IosWhether" is-link title="去评分" @click="checkStar"></u-cell> <u-cell v-if="showIosRating" is-link title="去评分" @click="openAppStoreRating"></u-cell>
<u-cell is-link title="功能介绍" @click="navigateTo('/pages/mine/set/versionFunctionList')"></u-cell> <u-cell is-link title="功能介绍" @click="navigateTo('/pages/mine/set/versionFunctionList')"></u-cell>
<u-cell is-link title="检查更新" @click="checkUpdate"></u-cell> <u-cell is-link title="检查更新" @click="checkUpdate"></u-cell>
<!-- #endif --> <!-- #endif -->
@@ -40,93 +40,72 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import APPUpdate from "@/plugins/APPUpdate"; import { ref } from 'vue'
import config from "@/config/config"; import { onLoad } from '@dcloudio/uni-app'
import { getAppVersion } from "@/api/message.js"; import APPUpdate from '@/plugins/APPUpdate'
export default { import config from '@/config/config'
data() { import { getAppVersion } from '@/api/message.js'
return {
config, const showIosRating = ref(false)
IosWhether: false, const versionData = ref<Record<string, any>>({})
editionHistory: [], const localVersion = ref<Record<string, any>>({})
versionData: {}, const params = ref<Record<string, any>>({ pageNumber: 1, pageSize: 5 })
localVersion: "",
params: { onLoad(() => {
pageNumber: 1,
pageSize: 5,
},
};
},
onLoad() {
// #ifdef APP-PLUS // #ifdef APP-PLUS
const platform = uni.getSystemInfoSync().platform; const platform = uni.getSystemInfoSync().platform
if (platform === "android") { if (platform === 'android') {
this.params.type = 0; params.value.type = 0
} else { } else {
this.IosWhether = true; showIosRating.value = true
this.params.type = 1; params.value.type = 1
} }
this.getVersion(platform); fetchRemoteVersion(platform)
plus.runtime.getProperty(plus.runtime.appid, (inf) => { plus.runtime.getProperty(plus.runtime.appid, (inf) => {
this.localVersion = { localVersion.value = {
versionCode: inf.version.replace(/\./g, ""), versionCode: inf.version.replace(/\./g, ''),
version: inf.version, version: inf.version,
}; }
}); })
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
const accountInfo = wx.getAccountInfoSync(); const accountInfo = wx.getAccountInfoSync()
this.version_number = accountInfo.miniProgram.version; localVersion.value = {
this.localVersion = { versionCode: accountInfo.miniProgram.version.replace(/\./g, ''),
versionCode: accountInfo.miniProgram.version.replace(/\./g, ""),
version: accountInfo.miniProgram.version, version: accountInfo.miniProgram.version,
envVersion: accountInfo.miniProgram.envVersion, envVersion: accountInfo.miniProgram.envVersion,
};
// #endif
},
methods: {
async getVersion(platform) {
let type;
platform == "android" ? (type = "ANDROID") : (type = "IOS");
let res = await getAppVersion(type);
if (res.data.success) {
this.versionData = res.data.result;
} }
}, // #endif
})
navigateTo(url) { async function fetchRemoteVersion(platform: string) {
uni.navigateTo({ const type = platform === 'android' ? 'ANDROID' : 'IOS'
url, const res = await getAppVersion(type)
}); if (res.data.success) {
}, versionData.value = res.data.result
}
}
checkStar() { function navigateTo(url: string) {
uni.navigateTo({ url })
}
function openAppStoreRating() {
plus.runtime.launchApplication({ plus.runtime.launchApplication({
action: `itms-apps://itunes.apple.com/app/${config.iosAppId}?action=write-review`, action: `itms-apps://itunes.apple.com/app/${config.iosAppId}?action=write-review`,
}); })
}, }
checkUpdate() { function checkUpdate() {
if ( if (versionData.value.version?.replace(/\./g, '') < localVersion.value.versionCode) {
this.versionData.version.replace(/\./g, "") < APPUpdate()
this.localVersion.versionCode } else {
) { uni.showToast({ title: '当前版本已是最新版', duration: 2000, icon: 'none' })
APPUpdate(); }
} else {
uni.showToast({
title: "当前版本已是最新版",
duration: 2000,
icon: "none",
});
} }
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -4,9 +4,9 @@
<view class="box-title">猜你想问</view> <view class="box-title">猜你想问</view>
<view <view
class="feedBack-item" class="feedBack-item"
:class="{ active: feedBack.type == item.value }" :class="{ active: feedbackForm.type == item.value }"
@click="handleClick(index)" @click="selectFeedbackType(index)"
v-for="(item, index) in list" v-for="(item, index) in feedbackTypeList"
:key="index" :key="index"
> >
{{ item.text }} {{ item.text }}
@@ -15,11 +15,11 @@
<view class="feedBack-box"> <view class="feedBack-box">
<view class="box-title">问题反馈 <view class="box-title">问题反馈
<text class="box-tag" v-if="feedBack.type">@{{ list.find(item => item.value == feedBack.type).text }}</text> <text class="box-tag" v-if="feedbackForm.type">@{{ feedbackTypeList.find(item => item.value == feedbackForm.type)?.text }}</text>
</view> </view>
<u-textarea <u-textarea
class="field-textarea" class="field-textarea"
v-model="feedBack.context" v-model="feedbackForm.context"
placeholder="请输入反馈信息" placeholder="请输入反馈信息"
border="none" border="none"
height="240" height="240"
@@ -39,7 +39,7 @@
<view class="box-title">手机号</view> <view class="box-title">手机号</view>
<u-input <u-input
class="field-input" class="field-input"
v-model="feedBack.mobile" v-model="feedbackForm.mobile"
type="number" type="number"
maxlength="11" maxlength="11"
border="none" border="none"
@@ -48,98 +48,69 @@
></u-input> ></u-input>
</view> </view>
<view class="submit" @click="submit()">提交</view> <view class="submit" @click="submitFeedback">提交</view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import storage from "@/utils/storage.js"; import { ref, reactive, getCurrentInstance } from 'vue'
import config from "@/config/config"; import { feedBack as submitFeedBackApi } from '@/api/members.js'
import { feedBack } from "@/api/members.js"; import { handleUploadAfterRead } from '@/utils/uploadHelper.js'
import { handleUploadAfterRead } from "@/utils/uploadHelper.js";
export default {
data() {
return {
storage,
config,
feedBack: {
type: "FUNCTION",
context: "",
mobile: "",
},
inputStyle: {
background: "#fafafa",
borderRadius: "12rpx",
padding: "0 24rpx",
height: "80rpx",
},
uploadFileList: [],
list: [
{ text: "功能相关", value: "FUNCTION" },
{ text: "优化反馈", value: "OPTIMIZE" },
{ text: "其他", value: "OTHER" },
],
};
},
methods: {
// 点击反馈内容
handleClick(index) {
this.feedBack["type"] = this.list[index].value;
},
onUploadAfterRead(event) { const { proxy } = getCurrentInstance()!
handleUploadAfterRead(event, this.uploadFileList, (urls) => {
this.feedBack.images = urls.join(",");
});
},
/** const feedbackForm = reactive({
* 提交意见反馈 type: 'FUNCTION',
*/ context: '',
submit() { mobile: '',
if (!this.feedBack.type) { images: '',
uni.showToast({ })
title: "请填写反馈类型", const inputStyle = {
duration: 2000, background: '#fafafa',
icon: "none", borderRadius: '12rpx',
}); padding: '0 24rpx',
return false; height: '80rpx',
} }
if (!this.feedBack.context) { const uploadFileList = ref<any[]>([])
uni.showToast({ const feedbackTypeList = [
title: "请填写反馈信息", { text: '功能相关', value: 'FUNCTION' },
duration: 2000, { text: '优化反馈', value: 'OPTIMIZE' },
icon: "none", { text: '其他', value: 'OTHER' },
}); ]
return false;
function selectFeedbackType(index: number) {
feedbackForm.type = feedbackTypeList[index].value
} }
if (this.feedBack.mobile && !this.$u.test.mobile(this.feedBack.mobile)) {
uni.showToast({ function onUploadAfterRead(event: any) {
title: "请填写您的正确手机号", handleUploadAfterRead(event, uploadFileList.value, (urls) => {
duration: 2000, feedbackForm.images = urls.join(',')
icon: "none", })
});
return false;
} }
/** 提交 */
feedBack(this.feedBack).then((res) => { function submitFeedback() {
if (!feedbackForm.type) {
uni.showToast({ title: '请填写反馈类型', duration: 2000, icon: 'none' })
return
}
if (!feedbackForm.context) {
uni.showToast({ title: '请填写反馈信息', duration: 2000, icon: 'none' })
return
}
if (feedbackForm.mobile && !proxy.$u.test.mobile(feedbackForm.mobile)) {
uni.showToast({ title: '请填写您的正确手机号', duration: 2000, icon: 'none' })
return
}
submitFeedBackApi(feedbackForm).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({ title: '提交成功!', duration: 2000, icon: 'none' })
title: "提交成功!",
duration: 2000,
icon: "none",
});
setTimeout(() => { setTimeout(() => {
uni.navigateBack({ uni.navigateBack({ delta: 1 })
delta: 1, }, 500)
}); }
}, 500); })
} }
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -5,48 +5,54 @@
<view>点击修改头像</view> <view>点击修改头像</view>
</view> </view>
<u-form :model="form" ref="uForm" class="form"> <up-form
<u-form-item label="昵称" label-width="150" :border-bottom="true"> :model="form"
ref="uForm"
class="form"
label-position="left"
label-width="180rpx"
>
<up-form-item label="昵称" label-width="180rpx" :border-bottom="true">
<u-input <u-input
v-model="form.nickName" v-model="form.nickName"
border="none" border="none"
input-align="right" input-align="right"
placeholder="请输入昵称" placeholder="请输入昵称"
/> />
</u-form-item> </up-form-item>
<u-form-item label="性别" label-width="150" :border-bottom="true"> <up-form-item label="性别" label-width="180rpx" :border-bottom="true">
<view class="sex-row"> <view class="sex-row">
<u-radio-group v-model="form.sex" :active-color="lightColor" :gap="40"> <u-radio-group v-model="form.sex" :active-color="lightColor" :gap="40">
<u-radio name="1" label="男" shape="circle"></u-radio> <u-radio name="1" label="男" shape="circle"></u-radio>
<u-radio name="0" label="女" shape="circle"></u-radio> <u-radio name="0" label="女" shape="circle"></u-radio>
</u-radio-group> </u-radio-group>
</view> </view>
</u-form-item> </up-form-item>
<u-form-item label="生日" label-width="150" :border-bottom="true"> <up-form-item label="生日" label-width="180rpx" :border-bottom="true">
<view class="form-value" @click="showBirthday = true"> <view class="form-value" @click="showBirthday = true">
{{ birthday || '请选择出生日期' }} {{ birthday || '请选择出生日期' }}
</view> </view>
<template #right> <template #right>
<u-icon name="arrow-right" color="#ccc" size="16"></u-icon> <u-icon name="arrow-right" color="#ccc" size="16"></u-icon>
</template> </template>
</u-form-item> </up-form-item>
<u-form-item label="城市" label-width="150" :border-bottom="true"> <up-form-item label="城市" label-width="180rpx" :border-bottom="true">
<view class="form-value" @click="clickRegion"> <view class="form-value" @click="clickRegion">
{{ form.___path || '请选择城市' }} {{ form.regionPath || '请选择城市' }}
</view> </view>
<template #right> <template #right>
<u-icon name="arrow-right" color="#ccc" size="16"></u-icon> <u-icon name="arrow-right" color="#ccc" size="16"></u-icon>
</template> </template>
</u-form-item> </up-form-item>
<u-form-item label="手机号" label-width="150" :border-bottom="false"> <up-form-item label="手机号" label-width="180rpx" :border-bottom="false">
<view v-if="form.mobile" class="form-value">{{ form.mobile }}</view> <view v-if="form.mobile" class="form-value">{{ form.mobile }}</view>
<view v-else class="bind-mobile" @click="navigateTo(form.username)">绑定手机号码</view> <view v-else class="bind-mobile" @click="navigateToBindMobile(form.username)">绑定手机号码</view>
</u-form-item> </up-form-item>
</u-form> </up-form>
<view class="bottom"> <view class="bottom">
<view class="submit" @click="submit">保存</view> <view class="submit" @click="submit">保存</view>
@@ -74,152 +80,135 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { saveUserInfo } from "@/api/members.js"; import { ref, reactive, computed } from 'vue'
import { upload } from "@/api/common.js"; import { onShow } from '@dcloudio/uni-app'
import storage from "@/utils/storage.js"; import { useStore } from '@/store'
import city from "@/components/m-city/m-city.vue"; import { quiteLoginOut } from '@/utils/filters.js'
import { saveUserInfo } from '@/api/members.js'
import { upload } from '@/api/common.js'
import storage from '@/utils/storage.js'
import MCity from '@/components/m-city/m-city.vue'
function parseBirthdayTimestamp(str) { function parseBirthdayTimestamp(str?: string) {
if (!str) { if (!str) return Date.now()
return Date.now(); const timestamp = Date.parse(String(str).replace(/-/g, '/'))
} return Number.isFinite(timestamp) ? timestamp : Date.now()
const timestamp = Date.parse(String(str).replace(/-/g, "/"));
return Number.isFinite(timestamp) ? timestamp : Date.now();
} }
function formatBirthday(timestamp) { function formatBirthday(timestamp: number) {
const date = new Date(timestamp); const date = new Date(timestamp)
const year = date.getFullYear(); const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, "0"); const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, "0"); const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`
} }
export default { const store = useStore()
components: { "m-city": city }, const lightColor = computed(() => store.getters.lightColor)
data() {
const userInfo = storage.getUserInfo() || {}; const userInfo = storage.getUserInfo() || {}
return { const form = reactive<Record<string, any>>({
lightColor: this.$lightColor, nickName: userInfo.nickName || '',
form: { birthday: userInfo.birthday || '',
nickName: userInfo.nickName || "", face: userInfo.face || '/static/missing-face.png',
birthday: userInfo.birthday || "",
face: userInfo.face || "/static/missing-face.png",
regionId: [], regionId: [],
region: userInfo.region || [], region: userInfo.region || [],
sex: userInfo.sex != null ? String(userInfo.sex) : "1", sex: userInfo.sex != null ? String(userInfo.sex) : '1',
___path: userInfo.region, regionPath: userInfo.region,
mobile: userInfo.mobile, mobile: userInfo.mobile,
username: userInfo.username, username: userInfo.username,
}, })
birthday: userInfo.birthday || "", const birthday = ref(userInfo.birthday || '')
birthdayValue: parseBirthdayTimestamp(userInfo.birthday), const birthdayValue = ref(parseBirthdayTimestamp(userInfo.birthday))
minBirthdayDate: new Date("1950-01-01").getTime(), const minBirthdayDate = new Date('1950-01-01').getTime()
maxBirthdayDate: Date.now(), const maxBirthdayDate = Date.now()
region: [ const region = ref([{ id: '', localName: '请选择', children: [] }])
{ const showBirthday = ref(false)
id: "", const cityPicker = ref<any>(null)
localName: "请选择",
children: [],
},
],
showBirthday: false,
};
},
methods: {
getPickerParentValue(e) {
this.form.region = [];
this.form.regionId = [];
let name = "";
e.forEach((item, index) => { function getPickerParentValue(selected: any[]) {
form.region = []
form.regionId = []
let name = ''
selected.forEach((item, index) => {
if (item.id) { if (item.id) {
this.form.region.push(item.localName); form.region.push(item.localName)
this.form.regionId.push(item.id); form.regionId.push(item.id)
if (index == e.length - 1) { name += index === selected.length - 1 ? item.localName : `${item.localName},`
name += item.localName; form.regionPath = name
} else {
name += item.localName + ",";
} }
this.form.___path = name; })
} }
});
},
clickRegion() { function clickRegion() {
this.$refs.cityPicker.show(); cityPicker.value?.show()
}, }
submit() { function submit() {
delete this.form.___path; const params = JSON.parse(JSON.stringify(form))
const params = JSON.parse(JSON.stringify(this.form)); delete params.regionPath
saveUserInfo(params).then((res) => { saveUserInfo(params).then((res) => {
if (res.statusCode == 200) { if (res.statusCode === 200) {
storage.setUserInfo(res.data.result); storage.setUserInfo(res.data.result)
uni.navigateBack(); uni.navigateBack()
}
})
} }
});
},
changeFace() { function changeFace() {
uni.chooseImage({ uni.chooseImage({
success: (chooseImageRes) => { success: (chooseImageRes) => {
const tempFilePaths = chooseImageRes.tempFilePaths;
uni.uploadFile({ uni.uploadFile({
url: upload, url: upload,
filePath: tempFilePaths[0], filePath: chooseImageRes.tempFilePaths[0],
name: "file", name: 'file',
header: { header: { accessToken: storage.getAccessToken() },
accessToken: storage.getAccessToken(),
},
success: (uploadFileRes) => { success: (uploadFileRes) => {
const data = JSON.parse(uploadFileRes.data); const data = JSON.parse(uploadFileRes.data)
this.form.face = data.result; form.face = data.result
}, },
}); })
},
});
}, },
})
}
selectTime(e) { function selectTime(e: any) {
const timestamp = typeof e?.value === "number" ? e.value : this.birthdayValue; const timestamp = typeof e?.value === 'number' ? e.value : birthdayValue.value
const formatted = formatBirthday(timestamp); const formatted = formatBirthday(timestamp)
this.birthdayValue = timestamp; birthdayValue.value = timestamp
this.form.birthday = formatted; form.birthday = formatted
this.birthday = formatted; birthday.value = formatted
this.showBirthday = false; showBirthday.value = false
}, }
closeBirthdayPicker() { function closeBirthdayPicker() {
this.showBirthday = false; showBirthday.value = false
}, }
navigateTo(username) { function navigateToBindMobile(username: string) {
uni.navigateTo({ uni.navigateTo({
url: "/pages/mine/set/securityCenter/bindMobile?username=" + username, url: `/pages/mine/set/securityCenter/bindMobile?username=${username}`,
}); })
}, }
syncUserInfo() { function syncUserInfo() {
const userInfo = storage.getUserInfo() || {}; const latest = storage.getUserInfo() || {}
this.form.nickName = userInfo.nickName || ""; form.nickName = latest.nickName || ''
this.form.birthday = userInfo.birthday || ""; form.birthday = latest.birthday || ''
this.form.face = userInfo.face || "/static/missing-face.png"; form.face = latest.face || '/static/missing-face.png'
this.form.region = userInfo.region || []; form.region = latest.region || []
this.form.sex = userInfo.sex != null ? String(userInfo.sex) : "1"; form.sex = latest.sex != null ? String(latest.sex) : '1'
this.form.___path = userInfo.region; form.regionPath = latest.region
this.form.mobile = userInfo.mobile; form.mobile = latest.mobile
this.form.username = userInfo.username; form.username = latest.username
this.birthday = userInfo.birthday || ""; birthday.value = latest.birthday || ''
this.birthdayValue = parseBirthdayTimestamp(userInfo.birthday); birthdayValue.value = parseBirthdayTimestamp(latest.birthday)
}, }
},
onShow() { onShow(() => {
this.syncUserInfo(); syncUserInfo()
}, })
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,189 +1,173 @@
<template> <template>
<view class="box"> <view class="box">
<view class="box-tips"> <view class="box-tips">
<h2 class='h2'> <h2 class="h2">绑定手机号码</h2>
绑定手机号码
</h2>
<view class="verification"></view> <view class="verification"></view>
</view> </view>
<view class="form"> <view class="form">
<u-form :model="codeForm" ref="validateCodeForm"> <up-form
<view v-if="!validateFlage"> :model="codeForm"
<u-form-item label-width="120" label="手机号" prop="mobile"> ref="validateCodeForm"
label-position="left"
label-width="180rpx"
>
<view v-if="!phoneVerified">
<up-form-item label-width="180rpx" label="手机号" prop="mobile">
<u-input maxlength="11" v-model="codeForm.mobile" placeholder="请输入您的手机号" /> <u-input maxlength="11" v-model="codeForm.mobile" placeholder="请输入您的手机号" />
</u-form-item> </up-form-item>
<u-form-item class="sendCode" label-width="120" prop="code" label="验证码"> <up-form-item class="sendCode" label-width="180rpx" prop="code" label="验证码">
<u-input v-model="codeForm.code" placeholder="请输入验证码" /> <u-input v-model="codeForm.code" placeholder="请输入验证码" />
<u-code unique-key="page-edit" :seconds="seconds" @end="end" @start="start" <u-code
ref="uCode" @change="codeChange"></u-code> unique-key="page-edit"
<view @tap="getCode" class="text-tips">{{ tips }}</view> :seconds="seconds"
</u-form-item> @end="onCodeCountdownEnd"
@start="onCodeCountdownStart"
ref="uCodeRef"
@change="onCodeTextChange"
></u-code>
<view @tap="requestSmsCode" class="text-tips">{{ codeTips }}</view>
</up-form-item>
<view class="submit" @click="validatePhone">绑定</view> <view class="submit" @click="submitBindMobile">绑定</view>
<myVerification keep-running @send="verification" class="verification" ref="verification" <myVerification
business="BIND_MOBILE" /> keep-running
@send="onVerificationPassed"
class="verification"
ref="verificationRef"
business="BIND_MOBILE"
/>
</view> </view>
</u-form> </up-form>
</view> </view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { import { ref, reactive, watch, getCurrentInstance } from 'vue'
sendMobile, import { onLoad, onReady } from '@dcloudio/uni-app'
bindMobile import { useStore } from '@/store'
} from "@/api/login"; import { sendMobile, bindMobile } from '@/api/login'
import { getUserInfo } from "@/api/members.js"; import { getUserInfo } from '@/api/members.js'
import storage from "@/utils/storage.js"; import storage from '@/utils/storage.js'
import MyVerification from '@/components/verification/verification.vue'
import myVerification from "@/components/verification/verification.vue"; //验证 const store = useStore()
import uuid from "@/utils/uuid.modified.js"; const { proxy } = getCurrentInstance()!
export default {
components: {
myVerification,
},
data() {
return {
uuid,
validateFlage: false, //是否进行了手机号验证
step: 0, //当前验证步骤
flage: false, //是否验证码验证
codeForm: {
mobile: "", //手机号
code: "", //验证码
username: "", //用户名
},
tips: "", //提示
seconds: 69, // 60s等待时间
// 验证码登录校验 const phoneVerified = ref(false)
codeRules: { const verificationPassed = ref(false)
mobile: [{ const codeForm = reactive({
validator: (rule, value, callback) => { mobile: '',
return this.$u.test.mobile(value); code: '',
username: '',
})
const codeTips = ref('')
const seconds = 69
const validateCodeForm = ref<any>(null)
const uCodeRef = ref<any>(null)
const verificationRef = ref<any>(null)
const codeRules = {
mobile: [
{
validator: (_rule: any, value: string) => proxy.$u.test.mobile(value),
message: '手机号码不正确',
trigger: ['blur'],
}, },
message: "手机号码不正确", ],
trigger: ["blur"], code: [
}, ], {
code: [{
min: 4, min: 4,
max: 6, max: 6,
required: true, required: true,
message: "请输入验证码", message: '请输入验证码',
trigger: ["blur"], trigger: ['blur'],
}, ],
}, },
}; ],
}, }
onLoad(options) {
this.codeForm.username = options.username; onLoad((options) => {
}, codeForm.username = options?.username || ''
onReady() { })
// 必须要在onReady生命周期因为onLoad生命周期组件可能尚未创建完毕
this.$refs.validateCodeForm.setRules(this.codeRules); onReady(() => {
}, validateCodeForm.value?.setRules(codeRules)
watch: { })
flage(val) {
if (val) { watch(verificationPassed, (val) => {
if (this.$refs.uCode.canGetCode) { if (!val) return
uni.showLoading({ if (!uCodeRef.value?.canGetCode) {
title: "正在获取验证码", proxy.$u.toast('请倒计时结束后再发送')
}); return
sendMobile(this.codeForm.mobile, "BIND_MOBILE").then((res) => { }
if (this.$store.state.isShowToast){ uni.hideLoading() }; uni.showLoading({ title: '正在获取验证码' })
// 这里此提示会被this.start()方法中的提示覆盖 sendMobile(codeForm.mobile, 'BIND_MOBILE').then((res) => {
if (store.state.isShowToast) uni.hideLoading()
if (res.data.success) { if (res.data.success) {
this.$refs.uCode.start(); uCodeRef.value?.start()
} else { } else {
uni.showToast({ uni.showToast({ title: res.data.message, duration: 2000, icon: 'none' })
title: res.data.message, verificationPassed.value = false
duration: 2000, verificationRef.value?.getCode()
icon: "none",
});
this.flage = false;
this.$refs.verification.getCode();
} }
}) })
} else { })
this.$u.toast("请倒计时结束后再发送");
}
}
},
},
methods: { function onVerificationPassed(val: string) {
// 验证码验证 verificationPassed.value = val === store.state.verificationKey
verification(val) { }
this.flage = val == this.$store.state.verificationKey ? true : false;
},
// 验证手机号 function submitBindMobile() {
validatePhone() { validateCodeForm.value?.validate((valid: boolean) => {
this.$refs.validateCodeForm.validate((valid) => { if (!valid) return
if (valid) { bindMobile(codeForm).then((res) => {
bindMobile(this.codeForm).then((res) => {
if (res.data.success) { if (res.data.success) {
this.validateFlage = !this.validateFlage; phoneVerified.value = true
// 获取最新的用户信息并更新缓存 getUserInfo().then((userRes) => {
getUserInfo().then(userRes => {
if (userRes.data.success) { if (userRes.data.success) {
storage.setUserInfo(userRes.data.result); storage.setUserInfo(userRes.data.result)
} }
// 显示成功提示 uni.showToast({ title: '绑定成功!', duration: 2000, icon: 'none' })
uni.showToast({
title: "绑定成功!",
duration: 2000,
icon: "none",
});
// 返回上一页
setTimeout(() => { setTimeout(() => {
uni.navigateBack({ uni.navigateBack({ delta: 1 })
delta: 1, }, 1000)
}); })
}, 1000);
});
} }
}); })
})
} }
});
},
codeChange(text) { function onCodeTextChange(text: string) {
this.tips = text; codeTips.value = text
},
end() {
this.flage = false;
this.$refs.verification.getCode()
},
/**获取验证码 */
getCode() {
if (this.tips == "重新获取") {
this.$refs.verification.error(); //发送
} }
if (!this.$u.test.mobile(this.codeForm.mobile)) {
uni.showToast({
title: "请输入正确手机号",
icon: "none",
});
return false;
}
if (!this.flage) {
this.$refs.verification.error(); //发送
return false;
}
},
start() {
this.$u.toast("验证码已发送");
this.flage = true;
this.$refs.verification.hide(); function onCodeCountdownEnd() {
}, verificationPassed.value = false
}, verificationRef.value?.getCode()
}; }
function requestSmsCode() {
if (codeTips.value === '重新获取') {
verificationRef.value?.error()
}
if (!proxy.$u.test.mobile(codeForm.mobile)) {
uni.showToast({ title: '请输入正确手机号', icon: 'none' })
return
}
if (!verificationPassed.value) {
verificationRef.value?.error()
}
}
function onCodeCountdownStart() {
proxy.$u.toast('验证码已发送')
verificationPassed.value = true
verificationRef.value?.hide()
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import url("@/pages/passport/login.scss"); @import url("@/pages/passport/login.scss");
@@ -192,7 +176,7 @@ import uuid from "@/utils/uuid.modified.js";
} }
.sendCode { .sendCode {
::v-deep .u-form-item--right__content__slot { ::v-deep .u-form-item__body__right__content__slot {
display: flex; display: flex;
} }
} }

View File

@@ -1,122 +1,67 @@
<template> <template>
<view class="box"> <view class="box">
<view class="box-tips"> <view class="box-tips">
<h2 class='h2'> <h2 class="h2">{{ verificationTitle.title }}</h2>
{{verificationTitle.title}}
</h2>
<view class="verification">{{ verificationTitle.desc }}</view> <view class="verification">{{ verificationTitle.desc }}</view>
</view> </view>
<view class="form"> <view class="form">
<u-form :model="codeForm" ref="validateCodeForm"> <up-form
<u-form-item label-width="120" label="旧密码"> :model="codeForm"
ref="validateCodeForm"
label-position="left"
label-width="180rpx"
>
<up-form-item label-width="180rpx" label="旧密码">
<u-input type="password" v-model="oldPassword" placeholder="请输入您的旧密码" /> <u-input type="password" v-model="oldPassword" placeholder="请输入您的旧密码" />
</u-form-item> </up-form-item>
<u-form-item label-width="120" label="密码"> <up-form-item label-width="180rpx" label="密码">
<u-input type="password" v-model="password" placeholder="请输入您的密码" /> <u-input type="password" v-model="password" placeholder="请输入您的密码" />
</u-form-item> </up-form-item>
<u-form-item label-width="120" label="确认密码"> <up-form-item label-width="180rpx" label="确认密码">
<u-input type="password" v-model="newPassword" placeholder="请再次输入您的密码" /> <u-input type="password" v-model="confirmPassword" placeholder="请再次输入您的密码" />
</u-form-item> </up-form-item>
<view class="submit" @click="updatePassword">修改密码</view> <view class="submit" @click="updatePassword">修改密码</view>
</u-form> </up-form>
</view> </view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { import { ref, reactive } from 'vue'
resetByMobile, import { modifyPass } from '@/api/login'
modifyPass import { md5 } from '@/utils/md5.js'
} from "@/api/login";
import { const verificationTitle = {
md5 title: '修改密码',
} from "@/utils/md5.js"; // md5 desc: '请验证并输入密码',
import myVerification from "@/components/verification/verification.vue"; //验证 }
import uuid from "@/utils/uuid.modified.js"; const codeForm = reactive({ mobile: '', code: '' })
export default { const oldPassword = ref('')
components: { const password = ref('')
myVerification, const confirmPassword = ref('')
},
data() {
return {
uuid,
validateFlage: false, //是否进行了手机号验证
verificationTitle: {
title: "修改密码",
desc: "请验证并输入密码",
},
step: 0, //当前验证步骤
flage: false, //是否验证码验证
codeForm: { function updatePassword() {
mobile: "", //手机号 if (password.value !== confirmPassword.value) {
code: "", //验证码 uni.showToast({ title: '两次输入密码不一致!', icon: 'none' })
}, return
newPassword: "", //新密码
password: "", //密码
oldPassword: '', //旧密码
tips: "", //提示
seconds: 69, // 60s等待时间
// 验证码登录校验
codeRules: {
mobile: [{
validator: (rule, value, callback) => {
return this.$u.test.mobile(value);
},
message: "手机号码不正确",
trigger: ["blur"],
}, ],
code: [{
min: 4,
max: 6,
required: true,
message: "请输入验证码",
trigger: ["blur"],
}, ],
},
};
},
onReady() {
// 必须要在onReady生命周期因为onLoad生命周期组件可能尚未创建完毕
this.$refs.validateCodeForm.setRules(this.codeRules);
},
methods: {
// 修改密码
updatePassword() {
if(this.password !== this.newPassword){
uni.showToast({
title: "两次输入密码不一致!",
icon: "none",
});
return;
} }
modifyPass({ modifyPass({
password: md5(this.oldPassword), password: md5(oldPassword.value),
newPassword: md5(this.newPassword), newPassword: md5(password.value),
}).then((res) => { }).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({ title: '修改成功!', duration: 2000, icon: 'none' })
title: "修改成功!",
duration: 2000,
icon: "none",
});
setTimeout(() => { setTimeout(() => {
uni.navigateBack({ uni.navigateBack({ delta: 1 })
delta: 1, }, 1000)
}); }
}, 1000); })
} }
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import url("@/pages/passport/login.scss"); @import url("@/pages/passport/login.scss");
@@ -124,12 +69,6 @@
margin: 40rpx 0; margin: 40rpx 0;
} }
.sendCode {
::v-deep .u-form-item--right__content__slot {
display: flex;
}
}
.h2 { .h2 {
font-size: 40rpx; font-size: 40rpx;
font-weight: bold; font-weight: bold;

View File

@@ -1,243 +1,200 @@
<template> <template>
<view class="box"> <view class="box">
<view class="box-tips"> <view class="box-tips">
<h2 class='h2'> <h2 class="h2">{{ verificationTitle[phoneVerified ? 1 : 0].title }}</h2>
{{verificationTitle[validateFlage==false ? 0 : 1].title}}
</h2>
<view class="verification">{{ verificationTitle[step].desc }}</view> <view class="verification">{{ verificationTitle[step].desc }}</view>
</view> </view>
<view class="form"> <view class="form">
<u-form :model="codeForm" ref="validateCodeForm"> <up-form
<view v-if="!validateFlage"> :model="codeForm"
<u-form-item label-width="120" label="手机号" prop="mobile"> ref="validateCodeForm"
label-position="left"
label-width="180rpx"
>
<view v-if="!phoneVerified">
<up-form-item label-width="180rpx" label="手机号" prop="mobile">
<u-input maxlength="11" v-model="codeForm.mobile" placeholder="请输入您的手机号" /> <u-input maxlength="11" v-model="codeForm.mobile" placeholder="请输入您的手机号" />
</u-form-item> </up-form-item>
<u-form-item class="sendCode" label-width="120" prop="code" label="验证码"> <up-form-item class="sendCode" label-width="180rpx" prop="code" label="验证码">
<u-input v-model="codeForm.code" placeholder="请输入验证码" /> <u-input v-model="codeForm.code" placeholder="请输入验证码" />
<u-code unique-key="page-edit" :seconds="seconds" @end="end" @start="start" <u-code
ref="uCode" @change="codeChange"></u-code> unique-key="page-edit"
<view @tap="getCode" class="text-tips">{{ tips }}</view> :seconds="seconds"
</u-form-item> @end="onCodeCountdownEnd"
@start="onCodeCountdownStart"
ref="uCodeRef"
@change="onCodeTextChange"
></u-code>
<view @tap="requestSmsCode" class="text-tips">{{ codeTips }}</view>
</up-form-item>
<view class="submit" @click="validatePhone">验证</view> <view class="submit" @click="verifyMobile">验证</view>
<myVerification keep-running @send="verification" class="verification" ref="verification" <myVerification
business="FIND_USER" /> keep-running
@send="onVerificationPassed"
class="verification"
ref="verificationRef"
business="FIND_USER"
/>
</view> </view>
<view v-if="validateFlage"> <view v-if="phoneVerified">
<u-form-item label-width="120" label="密码"> <up-form-item label-width="180rpx" label="密码">
<u-input type="password" v-model="password" placeholder="请输入您的密码" /> <u-input type="password" v-model="password" placeholder="请输入您的密码" />
</u-form-item> </up-form-item>
<u-form-item label-width="120" label="确认密码"> <up-form-item label-width="180rpx" label="确认密码">
<u-input type="password" v-model="newPassword" placeholder="请再次输入您的密码" /> <u-input type="password" v-model="confirmPassword" placeholder="请再次输入您的密码" />
</u-form-item> </up-form-item>
<view class="submit" @click="updatePassword">修改密码</view> <view class="submit" @click="updatePassword">修改密码</view>
</view> </view>
</u-form> </up-form>
</view> </view>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { import { ref, reactive, watch, getCurrentInstance } from 'vue'
sendMobile, import { onReady } from '@dcloudio/uni-app'
resetByMobile, import { useStore } from '@/store'
resetPassword import { isLogin } from '@/utils/filters.js'
} from "@/api/login"; import { sendMobile, resetByMobile, resetPassword } from '@/api/login'
import { md5 } from '@/utils/md5.js'
import MyVerification from '@/components/verification/verification.vue'
import { const store = useStore()
md5 const { proxy } = getCurrentInstance()!
} from "@/utils/md5.js"; // md5
import myVerification from "@/components/verification/verification.vue"; //验证 const phoneVerified = ref(false)
import uuid from "@/utils/uuid.modified.js"; const verificationPassed = ref(false)
export default { const verificationTitle = [
components: { { title: '安全验证', desc: '请输入当前手机号进行安全验证' },
myVerification, { title: '修改密码', desc: '请输入新密码' },
}, ]
data() { const step = ref(0)
return { const codeForm = reactive({ mobile: '', code: '' })
uuid, const password = ref('')
validateFlage: false, //是否进行了手机号验证 const confirmPassword = ref('')
verificationTitle: [{ const codeTips = ref('')
title: "安全验证", const seconds = 69
desc: "请输入当前手机号进行安全验证",
}, const validateCodeForm = ref<any>(null)
const uCodeRef = ref<any>(null)
const verificationRef = ref<any>(null)
const codeRules = {
mobile: [
{ {
title: "修改密码", validator: (_rule: any, value: string) => proxy.$u.test.mobile(value),
desc: "请输入新密码", message: '手机号码不正确',
trigger: ['blur'],
}, },
], ],
step: 0, //当前验证步骤 code: [
flage: false, //是否验证码验证 {
codeForm: {
mobile: "", //手机号
code: "", //验证码
},
newPassword: "", //新密码
password: "", //密码
tips: "", //提示
seconds: 69, // 60s等待时间
// 验证码登录校验
codeRules: {
mobile: [{
validator: (rule, value, callback) => {
return this.$u.test.mobile(value);
},
message: "手机号码不正确",
trigger: ["blur"],
}, ],
code: [{
min: 4, min: 4,
max: 6, max: 6,
required: true, required: true,
message: "请输入验证码", message: '请输入验证码',
trigger: ["blur"], trigger: ['blur'],
}, ],
}, },
}; ],
}, }
onReady() {
// 必须要在onReady生命周期因为onLoad生命周期组件可能尚未创建完毕
this.$refs.validateCodeForm.setRules(this.codeRules);
},
watch: {
flage(val) {
if (val) {
if (this.$refs.uCode.canGetCode) { onReady(() => {
uni.showLoading({ validateCodeForm.value?.setRules(codeRules)
title: "正在获取验证码", })
});
sendMobile(this.codeForm.mobile, "FIND_USER").then((res) => { watch(verificationPassed, (val) => {
if (this.$store.state.isShowToast){ uni.hideLoading() }; if (!val) return
// 这里此提示会被this.start()方法中的提示覆盖 if (!uCodeRef.value?.canGetCode) {
proxy.$u.toast('请倒计时结束后再发送')
return
}
uni.showLoading({ title: '正在获取验证码' })
sendMobile(codeForm.mobile, 'FIND_USER').then((res) => {
if (store.state.isShowToast) uni.hideLoading()
if (res.data.success) { if (res.data.success) {
this.$refs.uCode.start(); uCodeRef.value?.start()
} else { } else {
uni.showToast({ uni.showToast({ title: res.data.message, duration: 2000, icon: 'none' })
title: res.data.message, verificationPassed.value = false
duration: 2000, verificationRef.value?.getCode()
icon: "none",
});
this.flage = false;
this.$refs.verification.getCode();
} }
}) })
} else { })
this.$u.toast("请倒计时结束后再发送");
}
}
},
},
methods: { function onVerificationPassed(val: string) {
// 修改密码 verificationPassed.value = val === store.state.verificationKey
updatePassword() {
if(this.password !== this.newPassword){
uni.showToast({
title: "两次输入密码不一致!",
icon: "none",
});
return;
} }
resetPassword({
password: md5(this.password), function updatePassword() {
}).then((res) => { if (password.value !== confirmPassword.value) {
uni.showToast({ title: '两次输入密码不一致!', icon: 'none' })
return
}
resetPassword({ password: md5(password.value) }).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({ title: '修改成功!', duration: 2000, icon: 'none' })
title: "修改成功!",
duration: 2000,
icon: "none",
});
setTimeout(() => { setTimeout(() => {
uni.navigateBack({ uni.navigateBack({ delta: 1 })
delta: 1, }, 1000)
}); }
}, 1000); })
} }
});
},
// 验证码验证 function verifyMobile() {
verification(val) { validateCodeForm.value?.validate((valid: boolean) => {
this.flage = val == this.$store.state.verificationKey ? true : false; if (!valid) return
}, resetByMobile(codeForm).then((res) => {
// 验证手机号
validatePhone() {
this.$refs.validateCodeForm.validate((valid) => {
if (valid) {
resetByMobile(this.codeForm).then((res) => {
if (res.data.success) { if (res.data.success) {
this.validateFlage = !this.validateFlage; phoneVerified.value = true
// 登录成功 uni.showToast({ title: '验证成功!', icon: 'none' })
uni.showToast({
title: "验证成功!",
icon: "none",
});
} }
}); })
} })
});
},
codeChange(text) {
this.tips = text;
},
end() {
this.flage = false;
this.$refs.verification.getCode()
},
/**判断是否是当前用户的手机号 */
isUserPhone() {
let flage = false;
let user = this.isLogin();
if (user.mobile != this.codeForm.mobile) {
uni.showToast({
title: "请输入当前绑定手机号",
icon: "none",
});
flage = false;
} else {
flage = true;
} }
return flage; function onCodeTextChange(text: string) {
}, codeTips.value = text
/**获取验证码 */
getCode() {
if (this.isUserPhone()) {
if (this.tips == "重新获取") {
this.$refs.verification.error(); //发送
} }
if (!this.$u.test.mobile(this.codeForm.mobile)) {
uni.showToast({
title: "请输入正确手机号",
icon: "none",
});
return false;
}
if (!this.flage) {
this.$refs.verification.error(); //发送
return false;
}
}
},
start() {
this.$u.toast("验证码已发送");
this.flage = true;
this.$refs.verification.hide(); function onCodeCountdownEnd() {
}, verificationPassed.value = false
}, verificationRef.value?.getCode()
}; }
function isCurrentUserPhone() {
const user = isLogin()
if (user?.mobile !== codeForm.mobile) {
uni.showToast({ title: '请输入当前绑定手机号', icon: 'none' })
return false
}
return true
}
function requestSmsCode() {
if (!isCurrentUserPhone()) return
if (codeTips.value === '重新获取') {
verificationRef.value?.error()
}
if (!proxy.$u.test.mobile(codeForm.mobile)) {
uni.showToast({ title: '请输入正确手机号', icon: 'none' })
return
}
if (!verificationPassed.value) {
verificationRef.value?.error()
}
}
function onCodeCountdownStart() {
proxy.$u.toast('验证码已发送')
verificationPassed.value = true
verificationRef.value?.hide()
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import url("@/pages/passport/login.scss"); @import url("@/pages/passport/login.scss");
@@ -246,7 +203,7 @@
} }
.sendCode { .sendCode {
::v-deep .u-form-item--right__content__slot { ::v-deep .u-form-item__body__right__content__slot {
display: flex; display: flex;
} }
} }

View File

@@ -4,7 +4,7 @@
<u-cell-group> <u-cell-group>
<u-cell class="border-top" :isLink="false" title="面容登录"> <u-cell class="border-top" :isLink="false" title="面容登录">
<template #right-icon> <template #right-icon>
<u-switch @change="faceSwitchChange" active-color="#1abc9c" size="40" v-model="checked"></u-switch> <u-switch @change="onFaceSwitchChange" active-color="#1abc9c" size="40" v-model="enabled"></u-switch>
</template> </template>
</u-cell> </u-cell>
</u-cell-group> </u-cell-group>
@@ -12,74 +12,65 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import storage from "@/utils/storage.js"; import { ref } from 'vue'
import { setBiolofy } from "@/api/passport.js"; import { onLoad } from '@dcloudio/uni-app'
import storage from '@/utils/storage.js'
import { setBiolofy } from '@/api/passport.js'
export default { const enabled = ref(false)
data() {
return { onLoad(() => {
lightColor: this.$lightColor,
checked: true,
};
},
methods: {
faceSwitchChange(value) {
if (value === true) {
const res = uni.getSystemInfoSync();
plus.device.getInfo({
success: function (e) {
let params = {
mobile_type: res.model,
secret_key: e.uuid,
};
setBiolofy(params).then((res) => {
if (res.statusCode === 200) {
storage.setFaceLogin(true);
}
});
},
fail: function (e) {
//plus.nativeUI.toast('获取设备信息错误:' + JSON.stringify(e));
console.error("getDeviceInfo failed: " + JSON.stringify(e));
},
});
} else {
storage.setFaceLogin(false);
}
},
},
onLoad() {
// #ifdef APP-PLUS // #ifdef APP-PLUS
uni.checkIsSupportSoterAuthentication({ uni.checkIsSupportSoterAuthentication({
success(res) { success(res) {
if (!res.supportMode.find((e) => e === "facial")) { if (!res.supportMode.find((e) => e === 'facial')) {
plus.nativeUI.toast("此设备不支持面部识别"); plus.nativeUI.toast('此设备不支持面部识别')
uni.navigateBack(); uni.navigateBack()
} }
uni.checkIsSoterEnrolledInDevice({ uni.checkIsSoterEnrolledInDevice({
checkAuthMode: "facial", checkAuthMode: 'facial',
success(_res) { success(_res) {
if (!_res.isEnrolled) { if (!_res.isEnrolled) {
plus.nativeUI.toast("此设备未录入面部信息"); plus.nativeUI.toast('此设备未录入面部信息')
uni.navigateBack(); uni.navigateBack()
} }
}, },
fail(_err) { fail() {
// plus.nativeUI.toast(JSON.stringify(_err)); uni.navigateBack()
uni.navigateBack();
}, },
}); })
},
fail() {
uni.navigateBack()
},
})
enabled.value = storage.getFaceLogin() || false
// #endif
})
function onFaceSwitchChange(value: boolean) {
if (value) {
const systemInfo = uni.getSystemInfoSync()
plus.device.getInfo({
success(e) {
setBiolofy({
mobile_type: systemInfo.model,
secret_key: e.uuid,
}).then((res) => {
if (res.statusCode === 200) {
storage.setFaceLogin(true)
}
})
}, },
fail(err) { fail(err) {
// plus.nativeUI.toast(JSON.stringify(err)); console.error('getDeviceInfo failed: ' + JSON.stringify(err))
uni.navigateBack();
}, },
}); })
this.checked = storage.getFaceLogin() || false; } else {
// #endif storage.setFaceLogin(false)
}, }
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -4,7 +4,7 @@
<u-cell-group> <u-cell-group>
<u-cell class="border-top" :isLink="false" title="指纹登录"> <u-cell class="border-top" :isLink="false" title="指纹登录">
<template #right-icon> <template #right-icon>
<u-switch @change="fingerSwitchChange" :active-color="lightColor" size="40" v-model="checked"></u-switch> <u-switch @change="onFingerSwitchChange" :active-color="lightColor" size="40" v-model="enabled"></u-switch>
</template> </template>
</u-cell> </u-cell>
</u-cell-group> </u-cell-group>
@@ -12,60 +12,57 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import storage from "@/utils/storage.js"; import { ref, computed } from 'vue'
import { setBiolofy } from "@/api/passport.js"; import { onLoad } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import storage from '@/utils/storage.js'
import { setBiolofy } from '@/api/passport.js'
export default { const store = useStore()
data() { const lightColor = computed(() => store.getters.lightColor)
return { const enabled = ref(false)
lightColor: this.$lightColor,
checked: false, onLoad(() => {
};
},
methods: {
fingerSwitchChange(value) {
if (value === true) {
const res = uni.getSystemInfoSync();
plus.device.getInfo({
success: function (e) {
let params = {
mobile_type: res.model,
secret_key: e.uuid,
};
setBiolofy(params).then((res) => {
if (res.statusCode === 200) {
storage.setFingerLogin(true);
}
});
},
fail: function (e) {
console.error("getDeviceInfo failed: " + JSON.stringify(e));
},
});
} else {
storage.setFingerLogin(false);
}
},
},
onLoad() {
// #ifdef APP-PLUS // #ifdef APP-PLUS
if (!plus.fingerprint.isSupport()) { if (!plus.fingerprint.isSupport()) {
plus.nativeUI.toast("此设备不支持指纹识别"); plus.nativeUI.toast('此设备不支持指纹识别')
uni.navigateBack(); uni.navigateBack()
} }
if (!plus.fingerprint.isKeyguardSecure()) { if (!plus.fingerprint.isKeyguardSecure()) {
plus.nativeUI.toast("此设备未设置密码锁屏"); plus.nativeUI.toast('此设备未设置密码锁屏')
uni.navigateBack(); uni.navigateBack()
} }
if (!plus.fingerprint.isEnrolledFingerprints()) { if (!plus.fingerprint.isEnrolledFingerprints()) {
plus.nativeUI.toast("此设备未录入指纹"); plus.nativeUI.toast('此设备未录入指纹')
uni.navigateBack(); uni.navigateBack()
} }
this.checked = storage.getFingerLogin() || false; enabled.value = storage.getFingerLogin() || false
// #endif // #endif
})
function onFingerSwitchChange(value: boolean) {
if (value) {
const systemInfo = uni.getSystemInfoSync()
plus.device.getInfo({
success(e) {
setBiolofy({
mobile_type: systemInfo.model,
secret_key: e.uuid,
}).then((res) => {
if (res.statusCode === 200) {
storage.setFingerLogin(true)
}
})
}, },
}; fail(err) {
console.error('getDeviceInfo failed: ' + JSON.stringify(err))
},
})
} else {
storage.setFingerLogin(false)
}
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -2,56 +2,44 @@
<view class="securityCenter"> <view class="securityCenter">
<u-cell-group> <u-cell-group>
<u-cell title="修改密码" @click="navigateTo('/pages/mine/set/securityCenter/updatePwdTab')"></u-cell> <u-cell title="修改密码" @click="navigateTo('/pages/mine/set/securityCenter/updatePwdTab')"></u-cell>
<u-cell title="注销账户" @click="zhuxiao"></u-cell> <u-cell title="注销账户" @click="confirmAccountDeletion"></u-cell>
</u-cell-group> </u-cell-group>
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { function navigateTo(url: string) {
data() { uni.navigateTo({ url })
return { }
mobile: "", //存储手机号
};
},
methods: {
zhuxiao(){
function confirmAccountDeletion() {
uni.showModal({ uni.showModal({
title: "警告", title: '警告',
content: "您确定要注销当前账号吗?", content: '您确定要注销当前账号吗?',
confirmText: "确定注销", confirmText: '确定注销',
confirmColor: "#FF0000", confirmColor: '#FF0000',
cancelText: "取消", cancelText: '取消',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
uni.showModal({ uni.showModal({
title: "谨慎操作", title: '谨慎操作',
content: "再次向您确认,您确定要注销当前账号吗?", content: '再次向您确认,您确定要注销当前账号吗?',
confirmText: "坚持注销", confirmText: '坚持注销',
confirmColor: "#FF0000", confirmColor: '#FF0000',
cancelText: "取消", cancelText: '取消',
success: (res) => { success: (confirmRes) => {
if (res.confirm) { if (confirmRes.confirm) {
uni.showToast({ uni.showToast({
title: "您的注销申请已经提交,待管理员审核后。会自动注销当前账号", title: '您的注销申请已经提交,待管理员审核后。会自动注销当前账号',
duration: 10000, duration: 10000,
}); })
} }
}, },
}); })
} }
}, },
}); })
}, }
navigateTo(url) {
uni.navigateTo({
url: url,
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -7,22 +7,10 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { function navigateTo(url: string) {
data() { uni.navigateTo({ url })
return { }
mobile: "", //存储手机号
};
},
methods: {
navigateTo(url) {
uni.navigateTo({
url: url,
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -38,112 +38,95 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import config from "@/config/config"; import { ref } from 'vue'
export default { import { onShow } from '@dcloudio/uni-app'
data() { import config from '@/config/config'
return { import { isLogin, tipsToLogin, quiteLoginOut, logoff } from '@/utils/filters.js'
config,
userImage: config.defaultUserPhoto,
isCertificate: false,
userInfo: {},
fileSizeString: "0B",
};
},
methods: { const userImage = config.defaultUserPhoto
navigateTo(url) { const userInfo = ref<Record<string, any>>({})
if (url == "/pages/set/securityCenter/securityCenter") { const fileSizeString = ref('0B')
url += `?mobile=${this.userInfo.mobile}`;
onShow(() => {
userInfo.value = isLogin() || {}
// #ifdef APP-PLUS
getCacheSize()
// #endif
})
function navigateTo(url: string) {
if (url === '/pages/mine/set/securityCenter/securityCenter') {
url += `?mobile=${userInfo.value.mobile || ''}`
}
uni.navigateTo({ url })
} }
uni.navigateTo({
url: url,
});
},
getCacheSize() { function getCacheSize() {
let that = this; // #ifdef APP-PLUS
plus.cache.calculate(function (size) { plus.cache.calculate((size) => {
let sizeCache = parseInt(size); const sizeCache = parseInt(String(size))
if (sizeCache == 0) { if (sizeCache === 0) {
that.fileSizeString = "0B"; fileSizeString.value = '0B'
} else if (sizeCache < 1024) { } else if (sizeCache < 1024) {
that.fileSizeString = sizeCache + "B"; fileSizeString.value = `${sizeCache}B`
} else if (sizeCache < 1048576) { } else if (sizeCache < 1048576) {
that.fileSizeString = (sizeCache / 1024).toFixed(2) + "KB"; fileSizeString.value = `${(sizeCache / 1024).toFixed(2)}KB`
} else if (sizeCache < 1073741824) { } else if (sizeCache < 1073741824) {
that.fileSizeString = (sizeCache / 1048576).toFixed(2) + "MB"; fileSizeString.value = `${(sizeCache / 1048576).toFixed(2)}MB`
} else { } else {
that.fileSizeString = (sizeCache / 1073741824).toFixed(2) + "GB"; fileSizeString.value = `${(sizeCache / 1073741824).toFixed(2)}GB`
}
})
// #endif
} }
});
},
checkUserInfo() { function checkUserInfo() {
if (this.isLogin("auth")) { if (isLogin('auth')) {
this.navigateTo("/pages/mine/set/personMsg"); navigateTo('/pages/mine/set/personMsg')
} else { } else {
this.tipsToLogin(); tipsToLogin()
}
} }
},
clearCache() { function clearCache() {
let that = this; // #ifdef APP-PLUS
let os = plus.os.name; const os = plus.os.name
if (os == "Android") { if (os === 'Android') {
let main = plus.android.runtimeMainActivity(); const main = plus.android.runtimeMainActivity()
let sdRoot = main.getCacheDir(); const sdRoot = main.getCacheDir()
let files = plus.android.invoke(sdRoot, "listFiles"); const files = plus.android.invoke(sdRoot, 'listFiles')
let len = files.length; const len = files.length
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
let filePath = "" + files[i]; const filePath = `${files[i]}`
plus.io.resolveLocalFileSystemURL( plus.io.resolveLocalFileSystemURL(
filePath, filePath,
function (entry) { (entry) => {
if (entry.isDirectory) { if (entry.isDirectory) {
entry.removeRecursively( entry.removeRecursively(
function () { () => {
uni.showToast({ uni.showToast({ title: '缓存清理完成', duration: 2000, icon: 'none' })
title: "缓存清理完成", getCacheSize()
duration: 2000,
icon: "none",
});
that.getCacheSize();
}, },
function () {} () => {}
); )
} else { } else {
entry.remove(); entry.remove()
} }
}, },
function () { () => {
uni.showToast({ uni.showToast({ title: '文件路径读取失败', duration: 2000, icon: 'none' })
title: "文件路径读取失败",
duration: 2000,
icon: "none",
});
} }
); )
} }
} else { } else {
plus.cache.clear(function () { plus.cache.clear(() => {
uni.showToast({ uni.showToast({ title: '缓存清理完成', duration: 2000, icon: 'none' })
title: "缓存清理完成", getCacheSize()
duration: 2000, })
icon: "none",
});
that.getCacheSize();
});
} }
},
},
onShow() {
this.userInfo = this.isLogin();
// #ifdef APP-PLUS
this.getCacheSize();
// #endif // #endif
}, }
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,52 +1,40 @@
<template> <template>
<div> <div>
<u-collapse v-if="versionData.length !=0"> <u-collapse v-if="versionList.length !== 0">
<u-collapse-item class="version-item" :title="item.versionName" v-for="(item, index) in versionData" :key="index"> <u-collapse-item
<!-- {{item.body}} --> class="version-item"
:title="item.versionName"
v-for="(item, index) in versionList"
:key="index"
>
{{ item.content }} {{ item.content }}
</u-collapse-item> </u-collapse-item>
</u-collapse> </u-collapse>
<u-empty class="empty" v-else text="暂无版本信息" mode="list"></u-empty> <u-empty class="empty" v-else text="暂无版本信息" mode="list"></u-empty>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { getAppVersionList } from "@/api/message"; import { ref } from 'vue'
export default { import { onLoad } from '@dcloudio/uni-app'
data() { import { getAppVersionList } from '@/api/message'
return {
versionData: [], const versionList = ref<any[]>([])
appType: "", const appType = ref('')
params: { const params = { pageNumber: 1, pageSize: 10 }
pageNumber: 1,
pageSize: 10, onLoad(() => {
}, const platform = uni.getSystemInfoSync().platform
}; appType.value = platform === 'android' ? 'ANDROID' : 'IOS'
}, fetchVersionList()
mounted() { })
const platform = uni.getSystemInfoSync().platform;
/** async function fetchVersionList() {
* 获取是否是安卓 const res = await getAppVersionList(appType.value, params)
*/
if (platform === "android") {
this.appType = "ANDROID";
} else {
this.IosWhether = true;
this.appType = "IOS";
}
this.getVersionList();
},
methods: {
async getVersionList() {
let res = await getAppVersionList(this.appType, this.params);
if (res.data.success) { if (res.data.success) {
this.versionData = res.data.result.records; versionList.value = res.data.result.records
}
} }
},
},
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@@ -54,5 +42,4 @@ export default {
padding: 10rpx; padding: 10rpx;
background: #fff; background: #fff;
} }
</style> </style>

View File

@@ -3,10 +3,10 @@
<view class="date-card"> <view class="date-card">
<div class="box"> <div class="box">
<div class="circle-box"> <div class="circle-box">
<div class="cricle" @click="signIn()"> <div class="cricle" @click="handleSignIn()">
<span v-if="!ifSign" :class="{ active: signFlag || ifSign }">签到</span> <span v-if="!hasSignedToday" :class="{ active: signAnimating || hasSignedToday }">签到</span>
<span v-else :class="{ active: signFlag || ifSign }" <span v-else :class="{ active: signAnimating || hasSignedToday }"
:style="ifSign ? 'transform: rotateY(0deg);' : ''">已签</span> :style="hasSignedToday ? 'transform: rotateY(0deg);' : ''">已签</span>
</div> </div>
</div> </div>
<text class="tips">坚持每天连续签到可以获多重奖励哦</text> <text class="tips">坚持每天连续签到可以获多重奖励哦</text>
@@ -22,19 +22,19 @@
<view class="week"> <view class="week">
<text v-for="item in weekArr" :key="item.id">{{ item }}</text> <text v-for="item in weekArr" :key="item.id">{{ item }}</text>
</view> </view>
<view class="date" v-for="obj in dataObj" :key="obj.id"> <view class="date" v-for="(obj, rowIndex) in calendarRows" :key="rowIndex">
<view class="item" v-for="item in obj" :key="item.id" :class="item == '' ? 'hide' : ''" <view class="item" v-for="(item, dayIndex) in obj" :key="dayIndex" :class="item == '' ? 'hide' : ''"
:animation="item == currentDay ? animationData : ''"> :animation="item == currentDay ? animationData : ''">
<view class="just" :class="signArr.indexOf(item) != -1 ? 'active' : ''"> <view class="just" :class="signedDays.indexOf(item) != -1 ? 'active' : ''">
<view class="top">{{ item }} </view> <view class="top">{{ item }} </view>
<view class="bottom"> <view class="bottom">
<u-icon name="error" v-if="item <= currentDay" size="24" color="#999"></u-icon> <u-icon name="error" v-if="item <= currentDay" size="24" color="#999"></u-icon>
</view> </view>
</view> </view>
<view class="back" :class="signArr.indexOf(item) != -1 ? 'active' : ''" :style=" <view class="back" :class="signedDays.indexOf(item) != -1 ? 'active' : ''" :style="
signArr.indexOf(item) != -1 && ifSign signedDays.indexOf(item) != -1 && hasSignedToday
? 'transform: rotateY(0deg);' ? 'transform: rotateY(0deg);'
: signArr.indexOf(item) != -1 && item != currentDay : signedDays.indexOf(item) != -1 && item != currentDay
? 'transform: rotateY(0deg);' ? 'transform: rotateY(0deg);'
: '' : ''
"> ">
@@ -47,11 +47,11 @@
</view> </view>
</view> </view>
</div> </div>
<view class="mask" :class="{ show: maskFlag, trans: transFlag }" ref="mask"> <view class="mask" :class="{ show: showSuccessMask, trans: maskClosing }" ref="mask">
<view class="mask-header"> <view class="mask-header">
<text class="close"></text> <text class="close"></text>
<text>签到成功</text> <text>签到成功</text>
<text class="close" @click="close">×</text> <text class="close" @click="closeSuccessMask">×</text>
</view> </view>
<view class="mask-con"> <view class="mask-con">
<u-icon size="120" style="margin: 50rpx 0" :color="aiderLightColor" name="checkmark"></u-icon> <u-icon size="120" style="margin: 50rpx 0" :color="aiderLightColor" name="checkmark"></u-icon>
@@ -61,231 +61,147 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { sign, signTime } from "@/api/point.js"; import { ref, computed } from 'vue'
export default { import { onLoad } from '@dcloudio/uni-app'
data() { import { useStore } from '@/store'
return { import { sign, signTime } from '@/api/point.js'
aiderLightColor:this.$aiderLightColor,
signFlag: false,
animationData: {},
maskFlag: false, //
transFlag: false, //动画
weekArr: ["日", "一", "二", "三", "四", "五", "六"], //周数组
dateArr: [], //每个月的天数
monthArr: [
//实例化每个月
"1月",
"2月",
"3月",
"4月",
"5月",
"6月",
"7月",
"8月",
"9月",
"10月",
"11月",
"12月",
], //今天一个月英文
currentMonth: "", //当月
currentMonthIndex: "", //当月
currentYear: "", //今年
currentDay: "", //今天
currentWeek: "", //获取当月一号是周几
dataObj: [], //一个月有多少天这个获取
signArr: [], //本月签到过的天数 该参数用于请求接口后获取当月都哪天签到了
signAll: [], //所有签到数据
ifSign: false, //今天是否签到
};
},
async onLoad() {
//获取签到数据
var response = await signTime(
new Date().getFullYear() + "" + this.makeUp(new Date().getMonth() + 1)
);
this.signAll = response.data.result;
//获取展示数据
this.getDate();
},
methods: {
/**
* 补0
*/
makeUp(val) {
if (val >= 10) {
return val;
} else {
return "0" + val;
}
},
/** const store = useStore()
* 点击签到 const aiderLightColor = computed(() => store.getters.aiderLightColor)
*/
async signIn() { const signAnimating = ref(false)
await sign().then((response) => { const animationData = ref({})
if (this.ifSign) return; const showSuccessMask = ref(false)
if (this.signFlag) return; const maskClosing = ref(false)
if (response.data.code != 200) { const weekArr = ['日', '一', '二', '三', '四', '五', '六']
const monthLabels = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
const currentMonth = ref('')
const currentMonthIndex = ref(0)
const currentYear = ref(0)
const currentDay = ref(0)
const calendarRows = ref<any[][]>([])
const signedDays = ref<number[]>([])
const signRecords = ref<any[]>([])
const hasSignedToday = ref(false)
onLoad(async () => {
const response = await signTime(
`${new Date().getFullYear()}${padZero(new Date().getMonth() + 1)}`
)
signRecords.value = response.data.result
buildCalendar()
})
function padZero(val: number) {
return val >= 10 ? String(val) : `0${val}`
}
async function handleSignIn() {
if (hasSignedToday.value || signAnimating.value) return
const response = await sign()
if (response.data.code !== 200) {
uni.showToast({ uni.showToast({
title: response.data.message, title: response.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return
return false;
} }
var that = this;
var animation = uni.createAnimation({
duration: 200,
timingFunction: "linear",
});
this.signArr.push(this.currentDay);
this.animation = animation;
animation.rotateY(0).step();
this.animationData = animation.export();
setTimeout( const animation = uni.createAnimation({ duration: 200, timingFunction: 'linear' })
function () { signedDays.value.push(currentDay.value)
that.signFlag = true; animation.rotateY(0).step()
this.maskFlag = true; animationData.value = animation.export()
this.ifSign = !this.ifSign;
animation.rotateY(0).step();
this.animationData = animation.export();
}.bind(this),
200
);
});
},
/**
* 签到成功后关闭弹窗
*/
close() {
var that = this;
this.maskFlag = false;
this.transFlag = true;
setTimeout(() => { setTimeout(() => {
that.transFlag = false; signAnimating.value = true
}, 500); showSuccessMask.value = true
}, hasSignedToday.value = true
animation.rotateY(0).step()
/** animationData.value = animation.export()
* 获取今天时间 }, 200)
*
*/
getDate() {
var date = new Date(),
index = date.getMonth(),
curDay = null;
this.currentYear = date.getFullYear();
this.currentMonth = this.monthArr[index];
this.currentMonthIndex = index + 1;
this.currentDay = date.getDate();
if (this.currentDay == this.signArr[this.signArr.length - 1]) {
this.ifSign = true;
} }
curDay = this.getWeekByDay(this.currentYear + "-" + (index + 1) + "-1");
this.getMonthDays(index, curDay);
this.curentSignData();
},
/** function closeSuccessMask() {
* 获取当前已经签到的时间 showSuccessMask.value = false
*/ maskClosing.value = true
curentSignData() { setTimeout(() => {
var date = new Date(), maskClosing.value = false
index = date.getMonth(), }, 500)
curDay = null; }
this.signArr = [];
for (var i = 0; i < this.signAll.length; i++) { function buildCalendar() {
var item = this.signAll[i]; const date = new Date()
item.createTime = item.createTime.split(" ")[0]; const monthIndex = date.getMonth()
var itemVal = item.createTime.split("-"); currentYear.value = date.getFullYear()
currentMonth.value = monthLabels[monthIndex]
currentMonthIndex.value = monthIndex + 1
currentDay.value = date.getDate()
syncSignedDays()
const firstWeekDay = getWeekByDay(`${currentYear.value}-${monthIndex + 1}-1`)
buildMonthDays(monthIndex, firstWeekDay)
}
function syncSignedDays() {
const date = new Date()
const monthIndex = date.getMonth()
signedDays.value = []
hasSignedToday.value = false
signRecords.value.forEach((item) => {
const datePart = item.createTime.split(' ')[0]
const parts = datePart.split('-')
if ( if (
Number(itemVal[0]) === Number(this.currentYear) && Number(parts[0]) === currentYear.value &&
Number(itemVal[1]) === Number(this.currentMonthIndex) Number(parts[1]) === currentMonthIndex.value
) { ) {
this.signArr.push(Number(itemVal[2])); signedDays.value.push(Number(parts[2]))
} }
if ( if (
Number(itemVal[0]) === Number(date.getFullYear()) && Number(parts[0]) === date.getFullYear() &&
Number(itemVal[1]) === Number(index + 1) && Number(parts[1]) === monthIndex + 1 &&
Number(itemVal[2]) === Number(date.getDate()) Number(parts[2]) === date.getDate()
) { ) {
this.ifSign = true; hasSignedToday.value = true
} }
})
} }
},
/** function buildMonthDays(monthIndex: number, firstWeekDay: number) {
* 循环出当前月份的时间 const daysInRow: any[] = []
* 例子: const rows: any[][] = []
* "","","","","","",1, for (let i = 0; i < firstWeekDay; i++) {
* 2 ,3 ,4 ,5 ,6 ,7 ,8, daysInRow.push('')
* ...依次向下排
*/
getMonthDays(index, day) {
//day 当月1号是周几
this.dateArr = [];
this.dataObj = [];
for (var i = 0; i < day; i++) {
this.dateArr.push("");
} }
if (
index == 0 ||
index == 2 ||
index == 4 ||
index == 6 ||
index == 7 ||
index == 9 ||
index == 11
) {
for (let i = 1; i < 32; i++) {
this.dateArr.push(i);
}
}
if (index == 3 || index == 5 || index == 8 || index == 10) {
for (let i = 1; i < 31; i++) {
this.dateArr.push(i);
}
}
if (index == 1) {
if (
(this.currentYear % 4 == 0 && this.currentYear % 100 != 0) ||
this.currentYear % 400 == 0
) {
for (let i = 1; i < 30; i++) {
this.dateArr.push(i);
}
} else {
for (let i = 1; i < 29; i++) {
this.dateArr.push(i);
}
}
}
for (var y = 0; y < 10; y++) {
if (this.dateArr.length > 7) {
this.dataObj.push(this.dateArr.splice(0, 7));
} else {
for (let i = 0; i < 7 - this.dateArr.length; i++) {
this.dateArr.push("");
}
}
}
this.dataObj.push(this.dateArr);
},
/** const isLongMonth = [0, 2, 4, 6, 7, 9, 11].includes(monthIndex)
* 获取当前月份有几周 const isFebruary = monthIndex === 1
*/ let totalDays = isLongMonth ? 31 : 30
getWeekByDay(dayValue) { if (isFebruary) {
var day = new Date(Date.parse(dayValue.replace(/-/g, "/"))).getDay(); //将日期值格式化 const year = currentYear.value
return day; const isLeap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
}, totalDays = isLeap ? 29 : 28
}, }
};
for (let day = 1; day <= totalDays; day++) {
daysInRow.push(day)
}
while (daysInRow.length) {
const row = daysInRow.splice(0, 7)
while (row.length < 7) {
row.push('')
}
rows.push(row)
}
calendarRows.value = rows
}
function getWeekByDay(dayValue: string) {
return new Date(Date.parse(dayValue.replace(/-/g, '/'))).getDay()
}
</script> </script>
<style scoped> <style scoped>
page { page {

View File

@@ -185,6 +185,8 @@ page {
} }
.goods-list-wrap { .goods-list-wrap {
width: 100%;
box-sizing: border-box;
padding-bottom: 40rpx; padding-bottom: 40rpx;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@
:scrollable="false" :scrollable="false"
v-model:current="current" v-model:current="current"
@change="change" @change="change"
:lineColor="$lightColor" :lineColor="lightColor"
:activeStyle="{ color: $lightColor }" :activeStyle="{ color: lightColor }"
></u-tabs> ></u-tabs>
</view> </view>
<div class="u-tabs-search"> <div class="u-tabs-search">
@@ -194,194 +194,152 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import uniLoadMore from "@/components/uni-load-more/uni-load-more.vue"; import { ref, reactive, computed } from 'vue'
import { getAfterSaleList, cancelAfterSale } from "@/api/after-sale.js"; import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
import { getOrderList } from "@/api/order.js"; import { useStore } from '@/store'
import storage from "@/utils/storage"; import { unitPrice, serviceStatusList, parseGoodsImageUrl } from '@/utils/filters.js'
import { getAfterSaleList, cancelAfterSale } from '@/api/after-sale.js'
import { getOrderList } from '@/api/order.js'
import storage from '@/utils/storage'
export default { const store = useStore()
components: { const lightColor = computed(() => store.getters.lightColor)
uniLoadMore,
}, const list = [
data() { { name: '售后申请' },
return { { name: '申请中' },
list: [ { name: '申请记录' },
//tab表头 ]
{
name: "售后申请", const current = ref(0)
}, const tipsShow = ref(false)
{ const cancelShow = ref(false)
name: "申请中", const selectedOrder = ref<any>(null)
}, const orderList = ref<any[]>([])
{ const params = reactive<Record<string, any>>({
name: "申请记录",
},
],
current: 0, //当前表头索引
tipsShow: false, //提示开关
cancelShow: false, //取消显示开关
selectedOrder: "", //选中的order
orderList: [], //订单集合
params: {
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
sort: "createTime", sort: 'createTime',
flowPrice: 0, flowPrice: 0,
order: "desc", order: 'desc',
}, })
const logParams = reactive<Record<string, any>>({
logParams: {
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
}, })
status: "loadmore", const status = ref('loadmore')
keywords: "", // 搜索订单sn const keywords = ref('')
};
}, onLoad((options) => {
onLoad(options) { orderList.value = []
this.orderList = []; params.pageNumber = 1
this.params.pageNumber = 1; if (options?.orderSn) params.keywords = options.orderSn
if (options.orderSn) this.params.keywords = options.orderSn; searchOrderList(current.value)
this.searchOrderList(this.current); })
},
onPullDownRefresh() { onPullDownRefresh(() => {
this.change(this.current); change(current.value)
}, })
methods: {
getGoodsName(sku) { function hideLoadingIfNeeded() {
return sku.goodsName || sku.name || ""; if (store.state.isShowToast) uni.hideLoading()
}, }
getGoodsImage(goods, order, index) {
let image = goods.image || goods.goodsImage || goods.thumbnail; function getGoodsName(sku: any) {
return sku.goodsName || sku.name || ''
}
function getGoodsImage(goods: any, order: any, index: number) {
let image = goods.image || goods.goodsImage || goods.thumbnail
if (!image && order.groupImages) { if (!image && order.groupImages) {
const images = String(order.groupImages).split(","); const images = String(order.groupImages).split(',')
image = images[index] || images[0]; image = images[index] || images[0]
}
return parseGoodsImageUrl(image)
} }
return this.parseGoodsImageUrl(image);
},
/**
* 点击搜索执行搜索
*/
submitSearchOrderList(current) {
this.params.pageNumber = 1;
this.logParams.pageNumber = 1;
this.orderList = [];
this.searchOrderList(current);
},
// 清空
clear(current){
this.params.pageNumber = 1;
this.logParams.pageNumber = 1;
this.params.keywords = ''
this.orderList = [];
this.searchOrderList(current);
},
/**
* 切换tab页时初始化数据
*/
change(e) {
const index = typeof e === 'object' && e != null ? e.index : e;
this.current = index;
this.params = {
pageNumber: 1,
pageSize: 10,
};
this.orderList = [];
//如果是2 则读取售后申请记录列表
this.searchOrderList(index);
uni.stopPullDownRefresh();
},
/** function submitSearchOrderList(tabIndex: number) {
* 搜索初始化 params.pageNumber = 1
* 根据当前tab传值的索引进行更改 logParams.pageNumber = 1
*/ orderList.value = []
searchOrderList(index) { searchOrderList(tabIndex)
}
function clear(tabIndex: number) {
params.pageNumber = 1
logParams.pageNumber = 1
params.keywords = ''
orderList.value = []
searchOrderList(tabIndex)
}
function change(e: number | { index: number }) {
const index = typeof e === 'object' && e != null ? e.index : e
current.value = index
Object.assign(params, { pageNumber: 1, pageSize: 10 })
orderList.value = []
searchOrderList(index)
uni.stopPullDownRefresh()
}
function searchOrderList(index: number) {
if (index == 0) { if (index == 0) {
this.keywords ? (this.params.keywords = this.keywords) : ""; if (keywords.value) params.keywords = keywords.value
this.getOrderList(); fetchOrderList()
} else { } else {
this.logParams = { Object.assign(logParams, {
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
sort: "createTime", sort: 'createTime',
order: "desc", order: 'desc',
}; })
if (index === 1) { if (index === 1) {
this.logParams.serviceStatus = "APPLY"; logParams.serviceStatus = 'APPLY'
}
if (keywords.value) logParams.keywords = keywords.value
orderList.value = []
fetchAfterSaleLogList()
} }
this.keywords ? (this.logParams.keywords = this.keywords) : "";
this.orderList = [];
this.getAfterSaleLogList();
} }
},
/** function fetchOrderList() {
* 获取订单列表 uni.showLoading({ title: '加载中', mask: true })
*/ getOrderList(params).then((res) => {
getOrderList() { hideLoadingIfNeeded()
uni.showLoading({ const records = res.data.result.records
title: "加载中", if (records.length > 0) {
mask: true, orderList.value = orderList.value.concat(records)
}); params.pageNumber += 1
getOrderList(this.params).then((res) => {
if (this.$store.state.isShowToast){ uni.hideLoading() };
const orderList = res.data.result.records;
if (orderList.length > 0) {
this.orderList = this.orderList.concat(orderList);
this.params.pageNumber += 1;
} }
if (orderList.length < 10) { status.value = records.length < 10 ? 'nomore' : 'loading'
this.status = "nomore"; })
} else {
this.status = "loading";
} }
});
},
close(order, sku) { function close(order: any, _sku: any) {
console.log(order, sku); selectedOrder.value = order
this.selectedOrder = order; cancelShow.value = true
this.cancelShow = true; }
},
async closeService() { async function closeService() {
uni.showLoading({ uni.showLoading({ title: '加载中' })
title: "加载中", const res = await cancelAfterSale(selectedOrder.value.sn)
});
console.log(this.selectedOrder);
let res = await cancelAfterSale(this.selectedOrder.sn);
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({ title: '取消成功!', duration: 2000, icon: 'none' })
title: "取消成功!", }
duration: 2000, orderList.value = []
icon: "none", searchOrderList(current.value)
}); hideLoadingIfNeeded()
} }
this.orderList = [];
this.searchOrderList(this.current);
if (this.$store.state.isShowToast){ uni.hideLoading() }; function afterDetails(order: any, _sku?: any) {
}, uni.navigateTo({ url: './applyDetail?sn=' + order.sn })
}
/** function fetchAfterSaleLogList() {
* 售后详情 getAfterSaleList(logParams).then((res) => {
*/ const afterSaleLogList = res.data.result.records
afterDetails(order) { afterSaleLogList.forEach((item: any) => {
uni.navigateTo({
url: "./applyDetail?sn=" + order.sn,
});
},
/**
* 申请记录列表
*/
getAfterSaleLogList() {
getAfterSaleList(this.logParams).then((res) => {
let afterSaleLogList = res.data.result.records;
afterSaleLogList.forEach((item) => {
item.orderItems = [ item.orderItems = [
{ {
image: item.goodsImage, image: item.goodsImage,
@@ -390,83 +348,45 @@ export default {
num: item.num, num: item.num,
price: item.flowPrice, price: item.flowPrice,
}, },
]; ]
}); })
orderList.value = orderList.value.concat(afterSaleLogList)
this.orderList = this.orderList.concat(afterSaleLogList); status.value = afterSaleLogList.length < 10 ? 'nomore' : 'loading'
})
if (afterSaleLogList.length < 10) {
this.status = "nomore";
} else {
this.status = "loading";
} }
});
},
/** function applyService(sn: string, order: any, sku: any) {
* 申请售后 storage.setAfterSaleData({ ...order, ...sku })
*/ uni.navigateTo({ url: `/pages/order/afterSales/afterSalesSelect?sn=${sn}` })
applyService(sn, order, sku) { }
let data = {
...order, function onExpress(order: any, sku: any) {
...sku, sku.storeName = order.storeName
}; storage.setAfterSaleData({ ...order, ...sku })
storage.setAfterSaleData(data); uni.navigateTo({ url: `./afterSalesDetailExpress?serviceSn=${order.sn}` })
}
function onDetail(goods: any, sku: any) {
if (current.value == 0) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/order/afterSales/afterSalesSelect?sn=${sn}`, url: `/pages/product/goods?id=${sku.skuId}&goodsId=${sku.goodsId || sku.goodsId}`,
}); })
},
/**
* 提交物流信息
*/
onExpress(order, sku) {
sku.storeName = order.storeName;
let data = {
...order,
...sku,
};
storage.setAfterSaleData(data);
uni.navigateTo({
url: `./afterSalesDetailExpress?serviceSn=${order.sn}`,
});
},
/**
* 查看详情
*/
onDetail(goods, sku) {
// 售后申请
if (this.current == 0) {
uni.navigateTo({
url: `/pages/product/goods?id=${sku.skuId}&goodsId=${
sku.goodsId || sku.goodsId
}`,
});
} else { } else {
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${goods.skuId}&goodsId=${ url: `/pages/product/goods?id=${goods.skuId}&goodsId=${goods.goodsId || goods.goodsId}`,
goods.goodsId || goods.goodsId })
}`, }
});
} }
},
/** function renderDate() {
* 底部加载数据 if (current.value === 0) {
*/ params.pageNumber += 1
renderDate() { fetchOrderList()
if (this.current === 0) {
this.params.pageNumber += 1;
this.getOrderList();
} else { } else {
this.logParams.pageNumber += 1; logParams.pageNumber += 1
this.getAfterSaleLogList(); fetchAfterSaleLogList()
}
} }
},
},
};
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@@ -1,7 +1,12 @@
<template> <template>
<view class="page-wrap"> <view class="page-wrap">
<scroll-view scroll-y class="page-scroll"> <scroll-view scroll-y class="page-scroll">
<u-form :model="form" ref="uForm"> <up-form
:model="form"
ref="uForm"
label-position="left"
label-width="180rpx"
>
<view class="after-sales-goods-detail-view"> <view class="after-sales-goods-detail-view">
<view class="header"> <view class="header">
<view> <view>
@@ -58,7 +63,7 @@
<u-icon name="arrow-right" color="#ccc" size="16"></u-icon> <u-icon name="arrow-right" color="#ccc" size="16"></u-icon>
</view> </view>
</view> </view>
<u-form-item label="申请说明" label-width="150" :border-bottom="false" class="desc-item"> <up-form-item label="申请说明" label-width="180rpx" :border-bottom="false" class="desc-item">
<u-input <u-input
v-model="form.problemDesc" v-model="form.problemDesc"
type="textarea" type="textarea"
@@ -67,54 +72,54 @@
height="120" height="120"
placeholder="请描述申请售后的说明" placeholder="请描述申请售后的说明"
/> />
</u-form-item> </up-form-item>
</view> </view>
<!-- 退款方式 / 银行信息 --> <!-- 退款方式 / 银行信息 -->
<view class="opt-view form-block"> <view class="opt-view form-block">
<u-form-item label="退款方式" label-width="150" :border-bottom="true"> <up-form-item label="退款方式" label-width="180rpx" :border-bottom="true">
<view class="form-value">{{ <view class="form-value">{{
applyInfo.refundWay == 'ORIGINAL' ? '原路退回' : '账号退款' applyInfo.refundWay == 'ORIGINAL' ? '原路退回' : '账号退款'
}}</view> }}</view>
</u-form-item> </up-form-item>
<template v-if=" <template v-if="
applyInfo.accountType === 'BANK_TRANSFER' && applyInfo.accountType === 'BANK_TRANSFER' &&
applyInfo.applyRefundPrice != 0 applyInfo.applyRefundPrice != 0
"> ">
<u-form-item label="银行开户行" label-width="150" :border-bottom="true"> <up-form-item label="银行开户行" label-width="180rpx" :border-bottom="true">
<u-input <u-input
v-model="form.bankDepositName" v-model="form.bankDepositName"
border="none" border="none"
input-align="right" input-align="right"
placeholder="请输入银行开户行" placeholder="请输入银行开户行"
/> />
</u-form-item> </up-form-item>
<u-form-item label="银行开户名" label-width="150" :border-bottom="true"> <up-form-item label="银行开户名" label-width="180rpx" :border-bottom="true">
<u-input <u-input
v-model="form.bankAccountName" v-model="form.bankAccountName"
border="none" border="none"
input-align="right" input-align="right"
placeholder="请输入银行开户名" placeholder="请输入银行开户名"
/> />
</u-form-item> </up-form-item>
<u-form-item label="银行账号" label-width="150" :border-bottom="true" class="bank-account-item"> <up-form-item label="银行账号" label-width="180rpx" :border-bottom="true" class="bank-account-item">
<u-input <u-input
v-model="form.bankAccountNumber" v-model="form.bankAccountNumber"
border="none" border="none"
input-align="right" input-align="right"
placeholder="请输入银行账号" placeholder="请输入银行账号"
/> />
</u-form-item> </up-form-item>
</template> </template>
<u-form-item <up-form-item
v-if="form.serviceType !== 'RETURN_MONEY'" v-if="form.serviceType !== 'RETURN_MONEY'"
label="返回方式" label="返回方式"
label-width="150" label-width="180rpx"
:border-bottom="false" :border-bottom="false"
> >
<view class="form-value">快递至第三方卖家</view> <view class="form-value">快递至第三方卖家</view>
</u-form-item> </up-form-item>
</view> </view>
<!-- 上传凭证 --> <!-- 上传凭证 -->
@@ -133,7 +138,7 @@
<view class="opt-tip">提交服务单后,售后专员可能与您电话沟通,请保持手机畅通</view> <view class="opt-tip">提交服务单后,售后专员可能与您电话沟通,请保持手机畅通</view>
</view> </view>
</u-form> </up-form>
</scroll-view> </scroll-view>
<view class="submit-view"> <view class="submit-view">
@@ -142,7 +147,7 @@
ripple ripple
shape="circle" shape="circle"
v-if="applyInfo.refundWay" v-if="applyInfo.refundWay"
:custom-style="{ backgroundColor: $lightColor, width: '100%' }" :custom-style="{ backgroundColor: lightColor, width: '100%' }"
@click="onSubmit" @click="onSubmit"
>提交申请</u-button> >提交申请</u-button>
</view> </view>
@@ -158,246 +163,214 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { import { ref, reactive, computed, getCurrentInstance } from 'vue'
getAfterSaleReason, import { onLoad } from '@dcloudio/uni-app'
applyReturn, import { useStore } from '@/store'
getAfterSaleInfo, import { unitPrice, parseGoodsImageUrl } from '@/utils/filters.js'
} from "@/api/after-sale"; import { getAfterSaleReason, applyReturn, getAfterSaleInfo } from '@/api/after-sale'
import { handleUploadAfterRead } from '@/utils/uploadHelper.js'
import storage from '@/utils/storage.js'
import city from "@/components/m-city/m-city"; const store = useStore()
import { handleUploadAfterRead } from "@/utils/uploadHelper.js"; const { proxy } = getCurrentInstance()!
import storage from "@/utils/storage.js"; const $u = proxy!.$u
export default {
component: {
city,
},
data() {
return {
storage,
list: [{ id: "", localName: "请选择", children: [] }],
fileList: [],
sn: "",
sku: {},
typeValue: 0,
value: "",
type: "textarea",
border: true,
//退款原因 弹出框
reasonSelectShow: false,
reasonList: [],
applyInfo: {},
form: {
orderItemSn: "", // 订单sn
skuId: "",
reason: "", //退款原因
problemDesc: "", //退款说明
images: [], //图片凭证
num: 1, //退货数量
goodsId: "", //商品id
accountType: "",
applyRefundPrice: "",
refundWay: "",
serviceType: "", //申请类型
},
};
},
/** const lightColor = computed(() => store.getters.lightColor)
* 判断当前内容并生成数据
*/ const fileList = ref<any[]>([])
onLoad(options) { const sn = ref('')
let navTitle = "申请售后"; const sku = ref<any>({})
this.form.serviceType = "RETURN_GOODS"; const reasonSelectShow = ref(false)
if (options.value == 1) { const reasonList = ref<any[]>([])
navTitle = "申请退货"; const applyInfo = ref<any>({})
this.form.serviceType = "RETURN_GOODS"; const uToast = ref<any>(null)
const form = reactive({
orderItemSn: '',
skuId: '',
reason: '',
problemDesc: '',
images: [] as string[],
num: 1,
goodsId: '',
accountType: '',
applyRefundPrice: '',
refundWay: '',
serviceType: 'RETURN_GOODS',
bankDepositName: '',
bankAccountName: '',
bankAccountNumber: '',
})
onLoad((options) => {
let navTitle = '申请售后'
form.serviceType = 'RETURN_GOODS'
if (options?.value == '1') {
navTitle = '申请退货'
form.serviceType = 'RETURN_GOODS'
} }
if (options.value == 2) { if (options?.value == '2') {
navTitle = "申请换货"; navTitle = '申请换货'
this.form.serviceType = "EXCHANGE_GOODS"; form.serviceType = 'EXCHANGE_GOODS'
} }
if (options.value == 3) { if (options?.value == '3') {
navTitle = "申请退款"; navTitle = '申请退款'
this.form.serviceType = "RETURN_MONEY"; form.serviceType = 'RETURN_MONEY'
} }
this.typeValue = options.value; uni.setNavigationBarTitle({ title: navTitle })
uni.setNavigationBarTitle({ sn.value = options?.sn || ''
title: navTitle, //此处写页面的title sku.value = storage.getAfterSaleData()
}); form.orderItemSn = options?.sn || ''
this.sn = options.sn; form.skuId = sku.value.skuId
this.sku = storage.getAfterSaleData();; form.num = sku.value.num
form.goodsId = sku.value.goodsId
fetchReasonActions(form.serviceType)
init(options?.sn || '')
})
this.form.orderItemSn = options.sn; function hideLoadingIfNeeded() {
this.form.skuId = this.sku.skuId; if (store.state.isShowToast) uni.hideLoading()
this.form.num = this.sku.num; }
this.form.goodsId = this.sku.goodsId;
this.getReasonActions(this.form.serviceType);
this.init(options.sn); function getGoodsName(item: any) {
}, return item.goodsName || item.name || ''
methods: { }
getGoodsName(item) {
return item.goodsName || item.name || ""; function getGoodsImage(item: any) {
}, const image = item.image || item.goodsImage || item.thumbnail
getGoodsImage(item) { return parseGoodsImageUrl(image)
const image = item.image || item.goodsImage || item.thumbnail; }
return this.parseGoodsImageUrl(image);
}, function gotoGoodsDetail(goodsId: string) {
gotoGoodsDetail(goodsId) { if (!goodsId) return
if (!goodsId) return;
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${this.form.skuId}&goodsId=${goodsId}`, url: `/pages/product/goods?id=${form.skuId}&goodsId=${goodsId}`,
}); })
}, }
/** 获取申请原因下拉框数据 */
async getReasonActions(serviceType) { async function fetchReasonActions(serviceType: string) {
uni.showLoading({ uni.showLoading({ title: '加载中' })
title: "加载中",
});
await getAfterSaleReason(serviceType).then((res) => { await getAfterSaleReason(serviceType).then((res) => {
if (res.data.success) { if (res.data.success) {
let action = []; reasonList.value = res.data.result.map((item: any) => ({
res.data.result.forEach((item) => {
action.push({
value: item.id, value: item.id,
label: item.reason, label: item.reason,
}); }))
}); }
})
this.reasonList = action; hideLoadingIfNeeded()
} }
});
if (this.$store.state.isShowToast){ uni.hideLoading() };
},
//打开地区选择器
showCitySelect() {
this.$refs.cityPicker.show();
},
// 初始化数据 function init(orderItemSn: string) {
init(sn) { getAfterSaleInfo(orderItemSn).then((response) => {
getAfterSaleInfo(sn).then((response) => {
if (response.data.code == 400) { if (response.data.code == 400) {
uni.showToast({ uni.showToast({
title: response.data.message, title: response.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
} else { } else {
this.applyInfo = response.data.result; applyInfo.value = response.data.result
form.accountType = response.data.result.accountType
this.form.accountType = response.data.result.accountType;
} }
}); })
},
openReasonPicker() {
if (!this.reasonList.length) {
uni.showToast({
title: "暂无可选原因",
icon: "none",
});
return;
} }
this.reasonSelectShow = true;
},
//退款原因 function openReasonPicker() {
reasonSelectConfirm(val) { if (!reasonList.value.length) {
const selected = val?.value?.[0] || val?.[0]; uni.showToast({ title: '暂无可选原因', icon: 'none' })
return
}
reasonSelectShow.value = true
}
function reasonSelectConfirm(val: any) {
const selected = val?.value?.[0] || val?.[0]
if (selected) { if (selected) {
this.form.reason = selected.label || selected.text || ""; form.reason = selected.label || selected.text || ''
}
} }
},
//修改申请数量 function valChange(e: { value: number }) {
valChange(e) { form.num = e.value
this.form.num = e.value; }
},
onUploadAfterRead(event) { function onUploadAfterRead(event: any) {
handleUploadAfterRead(event, this.fileList, (urls) => { handleUploadAfterRead(event, fileList.value, (urls) => {
this.form.images = urls; form.images = urls
}); })
}, }
showToast(message, type = "error") {
const text = message || (type === "success" ? "操作成功" : "操作失败"); function showToast(message: string, type = 'error') {
if (this.$refs.uToast) { const text = message || (type === 'success' ? '操作成功' : '操作失败')
this.$refs.uToast.show({ message: text, type }); if (uToast.value) {
return; uToast.value.show({ message: text, type })
return
} }
uni.showToast({ uni.showToast({
title: text, title: text,
icon: type === "success" ? "success" : "none", icon: type === 'success' ? 'success' : 'none',
}); })
},
//提交申请
onSubmit() {
//提交申请前检测参数
if (!this.handleCheckParams()) {
return;
} }
uni.showLoading({ function onSubmit() {
title: "加载中", if (!validateFormParams()) return
});
this.form.accountType = this.applyInfo.accountType;
this.form.refundWay = this.applyInfo.refundWay;
this.form.applyRefundPrice = this.applyInfo.applyRefundPrice;
applyReturn(this.sn, this.form).then((resp) => { uni.showLoading({ title: '加载中' })
if (this.$store.state.isShowToast){ uni.hideLoading() }; form.accountType = applyInfo.value.accountType
form.refundWay = applyInfo.value.refundWay
form.applyRefundPrice = applyInfo.value.applyRefundPrice
applyReturn(sn.value, form).then((resp) => {
hideLoadingIfNeeded()
if (resp.data.success) { if (resp.data.success) {
this.showToast("提交成功", "success"); showToast('提交成功', 'success')
uni.redirectTo({ uni.redirectTo({ url: '/pages/order/afterSales/applySuccess' })
url: "/pages/order/afterSales/applySuccess",
});
} else { } else {
this.showToast(resp.data.message || "提交失败", "error"); showToast(resp.data.message || '提交失败', 'error')
} }
}); })
},
//检测提交参数
handleCheckParams() {
if (this.$u.test.isEmpty(this.form.reason)) {
this.showToast("请选择退款原因");
return false;
} }
if (this.$u.test.isEmpty(this.form.problemDesc)) {
this.showToast("请输入退款说明"); function validateFormParams() {
return false; if ($u.test.isEmpty(form.reason)) {
showToast('请选择退款原因')
return false
}
if ($u.test.isEmpty(form.problemDesc)) {
showToast('请输入退款说明')
return false
} }
if ( if (
this.applyInfo.accountType === "BANK_TRANSFER" && applyInfo.value.accountType === 'BANK_TRANSFER' &&
this.applyInfo.applyRefundPrice != 0 applyInfo.value.applyRefundPrice != 0
) { ) {
if (this.$u.test.isEmpty(this.form.bankDepositName)) { if ($u.test.isEmpty(form.bankDepositName)) {
this.showToast("请输入银行开户行"); showToast('请输入银行开户行')
return false; return false
} }
if (this.$u.test.isEmpty(this.form.bankAccountName)) { if ($u.test.isEmpty(form.bankAccountName)) {
this.showToast("请输入银行开户名"); showToast('请输入银行开户名')
return false; return false
} }
if (this.$u.test.isEmpty(this.form.bankAccountNumber)) { if ($u.test.isEmpty(form.bankAccountNumber)) {
this.showToast("请输入银行账号"); showToast('请输入银行账号')
return false; return false
} }
if (this.$u.test.chinese(this.form.bankAccountName) === false) { if ($u.test.chinese(form.bankAccountName) === false) {
this.showToast("银行开户名需为中文"); showToast('银行开户名需为中文')
return false; return false
} }
if (this.$u.test.chinese(this.form.bankDepositName) === false) { if ($u.test.chinese(form.bankDepositName) === false) {
this.showToast("银行开户行需为中文"); showToast('银行开户行需为中文')
return false; return false
} }
} }
return true; return true
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,6 +1,11 @@
<template> <template>
<view class="mp-iphonex-bottom content"> <view class="mp-iphonex-bottom content">
<u-form :model="form" ref="uForm"> <up-form
:model="form"
ref="uForm"
label-position="left"
label-width="180rpx"
>
<view class="after-sales-goods-detail-view"> <view class="after-sales-goods-detail-view">
<view class="header"> <view class="header">
<view> <view>
@@ -29,32 +34,32 @@
<!-- 上传凭证 --> <!-- 上传凭证 -->
<view class="opt-view"> <view class="opt-view">
<view class="img-title" style="font-size: 30rpx">填写物流信息</view> <view class="img-title" style="font-size: 30rpx">填写物流信息</view>
<u-form-item label="返回方式" :label-width="150"> <up-form-item label="返回方式" label-width="180rpx">
<div style="width: 100%; text-align: right;">快递至第三方卖家</div> <div style="width: 100%; text-align: right;">快递至第三方卖家</div>
</u-form-item> </up-form-item>
<u-form-item label="快递公司" :label-width="150"> <up-form-item label="快递公司" label-width="180rpx">
<div style="width: 100%; text-align: right;" @click="companySelectShow = true"> <div style="width: 100%; text-align: right;" @click="companySelectShow = true">
{{ form.courierCompany || '请选择快递公司' }} {{ form.courierCompany || '请选择快递公司' }}
</div> </div>
</u-form-item> </up-form-item>
<u-form-item label="快递单号" :label-width="150"> <up-form-item label="快递单号" label-width="180rpx">
<u-input input-align="right" v-model="form.logisticsNo" placeholder="请输入快递单号"/> <u-input input-align="right" v-model="form.logisticsNo" placeholder="请输入快递单号"/>
</u-form-item> </up-form-item>
<u-form-item label="发货时间" :label-width="150"> <up-form-item label="发货时间" label-width="180rpx">
<div style="width: 100%; text-align: right;" @click="timeshow = true">{{ <div style="width: 100%; text-align: right;" @click="timeshow = true">{{
form.mDeliverTime || '请选择发货时间' form.mDeliverTime || '请选择发货时间'
}} }}
</div> </div>
</u-form-item> </up-form-item>
</view> </view>
</scroll-view> </scroll-view>
<view class="submit-view"> <view class="submit-view">
<u-button ripple :customStyle="{'background':$lightColor,'color':'#fff' }" shape="circle" @click="onSubmit"> <u-button ripple :customStyle="{ background: lightColor, color: '#fff' }" shape="circle" @click="onSubmit">
提交申请 提交申请
</u-button> </u-button>
</view> </view>
</u-form> </up-form>
<u-select mode="single-column" :list="companyList" v-model:show="companySelectShow" <u-select mode="single-column" :list="companyList" v-model:show="companySelectShow"
@confirm="companySelectConfirm"></u-select> @confirm="companySelectConfirm"></u-select>
<u-calendar v-model:show="timeshow" :mode="'date'" @change="onTimeChange"></u-calendar> <u-calendar v-model:show="timeshow" :mode="'date'" @change="onTimeChange"></u-calendar>
@@ -62,124 +67,98 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import {getLogistics} from "@/api/address.js"; import { ref, reactive, computed } from 'vue'
import {fillShipInfo} from "@/api/after-sale.js"; import { onLoad } from '@dcloudio/uni-app'
import storage from "@/utils/storage"; import { useStore } from '@/store'
import { unitPrice } from '@/utils/filters.js'
import { getLogistics } from '@/api/address.js'
import { fillShipInfo } from '@/api/after-sale.js'
import storage from '@/utils/storage'
export default { const store = useStore()
data() { const lightColor = computed(() => store.getters.lightColor)
return {
//快递公司 弹出框
companySelectShow: false,
companyList: [], //快递公司集合
timeshow: false, //发货时间
form: {
courierCompany: "", //快递公司
logisticsId: "", //快递公司ID
logisticsNo: "", //快递单号
mDeliverTime: "", //发货时间
},
serviceDetail: {}, //服务详情
sku: {}, //sku信息
};
},
onLoad(options) {
this.sku = storage.getAfterSaleData(); const companySelectShow = ref(false)
let navTitle = "服务单详情"; const companyList = ref<any[]>([])
uni.setNavigationBarTitle({ const timeshow = ref(false)
title: navTitle, //此处写页面的title const form = reactive({
}); courierCompany: '',
this.serviceDetail.sn = options.serviceSn; logisticsId: '',
this.Logistics(); logisticsNo: '',
}, mDeliverTime: '',
methods: { })
/** const serviceDetail = reactive<{ sn: string }>({ sn: '' })
* 确认快递公司 const sku = ref<any>({})
*/ const uToast = ref<any>(null)
companySelectConfirm(e) {
this.form.logisticsId = e[0].value;
this.form.courierCompany = e[0].label;
},
/** onLoad((options) => {
* 获取快递公司 sku.value = storage.getAfterSaleData()
*/ uni.setNavigationBarTitle({ title: '服务单详情' })
Logistics() { serviceDetail.sn = options?.serviceSn || ''
fetchLogisticsList()
})
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
}
function companySelectConfirm(e: any[]) {
form.logisticsId = e[0].value
form.courierCompany = e[0].label
}
function fetchLogisticsList() {
getLogistics().then((res) => { getLogistics().then((res) => {
if (res.data.success) { if (res.data.success) {
res.data.result.forEach((item, index) => { companyList.value = res.data.result.map((item: any) => ({
this.companyList[index] = {
value: item.id, value: item.id,
label: item.name, label: item.name,
}; }))
});
} }
}); })
},
/**
* 更改时间
*/
onTimeChange(e) {
this.form.mDeliverTime = e.result;
},
/**
* 点击提交
*/
onSubmit() {
delete this.form.courierCompany;
if (this.form.logisticsId == "") {
this.$refs.uToast.show({
title: "请选择快递公司",
type: "error",
});
return;
}
if (this.form.logisticsNo == "") {
this.$refs.uToast.show({
title: "请填写快递单号",
type: "error",
});
return;
}
if (this.form.mDeliverTime == "") {
this.$refs.uToast.show({
title: "请选择发货时间",
type: "error",
});
return;
} }
uni.showLoading({ function onTimeChange(e: { result: string }) {
title: "加载中", form.mDeliverTime = e.result
mask: true,
});
fillShipInfo(this.serviceDetail.sn, this.form).then((res) => {
if (this.$store.state.isShowToast) {
uni.hideLoading()
} }
;
function onSubmit() {
const submitForm = { ...form }
delete submitForm.courierCompany
if (form.logisticsId == '') {
uToast.value?.show({ title: '请选择快递公司', type: 'error' })
return
}
if (form.logisticsNo == '') {
uToast.value?.show({ title: '请填写快递单号', type: 'error' })
return
}
if (form.mDeliverTime == '') {
uToast.value?.show({ title: '请选择发货时间', type: 'error' })
return
}
uni.showLoading({ title: '加载中', mask: true })
fillShipInfo(serviceDetail.sn, submitForm).then((res) => {
hideLoadingIfNeeded()
if (res.statusCode === 200) { if (res.statusCode === 200) {
this.$refs.uToast.show({ uToast.value?.show({
title: "提交成功", title: '提交成功',
type: "success", type: 'success',
back: true, back: true,
url: "/pages/order/afterSales/afterSales", url: '/pages/order/afterSales/afterSales',
}); })
} }
}); })
}, }
gotoGoodsDetail(sku) {
function gotoGoodsDetail(item: any) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${sku.skuId}&goodsId=${sku.goodsId}`, url: `/pages/product/goods?id=${item.skuId}&goodsId=${item.goodsId}`,
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -57,59 +57,51 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getAfterSaleInfo } from "@/api/after-sale"; import { ref } from 'vue'
import storage from "@/utils/storage"; import { onLoad } from '@dcloudio/uni-app'
export default { import { unitPrice, parseGoodsImageUrl } from '@/utils/filters.js'
data() { import { getAfterSaleInfo } from '@/api/after-sale'
return { import storage from '@/utils/storage'
sn: "",
sku: {}, //sku const sn = ref('')
applyInfo:"" const sku = ref<any>({})
}; const applyInfo = ref<any>({})
},
onLoad(options) { onLoad((options) => {
this.sn = options.sn; sn.value = options?.sn || ''
this.sku = storage.getAfterSaleData(); sku.value = storage.getAfterSaleData()
// 查看当前商品是否支持退款退货 init()
this.init() })
},
methods: { function getGoodsName(item: any) {
getGoodsName(item) { return item.goodsName || item.name || ''
return item.goodsName || item.name || "";
},
getGoodsImage(item) {
const image = item.image || item.goodsImage || item.thumbnail;
return this.parseGoodsImageUrl(image);
},
// 初始化数据
init() {
getAfterSaleInfo(this.sn).then((response) => {
if (response.data.success) {
this.applyInfo = response.data.result;
} }
});
},
/** function getGoodsImage(item: any) {
* 选择退货流程 const image = item.image || item.goodsImage || item.thumbnail
*/ return parseGoodsImageUrl(image)
onSelect(value) { }
function init() {
getAfterSaleInfo(sn.value).then((response) => {
if (response.data.success) {
applyInfo.value = response.data.result
}
})
}
function onSelect(value: number) {
uni.redirectTo({ uni.redirectTo({
url: `./afterSalesDetail?sn=${this.sn}&value=${value}`, url: `./afterSalesDetail?sn=${sn.value}&value=${value}`,
}); })
}, }
/** function navigateToGoodsDetail(skuId: string) {
* 跳转到商品信息
*/
navigateToGoodsDetail(id) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${id}&goodsId=${goodsId}`, url: `/pages/product/goods?id=${skuId}&goodsId=${sku.value.goodsId}`,
}); })
}, }
},
};
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@@ -25,7 +25,7 @@
</view> </view>
<view class="goods-info"> <view class="goods-info">
<view class="info-box"> <view class="info-box">
<view class="goods-item-view" @click="navgiateToGoodsDetail(serviceDetail)"> <view class="goods-item-view" @click="navigateToGoodsDetail(serviceDetail)">
<view class="goods-img"> <view class="goods-img">
<u-image <u-image
border-radius="6" border-radius="6"
@@ -184,198 +184,184 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import {
unitPrice,
parseGoodsImageUrl,
serviceStatusList,
secrecyMobile,
unixToDate,
} from '@/utils/filters.js'
import { import {
getServiceDetail, getServiceDetail,
getStoreAfterSaleAddress, getStoreAfterSaleAddress,
getAfterSaleLog, getAfterSaleLog,
getAfterSaleReason, getAfterSaleReason,
} from "@/api/after-sale.js"; } from '@/api/after-sale.js'
export default {
data() { const store = useStore()
return {
reason: "", //申请原因 const reason = ref('')
serviceTypeList: { const serviceTypeList: Record<string, string> = {
// 售后类型 CANCEL: '取消',
CANCEL: "取消", RETURN_GOODS: '退货',
RETURN_GOODS: "退货", EXCHANGE_GOODS: '换货',
EXCHANGE_GOODS: "换货", RETURN_MONEY: '退款',
RETURN_MONEY: "退款",
},
serviceDetail: {}, // 售后详情
logs: [], //日志
goodsList: [], //商品列表
storeAfterSaleAddress: {}, //售后地址
refundShow: false, //退款开关
accountShow: false, //账户显示
bankShow: false, //银行显示
sn: "", //订单sn
};
},
onLoad(options) {
uni.setNavigationBarTitle({
title: "服务单详情",
});
this.sn = options.sn;
this.loadDetail();
this.getAddress();
this.getLog(options.sn);
},
methods: {
statusFilter(val) {
switch (val) {
case "APPLY":
return "售后服务申请成功,等待商家审核";
case "PASS":
return "售后服务申请审核通过";
case "REFUSE":
return "售后服务申请已被商家拒绝,如有疑问请及时联系商家";
case "FULL_COURIER":
return "申请售后的商品已经寄出,等待商家收货";
case "STOCK_IN":
return "商家已将售后商品入库";
case "WAIT_FOR_MANUAL":
return "等待平台进行人工退款";
case "REFUNDING":
return "商家退款中,请您耐心等待";
case "COMPLETED":
return "售后服务已完成,感谢您的支持";
case "ERROR_EXCEPTION":
return "系统生成新订单异常,等待商家手动创建新订单";
case "CLOSED":
return "售后服务已关闭";
case "WAIT_REFUND":
return "等待平台进行退款";
default:
return "";
} }
}, const serviceDetail = ref<any>(null)
refundWayFilter(val) { const logs = ref<any[]>([])
switch (val) { const storeAfterSaleAddress = ref<any>({})
case "OFFLINE": const refundShow = ref(false)
return "账户退款"; const accountShow = ref(false)
case "ORIGINAL": const bankShow = ref(false)
return "原路退回"; const sn = ref('')
default:
return ""; onLoad((options) => {
uni.setNavigationBarTitle({ title: '服务单详情' })
sn.value = options?.sn || ''
loadDetail()
fetchAddress()
fetchLog(sn.value)
})
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
} }
},
accountTypeFilter(val) { function statusFilter(val: string) {
switch (val) { switch (val) {
case "WEIXINPAY": case 'APPLY':
return "微信"; return '售后服务申请成功,等待商家审核'
case "ALIPAY": case 'PASS':
return "支付宝"; return '售后服务申请审核通过'
case "BANK_TRANSFER": case 'REFUSE':
return "银行卡"; return '售后服务申请已被商家拒绝,如有疑问请及时联系商家'
case 'FULL_COURIER':
return '申请售后的商品已经寄出,等待商家收货'
case 'STOCK_IN':
return '商家已将售后商品入库'
case 'WAIT_FOR_MANUAL':
return '等待平台进行人工退款'
case 'REFUNDING':
return '商家退款中,请您耐心等待'
case 'COMPLETED':
return '售后服务已完成,感谢您的支持'
case 'ERROR_EXCEPTION':
return '系统生成新订单异常,等待商家手动创建新订单'
case 'CLOSED':
return '售后服务已关闭'
case 'WAIT_REFUND':
return '等待平台进行退款'
default: default:
return ""; return ''
} }
}, }
/**
* 点击图片放大或保存 function refundWayFilter(val: string) {
*/ switch (val) {
preview(urls, index) { case 'OFFLINE':
return '账户退款'
case 'ORIGINAL':
return '原路退回'
default:
return ''
}
}
function accountTypeFilter(val: string) {
switch (val) {
case 'WEIXINPAY':
return '微信'
case 'ALIPAY':
return '支付宝'
case 'BANK_TRANSFER':
return '银行卡'
default:
return ''
}
}
function preview(urls: string[], index: number) {
uni.previewImage({ uni.previewImage({
current: index, current: index,
urls: urls, urls,
longPressActions: { longPressActions: {
itemList: ["保存图片"], itemList: ['保存图片'],
success: function (data) {}, success: () => {},
fail: function (err) {}, fail: () => {},
}, },
}); })
},
/**
* 获取地址信息
*/
getAddress() {
getStoreAfterSaleAddress(this.sn).then((res) => {
if (res.data.success) {
this.storeAfterSaleAddress = res.data.result;
} }
});
},
/** function fetchAddress() {
* 获取日志 getStoreAfterSaleAddress(sn.value).then((res) => {
*/ if (res.data.success) {
getLog(sn) { storeAfterSaleAddress.value = res.data.result
getAfterSaleLog(sn).then((res) => { }
this.logs = res.data.result; })
}); }
},
/** function fetchLog(serviceSn: string) {
* 获取申请原因 getAfterSaleLog(serviceSn).then((res) => {
*/ logs.value = res.data.result
getReasonList(serviceType) { })
}
function fetchReasonList(serviceType: string) {
getAfterSaleReason(serviceType).then((res) => { getAfterSaleReason(serviceType).then((res) => {
if (res.data.success) { if (res.data.success) {
// 1357583466371219456 reason.value = serviceDetail.value.reason
this.reason = this.serviceDetail.reason; }
})
} }
});
},
/** function loadDetail() {
* 初始化详情 uni.showLoading({ title: '加载中' })
*/ getServiceDetail(sn.value).then((res) => {
loadDetail() { hideLoadingIfNeeded()
uni.showLoading({ serviceDetail.value = res.data.result
title: "加载中",
});
getServiceDetail(this.sn).then((res) => {
if (this.$store.state.isShowToast){ uni.hideLoading() };
this.serviceDetail = res.data.result;
if ( if (
this.serviceDetail.serviceType == "RETURN_GOODS" || serviceDetail.value.serviceType == 'RETURN_GOODS' ||
this.serviceDetail.serviceType === "RETURN_MONEY" serviceDetail.value.serviceType === 'RETURN_MONEY'
) { ) {
this.refundShow = true; refundShow.value = true
} }
this.accountShow = accountShow.value =
(this.serviceDetail.serviceType === "RETURN_GOODS" || (serviceDetail.value.serviceType === 'RETURN_GOODS' ||
this.serviceDetail.serviceType === "ORDER_CANCEL") && serviceDetail.value.serviceType === 'ORDER_CANCEL') &&
this.serviceDetail.refundWay === "OFFLINE"; serviceDetail.value.refundWay === 'OFFLINE'
this.bankShow = bankShow.value =
this.serviceDetail.accountType === "BANK_TRANSFER" && serviceDetail.value.accountType === 'BANK_TRANSFER' &&
this.serviceDetail.refundWay === "OFFLINE" && serviceDetail.value.refundWay === 'OFFLINE' &&
((this.serviceDetail.serviceType === "RETURN_GOODS") | ((serviceDetail.value.serviceType === 'RETURN_GOODS') |
(this.serviceDetail.serviceType === "ORDER_CANCEL") || (serviceDetail.value.serviceType === 'ORDER_CANCEL') ||
this.serviceDetail.serviceType === "RETURN_MONEY"); serviceDetail.value.serviceType === 'RETURN_MONEY')
this.getReasonList(this.serviceDetail.serviceType); fetchReasonList(serviceDetail.value.serviceType)
}); })
}, }
/** function navigateToGoodsDetail(item: any) {
* 访问商品详情
*/
navgiateToGoodsDetail(item) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`, url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
}); })
}, }
/** function onProgress() {
* 进度
*/
onProgress() {
uni.navigateTo({ uni.navigateTo({
url: `./applyProgress?sn=${ url: `./applyProgress?sn=${
this.serviceDetail.sn serviceDetail.value.sn
}&createTime=${encodeURIComponent(this.serviceDetail.createTime)} }&createTime=${encodeURIComponent(serviceDetail.value.createTime)}
&logs=${encodeURIComponent(JSON.stringify(this.logs))}&serviceStatus=${ &logs=${encodeURIComponent(JSON.stringify(logs.value))}&serviceStatus=${
this.serviceDetail.serviceStatus serviceDetail.value.serviceStatus
}`, }`,
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -35,54 +35,50 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { import { ref } from 'vue'
data() { import { onLoad } from '@dcloudio/uni-app'
return {
sn: "", //sn
createTime: "", //创建时间
logList: [], //日志集合
serviceStatus: "", //订单状态
};
},
onLoad(options) {
this.sn = options.sn;
this.createTime = decodeURIComponent(options.createTime);
this.serviceStatus = this.statusFilter(options.serviceStatus);
this.logList = JSON.parse(decodeURIComponent(options.logs));
}, const sn = ref('')
methods: { const createTime = ref('')
statusFilter(val) { const logList = ref<any[]>([])
const serviceStatus = ref('')
function statusFilter(val: string) {
switch (val) { switch (val) {
case "APPLY": case 'APPLY':
return "售后服务申请成功,等待商家审核"; return '售后服务申请成功,等待商家审核'
case "PASS": case 'PASS':
return "售后服务申请审核通过"; return '售后服务申请审核通过'
case "REFUSE": case 'REFUSE':
return "售后服务申请已被商家拒绝,如有疑问请及时联系商家"; return '售后服务申请已被商家拒绝,如有疑问请及时联系商家'
case "FULL_COURIER": case 'FULL_COURIER':
return "申请售后的商品已经寄出,等待商家收货"; return '申请售后的商品已经寄出,等待商家收货'
case "STOCK_IN": case 'STOCK_IN':
return "商家已将售后商品入库"; return '商家已将售后商品入库'
case "WAIT_FOR_MANUAL": case 'WAIT_FOR_MANUAL':
return "等待平台进行人工退款"; return '等待平台进行人工退款'
case "REFUNDING": case 'REFUNDING':
return "商家退款中,请您耐心等待"; return '商家退款中,请您耐心等待'
case "COMPLETED": case 'COMPLETED':
return "售后服务已完成,感谢您的支持"; return '售后服务已完成,感谢您的支持'
case "ERROR_EXCEPTION": case 'ERROR_EXCEPTION':
return "系统生成新订单异常,等待商家手动创建新订单"; return '系统生成新订单异常,等待商家手动创建新订单'
case "CLOSED": case 'CLOSED':
return "售后服务已关闭"; return '售后服务已关闭'
case "WAIT_REFUND": case 'WAIT_REFUND':
return "等待平台进行退款"; return '等待平台进行退款'
default: default:
return ""; return ''
} }
}, }
},
}; onLoad((options) => {
sn.value = options.sn || ''
createTime.value = decodeURIComponent(options.createTime || '')
serviceStatus.value = statusFilter(options.serviceStatus || '')
logList.value = JSON.parse(decodeURIComponent(options.logs || '[]'))
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -21,31 +21,18 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
export default { function navigateToAfterSales() {
data() {
return {};
},
methods: {
/**
* 跳转到售后服务
*/
navigateToAfterSales() {
uni.redirectTo({ uni.redirectTo({
url: "/pages/order/afterSales/afterSales", url: '/pages/order/afterSales/afterSales',
}); })
}, }
/** function navigateToHome() {
* 跳转到首页
*/
navigateToHome() {
uni.switchTab({ uni.switchTab({
url: "/pages/tabbar/home/index", url: '/pages/tabbar/home/index',
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -57,137 +57,112 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import storage from "@/utils/storage.js"; import { ref } from 'vue'
import { getOrderDetail } from "@/api/order.js"; import { onLoad } from '@dcloudio/uni-app'
import { getComplainReason, addComplain } from "@/api/after-sale.js"; import { useStore } from '@/store'
import { handleUploadAfterRead } from "@/utils/uploadHelper.js"; import { getOrderDetail } from '@/api/order.js'
export default { import { getComplainReason, addComplain } from '@/api/after-sale.js'
data() { import { handleUploadAfterRead } from '@/utils/uploadHelper.js'
return { import { unitPrice } from '@/utils/filters.js'
storage,
uploadFileList: [],
orderStatusMap: {
//订单状态列表
UNDELIVERED: "待发货",
PARTS_DELIVERED: "部分发货",
UNPAID: "未付款",
PAID: "已付款",
DELIVERED: "已发货",
CANCELLED: "已取消",
COMPLETE: "已完成",
TAKE: "已完成",
},
complainValue: "", //投诉内容
complainShow: false, //投诉主题开关
complainTopic: "", //投诉抱怨话题
complainList: [], // 投诉列表
images: [], //投诉内容图片
order: "", //订单
orderGoodsList: "", //订单商品
orderDetail: "", //订单详情
sn: "",
skuId: "", //商品skuid
};
},
onLoad(option) { const store = useStore()
this.loadData(option.sn);
this.sn = option.sn;
this.skuId = option.skuId;
this.getReasion();
},
methods: { const orderStatusMap: Record<string, string> = {
onUploadAfterRead(event) { UNDELIVERED: '待发货',
handleUploadAfterRead(event, this.uploadFileList, (urls) => { PARTS_DELIVERED: '部分发货',
this.images = urls; UNPAID: '未付款',
}); PAID: '已付款',
}, DELIVERED: '已发货',
/** CANCELLED: '已取消',
* 提交 COMPLETE: '已完成',
*/ TAKE: '已完成',
handleSubmit() { }
if(!this.images.length && !this.complainValue){
const uploadFileList = ref<any[]>([])
const complainValue = ref('')
const complainShow = ref(false)
const complainTopic = ref('')
const complainList = ref<any[]>([])
const images = ref<string[]>([])
const order = ref<Record<string, any>>({})
const orderGoodsList = ref<any[]>([])
const sn = ref('')
const skuId = ref('')
onLoad((option) => {
loadData(option.sn)
sn.value = option.sn
skuId.value = option.skuId
getReasion()
})
function onUploadAfterRead(event: any) {
handleUploadAfterRead(event, uploadFileList.value, (urls) => {
images.value = urls
})
}
function handleSubmit() {
if (!images.value.length && !complainValue.value) {
uni.showToast({ uni.showToast({
title: '请上传图片凭证和投诉内容', title: '请上传图片凭证和投诉内容',
icon:'none' icon: 'none',
}) })
return return
} }
// 循环出商品 const goods = orderGoodsList.value.filter((item) => item.skuId == skuId.value)
let goods = this.orderGoodsList.filter((item) => { const data = {
return item.skuId == this.skuId; complainTopic: complainTopic.value,
}); content: complainValue.value,
//数据赋值 goodsId: goods[0].goodsId,
let data = { images: images.value,
complainTopic: this.complainTopic, //投诉主题, orderSn: sn.value,
content: this.complainValue, //投诉内容 skuId: skuId.value,
goodsId: goods[0].goodsId, //商品id }
images: this.images, //图片
orderSn: this.sn, //订单号
skuId: this.skuId, //skuid
};
addComplain(data).then((res) => { addComplain(data).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({
title: "提交成功!", title: '提交成功!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
setTimeout(() => { setTimeout(() => {
uni.redirectTo({ uni.redirectTo({
url: "/pages/order/complain/complainList", url: '/pages/order/complain/complainList',
}); })
}, 1000); }, 1000)
}
})
} }
});
},
/** function getReasion() {
* 获取投诉原因
*/
getReasion() {
getComplainReason().then((res) => { getComplainReason().then((res) => {
if (res.data.result.length >= 1) { if (res.data.result.length >= 1) {
res.data.result.forEach((item) => { res.data.result.forEach((item: any) => {
let way = { complainList.value.push({
value: item.reason, value: item.reason,
label: item.reason, label: item.reason,
}; })
this.complainList.push(way); })
}); complainTopic.value = res.data.result[0].reason
this.complainTopic = res.data.result[0].reason; }
})
} }
});
},
/** function loadData(orderSn: string) {
* 加载订单详情 uni.showLoading({ title: '加载中' })
*/ getOrderDetail(orderSn).then((res) => {
loadData(sn) { const result = res.data.result
uni.showLoading({ order.value = result.order
title: "加载中", orderGoodsList.value = result.orderItems
}); if (store.state.isShowToast) uni.hideLoading()
getOrderDetail(sn).then((res) => { })
const order = res.data.result; }
this.order = order.order;
this.orderGoodsList = order.orderItems;
this.orderDetail = res.data.result;
if (this.$store.state.isShowToast){ uni.hideLoading() };
});
},
/** function confirmComplain(e: any[]) {
* 确认投诉 complainTopic.value = e[0].label
*/ }
confirmComplain(e) {
this.complainTopic = e[0].label;
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -51,99 +51,91 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getComplainDetail, communication } from "@/api/after-sale"; import { ref } from 'vue'
export default { import { onLoad } from '@dcloudio/uni-app'
data() { import { useStore } from '@/store'
return { import { getComplainDetail, communication } from '@/api/after-sale'
complainId: "",
complainValue: "", //回复内容
complainDetail: "", //投诉详情
statusData: {
NEW: "新投诉",
NO_APPLY: "未申请",
APPLYING: "申请中",
COMPLETE: "已完成",
EXPIRED: "已失效",
CANCEL: "已取消",
WAIT_ARBITRATION:"等待仲裁"
},
};
},
onLoad(option) { const store = useStore()
this.complainId = option.id;
this.init(option.id); const complainId = ref('')
}, const complainValue = ref('')
methods: { const complainDetail = ref<Record<string, any>>({})
/** const statusData: Record<string, string> = {
* 点击图片放大或保存 NEW: '新投诉',
*/ NO_APPLY: '未申请',
preview(urls, index) { APPLYING: '申请中',
COMPLETE: '已完成',
EXPIRED: '已失效',
CANCEL: '已取消',
WAIT_ARBITRATION: '等待仲裁',
}
onLoad((option) => {
complainId.value = option.id
init(option.id)
})
function preview(urls: string[], index: number) {
uni.previewImage({ uni.previewImage({
current: index, current: index,
urls: urls, urls,
longPressActions: { longPressActions: {
itemList: ["保存图片"], itemList: ['保存图片'],
success: function (data) {}, success: () => {},
fail: function (err) {}, fail: () => {},
}, },
}); })
}, }
handleSubmit() {
if (!this.complainValue) { function handleSubmit() {
uni.showToast({ if (!complainValue.value) {
title: "请输入回复内容", uni.showToast({
duration: 2000, title: '请输入回复内容',
icon: "none", duration: 2000,
}); icon: 'none',
return; })
return
}
const params = {
content: complainValue.value,
complainId: complainId.value,
} }
let params = {
content: this.complainValue,
complainId: this.complainId,
};
communication(params).then((res) => { communication(params).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({
title: "回复成功", title: '回复成功',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
this.complainValue = ''; complainValue.value = ''
this.init(this.complainId); init(complainId.value)
} else { } else {
uni.showToast({ uni.showToast({
title: res.data.message, title: res.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}
})
} }
});
}, function init(id: string) {
/** uni.showLoading({ title: '加载中' })
* 初始化投诉详情
*/
init(id) {
uni.showLoading({
title: "加载中",
});
getComplainDetail(id).then((res) => { getComplainDetail(id).then((res) => {
if (res.data.success) { if (res.data.success) {
this.complainDetail = res.data.result; complainDetail.value = res.data.result
} else { } else {
uni.showToast({ uni.showToast({
title: res.data.message, title: res.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}
if (store.state.isShowToast) uni.hideLoading()
})
} }
if (this.$store.state.isShowToast){ uni.hideLoading() };
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.row { .row {

View File

@@ -10,7 +10,7 @@
<u-line color="#DCDFE6"></u-line> <u-line color="#DCDFE6"></u-line>
<view class="goods-item-view"> <view class="goods-item-view">
<view class="goods-img" @click="handleToGoods(item)"> <view class="goods-img" @click="handleToGoods(item)">
<u-image border-radius="6" width="131rpx" height="131rpx" :src="item.goodsImage"></u-image> <u-image radius="6rpx" width="131rpx" height="131rpx" :src="item.goodsImage"></u-image>
</view> </view>
<view class="goods-info" @click="handleToGoods(item)"> <view class="goods-info" @click="handleToGoods(item)">
<view class="goods-title u-line-2">{{ item.goodsName }}</view> <view class="goods-title u-line-2">{{ item.goodsName }}</view>
@@ -28,9 +28,9 @@
<view class="complain-speak"> {{ item.complainTopic }} </view> <view class="complain-speak"> {{ item.complainTopic }} </view>
</view> </view>
<view class="complain-btn"> <view class="complain-btn">
<u-tag mode="plain" @click="handleClear(item)" class="complain-tag" text="撤销投诉" type="info" <u-tag plain @click="handleClear(item)" class="complain-tag" text="撤销投诉" type="info"
v-if="item.complainStatus === 'APPLYING' || item.complainStatus === 'NEW'" /> v-if="item.complainStatus === 'APPLYING' || item.complainStatus === 'NEW'" />
<u-tag mode="plain" @click="handleInfo(item)" class="complain-tag" text="投诉详情" type="info" /> <u-tag plain @click="handleInfo(item)" class="complain-tag" text="投诉详情" type="info" />
</view> </view>
</view> </view>
@@ -40,114 +40,175 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getComplain, clearComplain } from "@/api/after-sale"; import { ref } from 'vue'
import { onLoad, onReachBottom } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { unitPrice } from '@/utils/filters.js'
import { getComplain, clearComplain } from '@/api/after-sale'
export default { const store = useStore()
data() {
return { const statusData: Record<string, string> = {
statusData: { NEW: '新投诉',
NEW: "新投诉", NO_APPLY: '未申请',
NO_APPLY: "未申请", APPLYING: '申请中',
APPLYING: "申请中", COMPLETE: '已完成',
COMPLETE: "已完成", EXPIRED: '已失效',
EXPIRED: "已失效", CANCEL: '已取消',
CANCEL: "已取消", WAIT_ARBITRATION: '等待仲裁',
WAIT_ARBITRATION:"等待仲裁"
},
show: false,
content: "是否撤销投诉?",
params: {
pageNumber: 1,
pageSize: 20,
},
complaionDetail: "", //返回的整个response
complaionData: [], //投诉列表
empty: false,
checkComplainData: "", //存储投诉信息
};
},
mounted() {
this.init();
},
/**
* 触底加载
*/
onReachBottom() {
if (
this.complaionDetail &&
this.complaionDetail.total < this.params.pageNumber * this.params.pageSize
) {
this.params.pageNumber++;
this.init();
} }
},
methods: { const show = ref(false)
// 点击跳转到商品 const content = ref('是否撤销投诉?')
handleToGoods(val) { const params = ref({ pageNumber: 1, pageSize: 20 })
const complaionDetail = ref<any>(null)
const complaionData = ref<any[]>([])
const empty = ref(false)
const checkComplainData = ref<any>(null)
onLoad(() => {
init()
})
onReachBottom(() => {
if (
complaionDetail.value &&
complaionDetail.value.total > params.value.pageNumber * params.value.pageSize
) {
params.value.pageNumber++
init()
}
})
function handleToGoods(val: any) {
uni.navigateTo({ uni.navigateTo({
url: "/pages/product/goods?id=" + val.skuId + "&goodsId=" + val.goodsId, url: '/pages/product/goods?id=' + val.skuId + '&goodsId=' + val.goodsId,
}); })
}, }
/** function handleClear(val: any) {
* 点击撤销投诉 show.value = true
*/ checkComplainData.value = val
handleClear(val) { }
this.show = true;
this.checkComplainData = val; function handleClearConfirm() {
}, clearComplain(checkComplainData.value.id).then((res) => {
/**
* 执行撤销
*/
handleClearConfirm() {
clearComplain(this.checkComplainData.id).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({
title: "撤销成功", title: '撤销成功',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
this.complaionData = []; complaionData.value = []
this.params.pageNumber = 1; params.value.pageNumber = 1
this.init(); init()
}
})
} }
});
},
/** function handleInfo(val: any) {
* 查看详情
*/
handleInfo(val) {
uni.navigateTo({ uni.navigateTo({
url: "./complainInfo?id=" + val.id, url: './complainInfo?id=' + val.id,
}); })
}, }
/** function hideLoadingIfNeeded() {
* 初始化投诉列表 if (store.state.isShowToast) uni.hideLoading()
*/ }
init() {
uni.showLoading({ function init() {
title: "加载中", uni.showLoading({
}); title: '加载中',
getComplain(this.params).then((res) => { })
this.complaionDetail = res.data.result; getComplain(params.value).then((res) => {
if (res.data.result.records.length >= 1) { complaionDetail.value = res.data.result
this.complaionData.push(...res.data.result.records); if (res.data.result.records.length >= 1) {
} else { complaionData.value.push(...res.data.result.records)
this.empty = true; } else {
empty.value = true
}
hideLoadingIfNeeded()
})
} }
if (this.$store.state.isShowToast){ uni.hideLoading() };
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "../goods.scss"; .seller-view {
background-color: #fff;
margin: 20rpx 0;
}
.seller-info {
height: 70rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.seller-name {
width: auto;
min-width: 0;
font-size: 33rpx;
font-weight: 600;
display: flex;
flex-direction: row;
align-items: center;
height: 90rpx;
}
.name {
margin-left: 15rpx;
margin-top: -2rpx;
font-size: 28rpx;
flex: 1;
}
.order-sn {
color: #ff0000;
font-size: 26rpx;
flex-shrink: 0;
margin-left: 20rpx;
}
.goods-item-view {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 10rpx 30rpx;
}
.goods-img {
width: 131rpx;
height: 131rpx;
flex: 0 0 131rpx;
}
.goods-info {
padding-left: 30rpx;
min-width: 0;
flex: 1;
}
.goods-title {
margin-bottom: 10rpx;
color: $font-color-dark;
}
.goods-price {
font-size: 28rpx;
margin-bottom: 10rpx;
color: #ff5a10;
}
.goods-num {
text-align: center;
flex: 0 0 60rpx;
width: 60rpx;
color: $main-color;
}
.complain-item-view { .complain-item-view {
border-bottom: 2rpx solid #f5f7fa; border-bottom: 2rpx solid #f5f7fa;
@@ -162,9 +223,6 @@ export default {
font-size: 24rpx; font-size: 24rpx;
color: #999; color: #999;
} }
::v-deep .seller-name {
width: auto !important;
}
.complain-btn { .complain-btn {
padding: 20rpx 0; padding: 20rpx 0;
display: flex; display: flex;

View File

@@ -45,34 +45,24 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { getPackage } from "@/api/trade.js"; import { ref } from 'vue'
export default { import { onLoad } from '@dcloudio/uni-app'
data() { import { getPackage } from '@/api/trade.js'
return {
order: {}, const logisticsList = ref<any[]>([])
logisticsList: [],
} onLoad((option) => {
}, const sn = option.order_sn
components: { if (sn) fetchLogistics(sn)
}, })
computed: {
}, function fetchLogistics(sn: string) {
onLoad(option) {
let sn = option.order_sn;
this.tracesList(sn);
},
mounted() {
},
methods: {
tracesList(sn) {
getPackage(sn).then((res) => { getPackage(sn).then((res) => {
if (res.data.success) { if (res.data.success) {
this.logisticsList = res.data.result; logisticsList.value = res.data.result
} }
}); })
},
},
} }
</script> </script>
<style > <style >

View File

@@ -31,7 +31,7 @@
<view class="img"> <view class="img">
<!-- 循环出商家回复评价的图片 --> <!-- 循环出商家回复评价的图片 -->
<u-image width="140rpx" height="140rpx" v-if="comment.replyImage" v-for="(replyImg, replyIndex) in splitImg(comment.replyImage)" :src="replyImg" :key="replyIndex" <u-image width="140rpx" height="140rpx" v-if="comment.replyImage" v-for="(replyImg, replyIndex) in splitImg(comment.replyImage)" :src="replyImg" :key="replyIndex"
@click="preview(splitImg( comment.replyImage), index)"> @click="preview(splitImg(comment.replyImage), replyIndex)">
</u-image> </u-image>
</view> </view>
</view> </view>
@@ -40,56 +40,46 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import configs from '@/config/config' import configs from '@/config/config'
export default {
data() {
return {
configs,
userImage:configs.defaultUserPhoto,
comment: {}, //评论信息 const userImage = configs.defaultUserPhoto
gradeList: {
//评价grade const comment = ref<Record<string, any>>({})
GOOD: "好评", const gradeList: Record<string, string> = {
MODERATE: "中评", GOOD: '好评',
WORSE: "差评", MODERATE: '中评',
haveImage: "有图", WORSE: '差评',
}, haveImage: '有图',
};
},
onLoad(options) {
this.comment = JSON.parse(decodeURIComponent(options.comment));
},
methods: {
/**
* 切割图像
*/
splitImg(val) {
if (val && val.split(",")) {
return val.split(",");
} else if (val) {
return val;
} else {
return false;
} }
},
/** onLoad((options) => {
* 点击图片放大或保存 comment.value = JSON.parse(decodeURIComponent(options.comment))
*/ })
preview(urls, index) {
function splitImg(val: string) {
if (val && val.split(',')) {
return val.split(',')
} else if (val) {
return val
}
return false
}
function preview(urls: string[] | false, index: number) {
if (!urls) return
uni.previewImage({ uni.previewImage({
current: index, current: index,
urls: urls, urls: Array.isArray(urls) ? urls : [urls],
longPressActions: { longPressActions: {
itemList: ["保存图片"], itemList: ['保存图片'],
success: function (data) {}, success: () => {},
fail: function (err) {}, fail: () => {},
}, },
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -8,8 +8,9 @@
:inactiveStyle="{ color: '#333' }" :inactiveStyle="{ color: '#333' }"
v-model:current="current" v-model:current="current"
class="utabs" class="utabs"
:lineColor="$lightColor" :lineColor="lightColor"
:activeStyle="{ color: $lightColor }" :activeStyle="{ color: lightColor }"
:bg-color="'#ffffff'"
></u-tabs> ></u-tabs>
</view> </view>
<swiper class="swiper-box" :current="current" @change="changeSwiper" duration="500"> <swiper class="swiper-box" :current="current" @change="changeSwiper" duration="500">
@@ -38,7 +39,7 @@
<view class="btn-view u-row-between" v-if="current == 2"> <view class="btn-view u-row-between" v-if="current == 2">
<view class="description"> <view class="description">
<view class="text title"> <view class="text title">
<u-read-more ref="uReadMore" :color="$lightColor" text-indent="0"> <u-read-more ref="uReadMore" :color="lightColor" text-indent="0">
<rich-text :nodes="'评论内容:' + order.content || ''"></rich-text> <rich-text :nodes="'评论内容:' + order.content || ''"></rich-text>
</u-read-more> </u-read-more>
</view> </view>
@@ -78,171 +79,116 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getOrderList } from "@/api/order.js"; import { ref, reactive, computed, watch } from 'vue'
import { getComments } from "@/api/members.js"; import { onShow } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { getOrderList } from '@/api/order.js'
import { getComments } from '@/api/members.js'
export default { const store = useStore()
data() { const lightColor = computed(() => store.getters.lightColor)
return {
list: [
//顶部tab
{ const list = [
name: "全部订单", { name: '全部订单' },
}, { name: '待评价' },
{ { name: '已评价' },
name: "待评价", ]
},
{ const gradeList: Record<string, string> = {
name: "已评价", GOOD: '好评',
}, MODERATE: '中评',
], WORSE: '差评',
gradeList: { haveImage: '有图',
//评论表 }
GOOD: "好评",
MODERATE: "中评", const groupCommentStatusWay: Record<string, string> = {
WORSE: "差评", NEW: '新订单,不能进行评论',
haveImage: "有图", UNFINISHED: '未完成评论',
}, WAIT_CHASE: '待追评的评论信息',
groupCommentStatusWay: { FINISHED: '已经完成评论',
NEW: "新订单,不能进行评论", }
UNFINISHED: "未完成评论",
WAIT_CHASE: "待追评的评论信息", const current = ref(0)
FINISHED: "已经完成评论", const orderList = ref<any[]>([])
}, const params = reactive<Record<string, any>>({
current: 0, //当前tabIndex
orderList: [], //商品集合
params: {
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
loadStatus: "more", loadStatus: 'more',
}, })
};
},
onShow() { onShow(() => {
this.orderList = []; orderList.value = []
this.params.pageNumber = 1; params.pageNumber = 1
this.current = 0 current.value = 0
this.loadData() loadData()
}, })
watch: {
/** watch(current, (val) => {
* 切换current params.pageNumber = 1
* 更改页面并重新加载数据 params.loadStatus = 'more'
*/ orderList.value = []
current(val) {
this.params.pageNumber = 1;
this.params.loadStatus = "more";
this.orderList = [];
//重新读取数据
if (val == 0) { if (val == 0) {
delete this.params.commentStatus delete params.commentStatus
this.loadData(); loadData()
} else if (val == 1) { } else if (val == 1) {
this.params.commentStatus = "UNFINISHED"; params.commentStatus = 'UNFINISHED'
this.orderList = []; orderList.value = []
this.loadData(); loadData()
} else { } else {
this.params.commentStatus = "FINISHED"; params.commentStatus = 'FINISHED'
this.orderList = []; orderList.value = []
return this.loadComments(); loadComments()
} }
}, })
},
methods: { function preview(urls: string[], index: number) {
/**
* 判断当前店铺是否有可评价的商品
*/
commentStatus(val) {
if (this.current == 2) {
return true;
} else {
let show;
val.orderItems &&
val.orderItems.forEach((item) => {
if (item.commentStatus == "UNFINISHED") {
show = true;
} else {
show = false;
}
});
return show;
}
},
/**
* 点击图片放大或保存
*/
preview(urls, index) {
uni.previewImage({ uni.previewImage({
current: index, current: index,
urls: urls, urls,
longPressActions: { longPressActions: {
itemList: ["保存图片"], itemList: ['保存图片'],
success: function (data) {}, success: () => {},
fail: function (err) {}, fail: () => {},
}, },
}); })
},
/**
* 点击swiper
*/
changeSwiper(e) {
this.current = e.target.current;
},
/**
* 获取订单数据
*/
loadData() {
uni.showLoading({
title: "加载中",
});
getOrderList(this.params).then((res) => {
if (this.$store.state.isShowToast){ uni.hideLoading() };
const orderList = res.data.result.records;
if (orderList.length < 10) {
this.params.loadStatus = "noMore";
} }
if (orderList.length > 0) {
this.orderList = this.orderList.concat(orderList);
this.params.pageNumber += 1;
}
});
},
/** function changeSwiper(e: any) {
* 发表评价 current.value = e.target.current
*/ }
talkCommont(sku) {
console.log(sku); function loadData() {
uni.showLoading({ title: '加载中' })
getOrderList(params).then((res) => {
if (store.state.isShowToast) uni.hideLoading()
const records = res.data.result.records
if (records.length < 10) {
params.loadStatus = 'noMore'
}
if (records.length > 0) {
orderList.value = orderList.value.concat(records)
params.pageNumber += 1
}
})
}
function talkCommont(sku: any) {
uni.navigateTo({ uni.navigateTo({
url: `./releaseEvaluate?sn=${sku.sn}&sku=${encodeURIComponent( url: `./releaseEvaluate?sn=${sku.sn}&sku=${encodeURIComponent(JSON.stringify(sku))}`,
JSON.stringify(sku) })
)}`,
});
},
/**
* 加载已评价数据
*/
loadComments() {
uni.showLoading({
title: "加载中",
});
getComments(this.params).then((res) => {
if (this.$store.state.isShowToast){ uni.hideLoading() };
let orderList = res.data.result.records;
if (orderList.length < 10) {
this.params.loadStatus = "noMore";
} }
orderList.forEach((item) => {
function loadComments() {
uni.showLoading({ title: '加载中' })
getComments(params).then((res) => {
if (store.state.isShowToast) uni.hideLoading()
const records = res.data.result.records
if (records.length < 10) {
params.loadStatus = 'noMore'
}
records.forEach((item: any) => {
item.orderItems = [ item.orderItems = [
{ {
image: item.goodsImage, image: item.goodsImage,
@@ -250,37 +196,27 @@ export default {
goodsId: item.goodsId, goodsId: item.goodsId,
skuId: item.skuId, skuId: item.skuId,
}, },
]; ]
}); })
this.orderList = this.orderList.concat(orderList); orderList.value = orderList.value.concat(records)
this.params.pageNumber += 1; params.pageNumber += 1
}); })
},
/**
* 滑到底部加载数据
*/
renderData(index) {
if (this.params.loadStatus == "noMore") return;
if (index == 0) {
this.loadData();
} else {
this.loadComments();
} }
},
/** function renderData(index: number) {
* 评价详情 if (params.loadStatus == 'noMore') return
*/ if (index == 0) {
onDetail(comment) { loadData()
} else {
loadComments()
}
}
function onDetail(comment: any) {
uni.navigateTo({ uni.navigateTo({
url: url: './evaluateDetail?comment=' + encodeURIComponent(JSON.stringify(comment)),
"./evaluateDetail?comment=" + })
encodeURIComponent(JSON.stringify(comment)), }
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
page { page {
@@ -310,6 +246,7 @@ page {
.u-tabs-box { .u-tabs-box {
position: relative; position: relative;
z-index: 10; z-index: 10;
background: #ffffff;
} }
.box-content { .box-content {
margin: 20rpx 0; margin: 20rpx 0;

View File

@@ -86,80 +86,69 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import storage from "@/utils/storage.js"; import { ref, reactive } from 'vue'
import { commentsMemberOrder } from "@/api/members.js"; import { onLoad } from '@dcloudio/uni-app'
import { handleUploadAfterRead } from "@/utils/uploadHelper.js"; import { useStore } from '@/store'
import { commentsMemberOrder } from '@/api/members.js'
import { handleUploadAfterRead } from '@/utils/uploadHelper.js'
export default { const store = useStore()
data() {
return {
storage,
type: "textarea", //输入框状态为 textarea
border: false, //没有border
maxlength: 500, //评价最大字数为500字
placeholder:
"宝贝满足您的期待吗?说说它的优点和美中不足的地方吧。您的评价会帮助更多的人",
sku: {}, //订单信息
form: {
content: "", //评价详情
goodsId: "", //商品id
grade: "GOOD", //默认为好评
orderItemSn: "", //商品的sn
skuId: "", //商品skuId
descriptionScore: 5, //默认描述得分为5分
serviceScore: 5, //默认服务得分为5分
deliveryScore: 5, //默认物流得分为5分
},
uploadFileList: [],
};
},
onLoad(options) {
// 获取上一级传过来的数据进行解析
this.form.orderItemSn = options.sn;
this.sku = JSON.parse(decodeURIComponent(options.sku));
this.form.goodsId = this.sku.goodsId;
this.form.skuId = this.sku.skuId;
},
methods: {
/**
* 点击评价
*/
onGrade(grade) {
this.form.grade = grade;
},
/** const type = 'textarea'
* 提交评价 const border = false
*/ const maxlength = 500
onSubmit() { const placeholder =
uni.showLoading({ '宝贝满足您的期待吗?说说它的优点和美中不足的地方吧。您的评价会帮助更多的人'
title: "加载中",
}); const sku = ref<Record<string, any>>({})
commentsMemberOrder(this.form).then((res) => { const form = reactive<Record<string, any>>({
if (this.$store.state.isShowToast){ uni.hideLoading() }; content: '',
goodsId: '',
grade: 'GOOD',
orderItemSn: '',
skuId: '',
descriptionScore: 5,
serviceScore: 5,
deliveryScore: 5,
})
const uploadFileList = ref<any[]>([])
onLoad((options) => {
form.orderItemSn = options.sn
sku.value = JSON.parse(decodeURIComponent(options.sku))
form.goodsId = sku.value.goodsId
form.skuId = sku.value.skuId
})
function onGrade(grade: string) {
form.grade = grade
}
function onSubmit() {
uni.showLoading({ title: '加载中' })
commentsMemberOrder(form).then((res) => {
if (store.state.isShowToast) uni.hideLoading()
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({
title: "发布评价成功", title: '发布评价成功',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
success: () => { success: () => {
setTimeout(() => { setTimeout(() => {
uni.navigateBack(); uni.navigateBack()
}, 500); }, 500)
}, },
}); })
}
})
} }
});
},
onUploadAfterRead(event) { function onUploadAfterRead(event: any) {
handleUploadAfterRead(event, this.uploadFileList, (urls) => { handleUploadAfterRead(event, uploadFileList.value, (urls) => {
this.form.images = urls; form.images = urls
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -384,471 +384,426 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import * as API_Address from "@/api/address"; import { ref, computed, watch, getCurrentInstance } from 'vue'
import * as API_Order from "@/api/order"; import { onLoad, onShow, onBackPress } from '@dcloudio/uni-app'
import * as API_Trade from "@/api/trade"; import { useStore } from '@/store'
import configs from "@/config/config"; import * as API_Address from '@/api/address'
import LiLiWXPay from "@/js_sdk/lili-pay/wx-pay.js"; import * as API_Order from '@/api/order'
import invoices from "@/pages/order/invoice/setInvoice"; import * as API_Trade from '@/api/trade'
import { mapState } from "vuex"; import configs from '@/config/config'
export default { import LiLiWXPay from '@/js_sdk/lili-pay/wx-pay.js'
onLoad: function (val) { import invoices from '@/pages/order/invoice/setInvoice'
this.routerVal = val; import {
}, unitPrice,
components: { goodsFormatPrice,
invoices, secrecyMobile,
}, isLogin,
} from '@/utils/filters.js'
data() { const store = useStore()
return { const { proxy } = getCurrentInstance()!
configs, const lightColor = computed(() => store.getters.lightColor)
userImage: configs.defaultUserPhoto, const mainColor = computed(() => store.getters.mainColor)
invoiceFlag: false, //开票开关 const aiderLightColor = computed(() => store.getters.aiderLightColor)
shippingText: "LOGISTICS", const remark = computed(() => store.state.remark)
shippingFlag: false,
shippingMethod: [],
shippingWay: [
{
value: "LOGISTICS",
label: "物流",
},
{
value: "SELF_PICK_UP",
label: "自提",
},
],
isAssemble: false, //是否拼团
// 判断是否填写过备注
remarkFlag: false,
selectAddressId: "",
routerVal: "",
params: {},
// 优惠劵
couponList: "",
// 已选地址
address: "",
shopAddress: "",
// 发票信息
receiptList: "",
// 店铺信息
orderMessage: "",
data: "",
// 存储备注
remarkVal: [],
remarkVal1: "",
detail: "", //返回的所有数据
endWay: "", //最后一个参团人
masterWay: "", //团长信息
pintuanFlage: true, //是开团还是拼团
notSupportFreight: [], //不支持运费
notSupportFreightNoticeText: "",
storeAddress: "",
originOrderData:"", // 原始订单数据 interface ShippingOption {
}; value: string
label: string
}
const shippingWay: ShippingOption[] = [
{ value: 'LOGISTICS', label: '物流' },
{ value: 'SELF_PICK_UP', label: '自提' },
]
const userImage = configs.defaultUserPhoto
const invoiceFlag = ref(false)
const shippingText = ref('LOGISTICS')
const shippingFlag = ref(false)
const shippingMethod = ref<ShippingOption[]>([])
const isAssemble = ref(false)
const remarkFlag = ref(false)
const selectAddressId = ref('')
const routerVal = ref<Record<string, any>>({})
const params = ref<Record<string, any>>({})
const couponList = ref('')
const address = ref<any>('')
const shopAddress = ref('')
const receiptList = ref<any>('')
const orderMessage = ref<any>('')
const data = ref('')
const remarkVal = ref<any[]>([])
const remarkVal1 = ref('')
const detail = ref('')
const endWay = ref<any>('')
const masterWay = ref<any>('')
const pintuanFlage = ref(true)
const notSupportFreight = ref<any[]>([])
const notSupportFreightNoticeText = ref('')
const storeAddress = ref<any>('')
const originOrderData = ref<any>('')
watch(
remarkVal,
(val) => {
store.commit('setRemark', val)
}, },
watch: { { immediate: true, deep: true }
// 监听备注 并在 vuex 中存储 )
remarkVal: {
handler(val) { onLoad((val) => {
this.$store.commit("setRemark", val); routerVal.value = val || {}
}, })
immediate: true,
deep: true, onBackPress((e) => {
}, if (e.from == 'backbutton') {
}, const curRoute = getCurrentPages().slice(-1)[0]?.options || {}
computed: {
...mapState(["remark"]),
},
/**
* 监听返回
*/
onBackPress(e) {
if (e.from == "backbutton") {
const curRoute = getCurrentPages().slice(-1)[0]?.options || {};
if (curRoute.addId) { if (curRoute.addId) {
uni.reLaunch({ uni.reLaunch({
url: "/pages/tabbar/cart/cartList", url: '/pages/tabbar/cart/cartList',
}); })
} else if (this.routerVal?.way === "CART") { } else if (routerVal.value?.way === 'CART') {
uni.switchTab({ uni.switchTab({
url: "/pages/tabbar/cart/cartList", url: '/pages/tabbar/cart/cartList',
}); })
} else { } else {
uni.navigateBack(); uni.navigateBack()
} }
return true; return true
} }
}, return false
})
async onShow() { onShow(async () => {
// 判断是否存在写过备注信息的商品 if (remark.value && remark.value.length > 0) {
if (this.remark && this.remark.length > 0) { remarkFlag.value = true
this.remarkFlag = true;
} }
uni.showLoading({ uni.showLoading({
mask: true, mask: true,
}); })
try { try {
await this.getOrderList(); await getOrderList()
await this.getDistribution(); await getDistribution()
if (this.routerVal.way == "PINTUAN") { if (routerVal.value.way == 'PINTUAN') {
this.isAssemble = true; isAssemble.value = true
this.routerVal.parentOrder = JSON.parse( routerVal.value.parentOrder = JSON.parse(
decodeURIComponent(this.routerVal.parentOrder) decodeURIComponent(routerVal.value.parentOrder)
); )
this.pintuanWay(); pintuanWay()
} }
} finally { } finally {
uni.hideLoading(); uni.hideLoading()
} }
}, })
mounted() {},
methods: { function getShippingLabel() {
getShippingLabel() {
const item = const item =
this.shippingMethod.find((e) => e.value === this.shippingText) || shippingMethod.value.find((e) => e.value === shippingText.value) ||
this.shippingWay.find((e) => e.value === this.shippingText); shippingWay.find((e) => e.value === shippingText.value)
return item ? item.label : ""; return item ? item.label : ''
}, }
//发票回调 选择发票之后刷新购物车 async function callbackInvoice(val: any) {
async callbackInvoice(val) { invoiceFlag.value = false
this.invoiceFlag = false; receiptList.value = val
this.receiptList = val;
if (val) { if (val) {
let submit = { const submit = {
way: this.routerVal.way, way: routerVal.value.way,
...this.receiptList, ...receiptList.value,
}; }
let receipt = await API_Order.getReceipt(submit); const receipt = await API_Order.getReceipt(submit)
if (receipt.data.success) { if (receipt.data.success) {
this.shippingFlag = false; shippingFlag.value = false
this.getOrderList(); getOrderList()
}
} }
} }
},
// 跳转到店铺 function navigateToStore(val: any) {
navigateToStore(val) {
uni.navigateTo({ uni.navigateTo({
url: "/pages/product/shopPage?id=" + val.storeId, url: '/pages/product/shopPage?id=' + val.storeId,
}); })
}, }
// 点击跳转地址
clickToAddress() { function clickToAddress() {
this.navigateTo( navigateTo(
`/pages/mine/address/address?from=cart&way=${ `/pages/mine/address/address?from=cart&way=${
this.routerVal.way routerVal.value.way
}&parentOrder=${encodeURIComponent( }&parentOrder=${encodeURIComponent(
JSON.stringify(this.routerVal.parentOrder) JSON.stringify(routerVal.value.parentOrder)
)}` )}`
); )
}, }
clickToStoreAddress() {
this.navigateTo(
`/pages/mine/address/storeAddress?from=cart&way=${this.routerVal.way}&storeId=${this.remarkVal[0].storeId}`
);
},
// 判断团长以及团员信息 function clickToStoreAddress() {
pintuanWay() { navigateTo(
const { memberId } = this.routerVal.parentOrder; `/pages/mine/address/storeAddress?from=cart&way=${routerVal.value.way}&storeId=${remarkVal.value[0].storeId}`
)
}
const userInfo = this.isLogin(); function pintuanWay() {
const { memberId } = routerVal.value.parentOrder
const userInfo = isLogin()
if (memberId) { if (memberId) {
this.endWay = userInfo; endWay.value = userInfo
this.masterWay = this.routerVal.parentOrder; masterWay.value = routerVal.value.parentOrder
this.pintuanFlage = false; pintuanFlage.value = false
} else { } else {
this.pintuanFlage = true; pintuanFlage.value = true
this.masterWay = userInfo; masterWay.value = userInfo
}
} }
},
// 判断发票
invoice() {
this.invoiceFlag = true;
},
// 领取优惠券 function invoice() {
GET_Discount() { invoiceFlag.value = true
// 循环店铺id,商品id获取优惠券 }
let store = [];
let skus = []; function GET_Discount() {
let selectedCoupon = []; let storeIds: any[] = []
if (this.orderMessage.platformCoupon) let skus: any[] = []
selectedCoupon.push(this.orderMessage.platformCoupon.memberCoupon.id); const selectedCoupon: any[] = []
if (orderMessage.value.platformCoupon) {
selectedCoupon.push(orderMessage.value.platformCoupon.memberCoupon.id)
}
if ( if (
this.orderMessage.storeCoupons && orderMessage.value.storeCoupons &&
Object.keys(this.orderMessage.storeCoupons)[0] Object.keys(orderMessage.value.storeCoupons)[0]
) { ) {
let storeMemberCouponsId = Object.keys( const storeMemberCouponsId = Object.keys(
this.orderMessage.storeCoupons orderMessage.value.storeCoupons
)[0]; )[0]
let storeCouponId = const storeCouponId =
this.orderMessage.storeCoupons[storeMemberCouponsId].memberCoupon.id; orderMessage.value.storeCoupons[storeMemberCouponsId].memberCoupon.id
selectedCoupon.push(storeCouponId); selectedCoupon.push(storeCouponId)
} }
this.orderMessage.cartList.forEach((item) => { orderMessage.value.cartList.forEach((item: any) => {
item.skuList.forEach((sku) => { item.skuList.forEach((sku: any) => {
store.push(sku.storeId); storeIds.push(sku.storeId)
skus.push(sku.goodsSku.id); skus.push(sku.goodsSku.id)
}); })
}); })
store = Array.from(new Set(store)); storeIds = Array.from(new Set(storeIds))
skus = Array.from(new Set(skus)); skus = Array.from(new Set(skus))
uni.setStorage({ uni.setStorage({
key: "totalPrice", key: 'totalPrice',
data: this.orderMessage.priceDetailDTO.goodsPrice, data: orderMessage.value.priceDetailDTO.goodsPrice,
}); })
this.navigateTo( navigateTo(
`/pages/cart/coupon/index?way=${this.routerVal.way}&storeId=${store}&skuId=${skus}&selectedCoupon=${selectedCoupon}` `/pages/cart/coupon/index?way=${routerVal.value.way}&storeId=${storeIds}&skuId=${skus}&selectedCoupon=${selectedCoupon}`
); )
}, }
/** function navigateTo(url: string) {
* 跳转
*/
navigateTo(url) {
uni.navigateTo({ uni.navigateTo({
url, url,
}); })
}, }
/** function createTradeFun() {
* 提交订单准备支付 proxy!.$u.throttle(() => {
*/ if (shippingText.value === 'SELF_PICK_UP') {
if (!storeAddress.value.id) {
// 创建订单
createTradeFun() {
// 防抖
this.$u.throttle(() => {
if (this.shippingText === "SELF_PICK_UP") {
if (!this.storeAddress.id) {
uni.showToast({ uni.showToast({
title: "请选择提货点", title: '请选择提货点',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
} else if (this.shippingText === "LOGISTICS" && this.orderMessage.cartTypeEnum !== 'VIRTUAL') { } else if (
if (!this.address.id) { shippingText.value === 'LOGISTICS' &&
orderMessage.value.cartTypeEnum !== 'VIRTUAL'
) {
if (!address.value.id) {
uni.showToast({ uni.showToast({
title: "请选择地址", title: '请选择地址',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
} }
// 创建订单 let client
let client;
// #ifdef H5 // #ifdef H5
client = "H5"; client = 'H5'
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
client = "WECHAT_MP"; client = 'WECHAT_MP'
// #endif // #endif
// #ifdef APP-PLUS // #ifdef APP-PLUS
client = "APP"; client = 'APP'
// #endif // #endif
let submit = { const submit: Record<string, any> = {
client, client,
way: this.routerVal.way, way: routerVal.value.way,
remark: this.remarkVal, remark: remarkVal.value,
parentOrderSn: "", parentOrderSn: '',
}; }
// 如果是拼团并且当前用户不是团长 if (routerVal.value.parentOrder && routerVal.value.parentOrder.orderSn) {
this.routerVal.parentOrder && this.routerVal.parentOrder.orderSn submit.parentOrderSn = routerVal.value.parentOrder.orderSn
? (submit.parentOrderSn = this.routerVal.parentOrder.orderSn) } else {
: delete submit.parentOrderSn; delete submit.parentOrderSn
}
/**
* 创建订单
*/
API_Trade.createTrade(submit).then((res) => { API_Trade.createTrade(submit).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({
title: "创建订单成功!", title: '创建订单成功!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
// 如果当前价格为0跳转到订单列表 if (orderMessage.value.priceDetailDTO.billPrice == 0) {
if (this.orderMessage.priceDetailDTO.billPrice == 0) {
uni.navigateTo({ uni.navigateTo({
url: "/pages/order/myOrder?status=0", url: '/pages/order/myOrder?status=0',
}); })
} else { } else {
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
// 微信小程序中点击创建订单直接开始支付 pay(res.data.result.sn)
this.pay(res.data.result.sn);
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
this.navigateTo( navigateTo(
`/pages/cart/payment/payOrder?trade_sn=${res.data.result.sn}` `/pages/cart/payment/payOrder?trade_sn=${res.data.result.sn}`
); )
// #endif // #endif
} }
} else { } else {
uni.showToast({ uni.showToast({
title: res.data.message, title: res.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}
})
}, 3000)
} }
});
}, 3000);
},
/** async function pay(sn: string) {
* 微信小程序中直接支付
*/
async pay(sn) {
new LiLiWXPay({ new LiLiWXPay({
sn: sn, sn,
price: this.orderMessage.priceDetailDTO.billPrice, price: orderMessage.value.priceDetailDTO.billPrice,
}).pay(); }).pay()
}, }
/** function getUserAddress() {
* 获取用户地址
*/
getUserAddress() {
// 如果没有商品选择地址的话 则选择 默认地址
API_Address.getAddressDefault().then((res) => { API_Address.getAddressDefault().then((res) => {
if (res.data.result) { if (res.data.result) {
res.data.result.consigneeAddressPath = res.data.result.consigneeAddressPath =
res.data.result.consigneeAddressPath.split(","); res.data.result.consigneeAddressPath.split(',')
this.address = res.data.result; address.value = res.data.result
} }
}); })
}, }
// 获取配送列表
async getDistribution() { async function getDistribution() {
let shopRes = await API_Trade.shippingMethodList({ const shopRes = await API_Trade.shippingMethodList({
way: this.routerVal.way, way: routerVal.value.way,
}); })
let shopList;
if (shopRes.data.success) { if (shopRes.data.success) {
shopList = shopRes.data.result; const shopList = shopRes.data.result
let way = []; const way: ShippingOption[] = []
console.log(shopList); console.log(shopList)
this.shippingWay.forEach((item) => { shippingWay.forEach((item) => {
shopList.forEach((child) => { shopList.forEach((child: string) => {
if (item.value == child) { if (item.value == child) {
way.push(item); way.push(item)
}
})
})
shippingMethod.value = way
if (way.length && !way.some((item) => item.value === shippingText.value)) {
shippingText.value = way[0].value
} }
});
});
this.shippingMethod = way;
if (way.length && !way.some((item) => item.value === this.shippingText)) {
this.shippingText = way[0].value;
} }
} }
},
// 选择配送 async function confirmDistribution(val: any) {
async confirmDistribution(val) { const selected = val?.value?.[0] || val?.[0]
const selected = val?.value?.[0] || val?.[0];
if (!selected?.value) { if (!selected?.value) {
return; return
} }
let res = await API_Trade.setShipMethod({ const res = await API_Trade.setShipMethod({
shippingMethod: selected.value, shippingMethod: selected.value,
way: this.routerVal.way, way: routerVal.value.way,
}); })
this.shippingText = selected.value; shippingText.value = selected.value
if (res.data.success) { if (res.data.success) {
this.getOrderList(); getOrderList()
}
} }
},
// 获取结算参数 function getOrderList() {
getOrderList() { notSupportFreight.value = []
this.notSupportFreight = []; notSupportFreightNoticeText.value = ''
this.notSupportFreightNoticeText = ""; return API_Trade.getCheckoutParams(routerVal.value.way).then((res) => {
return API_Trade.getCheckoutParams(this.routerVal.way).then((res) => { originOrderData.value = orderMessage.value
// 获取结算参数 进行首次判断 ? JSON.parse(JSON.stringify(orderMessage.value))
this.originOrderData = this.orderMessage : null
? JSON.parse(JSON.stringify(this.orderMessage))
: null;
if ( if (
!res.data.result.checkedSkuList || !res.data.result.checkedSkuList ||
res.data.result.checkedSkuList.length === 0 res.data.result.checkedSkuList.length === 0
) { ) {
if (!this.originOrderData?.checkedSkuList?.length) { if (!originOrderData.value?.checkedSkuList?.length) {
uni.switchTab({ uni.switchTab({
url: "/pages/tabbar/cart/cartList", url: '/pages/tabbar/cart/cartList',
}); })
} }
} }
if (res.data.result.skuList.length <= 0) { if (res.data.result.skuList.length <= 0) {
if (!this.originOrderData?.skuList?.length) { if (!originOrderData.value?.skuList?.length) {
uni.navigateTo({ uni.navigateTo({
url: "/pages/order/myOrder?status=0", url: '/pages/order/myOrder?status=0',
}); })
} }
} }
let repeatData; let repeatData
res.data.result.cartList.forEach((item, index) => { res.data.result.cartList.forEach((item: any, index: number) => {
// 如果已经写过备注信息的话赋值
repeatData = { repeatData = {
remark: this.remarkFlag remark: remarkFlag.value
? this.remark[index].storeId == item.storeId ? remark.value[index].storeId == item.storeId
? this.remark[index].remark ? remark.value[index].remark
: item.remark : item.remark
: item.remark, : item.remark,
storeId: item.storeId, storeId: item.storeId,
}; }
this.remarkVal[index] = repeatData; remarkVal.value[index] = repeatData
}); })
this.orderMessage = res.data.result; orderMessage.value = res.data.result
/** ;(store.state as any).canUseCoupons = res.data.result.canUseCoupons
* 为了避免路径传值在h5中超出限制问题 ;(store.state as any).cantUseCoupons = res.data.result.cantUseCoupons
* 这块将可用的优惠券以及不可用的优惠券放入到vuex里面进行存储
*/
this.$store.state.canUseCoupons = res.data.result.canUseCoupons;
this.$store.state.cantUseCoupons = res.data.result.cantUseCoupons;
if (!res.data.result.memberAddress) { if (!res.data.result.memberAddress) {
// 获取会员默认地址 getUserAddress()
this.getUserAddress();
} else { } else {
this.address = res.data.result.memberAddress; address.value = res.data.result.memberAddress
res.data.result.memberAddress.consigneeAddressPath = res.data.result.memberAddress.consigneeAddressPath =
res.data.result.memberAddress.consigneeAddressPath.split(","); res.data.result.memberAddress.consigneeAddressPath.split(',')
} }
if (res.data.result.storeAddress) { if (res.data.result.storeAddress) {
this.storeAddress = res.data.result.storeAddress; storeAddress.value = res.data.result.storeAddress
console.log("storeAddress", this.storeAddress); console.log('storeAddress', storeAddress.value)
} }
if ( if (
res.data.result.notSupportFreight && res.data.result.notSupportFreight &&
res.data.result.notSupportFreight.length != 0 res.data.result.notSupportFreight.length != 0
) { ) {
this.notSupportFreight = res.data.result.notSupportFreight; notSupportFreight.value = res.data.result.notSupportFreight
this.notSupportFreightNoticeText = "以下商品超出配送范围:"; notSupportFreightNoticeText.value = '以下商品超出配送范围:'
res.data.result.notSupportFreight.forEach((item) => { res.data.result.notSupportFreight.forEach((item: any) => {
this.notSupportFreightNoticeText += item.goodsSku.goodsName; notSupportFreightNoticeText.value += item.goodsSku.goodsName
}); })
}
})
} }
});
},
//
},
};
</script> </script>
<style scoped> <style scoped>
page { page {

View File

@@ -74,185 +74,128 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getReceiptDetail } from "@/api/order.js"; import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getReceiptDetail } from '@/api/order.js'
import { unitPrice } from '@/utils/filters.js'
export default { const order = ref<Record<string, any>>({})
data() { const title_type = ref('')
return { const showInvoicePopup = ref(false)
order: {},
title_type: "", onLoad((options) => {
showInvoicePopup: false, loadData(options.id)
}; })
},
onLoad(options) { function loadData(id: string) {
this.loadData(options.id);
},
methods: {
loadData(id) {
getReceiptDetail(id).then((res) => { getReceiptDetail(id).then((res) => {
let order = res.data.result; const result = res.data.result
this.order = order; order.value = result
this.title_type = order.companyName || order.taxpayerId ? "单位" : "个人"; title_type.value = result.companyName || result.taxpayerId ? '单位' : '个人'
}); })
},
getTitleNameValue() {
return this.title_type === "单位"
? this.order.companyName || "-"
: this.order.personalName || "-";
},
viewInvoice() {
if (!this.order.invoiceAddress) {
uni.showToast({
title: "暂无发票地址",
duration: 2000,
icon: "none",
});
return;
} }
if (this.isImageInvoice()) {
this.showInvoicePopup = true; function getTitleNameValue() {
return; return title_type.value === '单位'
? order.value.companyName || '-'
: order.value.personalName || '-'
}
function viewInvoice() {
if (!order.value.invoiceAddress) {
uni.showToast({
title: '暂无发票地址',
duration: 2000,
icon: 'none',
})
return
}
if (isImageInvoice()) {
showInvoicePopup.value = true
return
} }
// #ifdef APP-PLUS // #ifdef APP-PLUS
plus.runtime.openURL(this.order.invoiceAddress); plus.runtime.openURL(order.value.invoiceAddress)
// #endif // #endif
// #ifndef APP-PLUS // #ifndef APP-PLUS
uni.navigateTo({ uni.navigateTo({
url: url: '/pages/tabbar/home/web-view?src=' + encodeURIComponent(order.value.invoiceAddress),
"/pages/tabbar/home/web-view?src=" + })
encodeURIComponent(this.order.invoiceAddress),
});
// #endif // #endif
},
isImageInvoice() {
const url = (this.order.invoiceAddress || "").split("?")[0].toLowerCase();
return /\.(png|jpe?g|gif|bmp|webp)$/.test(url);
},
previewImageInvoice() {
if (!this.order.invoiceAddress) {
return;
} }
function isImageInvoice() {
const url = (order.value.invoiceAddress || '').split('?')[0].toLowerCase()
return /\.(png|jpe?g|gif|bmp|webp)$/.test(url)
}
function previewImageInvoice() {
if (!order.value.invoiceAddress) return
uni.previewImage({ uni.previewImage({
current: 0, current: 0,
urls: [this.order.invoiceAddress], urls: [order.value.invoiceAddress],
}); })
}, }
downloadImageInvoice() {
if (!this.order.invoiceAddress) { function downloadImageInvoice() {
if (!order.value.invoiceAddress) {
uni.showToast({ uni.showToast({
title: "暂无发票可下载", title: '暂无发票可下载',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return; return
} }
uni.downloadFile({ uni.downloadFile({
url: this.order.invoiceAddress, url: order.value.invoiceAddress,
success: (res) => { success: (res) => {
if (res.statusCode !== 200) { if (res.statusCode !== 200) {
uni.showToast({ uni.showToast({
title: "下载失败", title: '下载失败',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return; return
} }
const tempFilePath = res.tempFilePath; const tempFilePath = res.tempFilePath
// #ifdef H5 // #ifdef H5
const link = document.createElement("a"); const link = document.createElement('a')
link.href = tempFilePath || this.order.invoiceAddress; link.href = tempFilePath || order.value.invoiceAddress
link.download = "invoice"; link.download = 'invoice'
document.body.appendChild(link); document.body.appendChild(link)
link.click(); link.click()
document.body.removeChild(link); document.body.removeChild(link)
// #endif // #endif
// #ifndef H5 // #ifndef H5
uni.saveImageToPhotosAlbum({ uni.saveImageToPhotosAlbum({
filePath: tempFilePath, filePath: tempFilePath,
success: () => { success: () => {
uni.showToast({ uni.showToast({
title: "发票已保存到相册", title: '发票已保存到相册',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}, },
fail: () => { fail: () => {
uni.showToast({ uni.showToast({
title: "保存失败", title: '保存失败',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}, },
}); })
// #endif // #endif
}, },
fail: () => { fail: () => {
uni.showToast({ uni.showToast({
title: "下载失败", title: '下载失败',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
}, },
}); })
},
/**
* 点击图片放大或保存
*/
preview() {
//预览发票
if (this.order.elec_file_list.length) {
uni.previewImage({
current: 0,
urls: this.order.elec_file_list,
longPressActions: {
itemList: ["发送给朋友", "保存图片", "收藏"],
success: function (data) {},
fail: function (err) {},
},
});
} else {
uni.showToast({
title: "暂无发票可预览",
duration: 2000,
icon: "none",
});
} }
},
download() {
//下载发票
let _this = this;
if (this.order.elec_file_list.length) {
this.order.elec_file_list.forEach((item) => {
uni.downloadFile({
url: item,
success: (res) => {
if (res.statusCode === 200) {
let tempFilePath = res.tempFilePath;
uni.saveFile({
tempFilePath: tempFilePath,
success: function (res) {
uni.showToast({
title: "发票已下载到" + res.savedFilePath,
duration: 2000,
icon: "none",
});
},
});
}
},
});
});
} else {
uni.showToast({
title: "暂无发票可下载",
duration: 2000,
icon: "none",
});
}
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -92,245 +92,260 @@
</div> </div>
</u-popup> </u-popup>
</template> </template>
<script> <script setup lang="ts">
export default { import { ref, reactive, computed, watch, onMounted, getCurrentInstance } from 'vue'
props: ["res"],
computed: { interface InvoiceOption {
isSpecialInvoice() { title: string
return this.getActiveTitle(this.invoiceType) === "增值税专用发票"; active: boolean
}, disabled?: boolean
titleName: {
get() {
return this.isUnitTitle()
? this.submitData.companyName
: this.submitData.personalName;
},
set(value) {
if (this.isUnitTitle()) {
this.submitData.companyName = value;
} else {
this.submitData.personalName = value;
} }
this.syncReceiptTitle();
interface SubmitData {
receiptTitle: string
receiptType: string
personalName: string
companyName: string
taxpayerId: string
receiptContent: string
companyAddress: string
companyPhone: string
bankName: string
bankAccount: string
receiptPhone: string
receiptEmail: string
}
const props = defineProps<{
res?: Record<string, any>
}>()
const emit = defineEmits<{
callbackInvoice: [val: SubmitData | boolean]
}>()
const { proxy } = getCurrentInstance()!
const shouldClearOnTypeChange = ref(false)
const taxpayerFlag = ref(false)
const submitData = reactive<SubmitData>({
receiptTitle: '',
receiptType: '1',
personalName: '',
companyName: '',
taxpayerId: '',
receiptContent: '',
companyAddress: '',
companyPhone: '',
bankName: '',
bankAccount: '',
receiptPhone: '',
receiptEmail: '',
})
const show = ref(true)
const title = ref('')
const tips =
'电子发票即电子增值税发票,是税局认可的有效凭证,其法律效力、基本用途及使用规定同纸质发票。'
const invoiceType = reactive<InvoiceOption[]>([
{ title: '电子普通发票', active: true },
{ title: '增值税专用发票', active: false },
])
const invoiceHeader = reactive<InvoiceOption[]>([
{ title: '个人', active: false },
{ title: '单位', active: false },
])
const goodsType = reactive<InvoiceOption[]>([
{ title: '商品明细', active: false },
{ title: '商品类别', active: false },
])
const isSpecialInvoice = computed(
() => getActiveTitle(invoiceType) === '增值税专用发票'
)
const titleName = computed({
get() {
return isUnitTitle() ? submitData.companyName : submitData.personalName
}, },
set(value: string) {
if (isUnitTitle()) {
submitData.companyName = value
} else {
submitData.personalName = value
}
syncReceiptTitle()
}, },
}, })
watch: {
invoiceType: { watch(
handler(val) { invoiceType,
const currentType = this.getActiveTitle(val); (val) => {
const nextReceiptType = const currentType = getActiveTitle(val)
currentType === "增值税专用发票" ? "2" : "1"; const nextReceiptType = currentType === '增值税专用发票' ? '2' : '1'
const previousReceiptType = this.submitData.receiptType; const previousReceiptType = submitData.receiptType
this.submitData.receiptType = nextReceiptType; submitData.receiptType = nextReceiptType
if ( if (
this.shouldClearOnTypeChange && shouldClearOnTypeChange.value &&
previousReceiptType && previousReceiptType &&
previousReceiptType !== nextReceiptType previousReceiptType !== nextReceiptType
) { ) {
this.clearInvoiceInfo(); clearInvoiceInfo()
} }
if (currentType === "增值税专用发票") { if (currentType === '增值税专用发票') {
this.setActiveByTitle(this.invoiceHeader, "单位"); setActiveByTitle(invoiceHeader, '单位')
this.setActiveByTitle(this.goodsType, "商品明细"); setActiveByTitle(goodsType, '商品明细')
this.title = "单位"; title.value = '单位'
this.taxpayerFlag = true; taxpayerFlag.value = true
this.submitData.receiptContent = "商品明细"; submitData.receiptContent = '商品明细'
this.syncReceiptTitle(); syncReceiptTitle()
} else { } else {
this.setActiveByTitle(this.invoiceHeader, "个人"); setActiveByTitle(invoiceHeader, '个人')
this.setActiveByTitle(this.goodsType, "商品明细"); setActiveByTitle(goodsType, '商品明细')
this.title = "个人"; title.value = '个人'
this.taxpayerFlag = false; taxpayerFlag.value = false
this.submitData.receiptContent = "商品明细"; submitData.receiptContent = '商品明细'
this.syncReceiptTitle(); syncReceiptTitle()
} }
this.shouldClearOnTypeChange = false; shouldClearOnTypeChange.value = false
}, },
deep: true, { deep: true }
}, )
invoiceHeader: {
handler(val) { watch(
if (this.isSpecialInvoice) { invoiceHeader,
this.title = "单位"; (val) => {
this.taxpayerFlag = true; if (isSpecialInvoice.value) {
return; title.value = '单位'
taxpayerFlag.value = true
return
} }
this.title = this.getActiveTitle(val) || "个人"; title.value = getActiveTitle(val) || '个人'
this.taxpayerFlag = this.title == "单位"; taxpayerFlag.value = title.value == '单位'
if (!this.taxpayerFlag) { if (!taxpayerFlag.value) {
this.submitData.taxpayerId = ""; submitData.taxpayerId = ''
} }
this.syncReceiptTitle(); syncReceiptTitle()
},
deep: true,
},
goodsType: {
handler(val) {
this.submitData.receiptContent = val.filter((item) => {
return item.active == true;
})[0].title;
},
deep: true,
},
}, },
{ deep: true }
)
data() { watch(
return { goodsType,
shouldClearOnTypeChange: false, (val) => {
taxpayerFlag: false, submitData.receiptContent = val.filter((item) => item.active == true)[0].title
submitData: {
receiptTitle: "", //发票抬头
receiptType: "1", // 发票类型
personalName: "",
companyName: "",
taxpayerId: "", //纳税人
receiptContent: "",
companyAddress: "", //单位地址
companyPhone: "", //单位电话
bankName: "", //开户银行
bankAccount: "", //银行账号
receiptPhone: "", //收票人手机
receiptEmail: "", //收票人邮箱
}, },
show: true, { deep: true }
title: "", )
tips:
"电子发票即电子增值税发票,是税局认可的有效凭证,其法律效力、基本用途及使用规定同纸质发票。", onMounted(() => {
// 发票类型 if (props.res) {
invoiceType: [ submitData.receiptType = normalizeReceiptType(props.res.receiptType)
{ submitData.personalName =
title: "电子普通发票", props.res.personalName ||
active: true, (!props.res.companyName && !props.res.taxpayerId
}, ? props.res.receiptTitle || ''
{ : '')
title: "增值税专用发票", submitData.companyName =
active: false, props.res.companyName ||
}, (props.res.taxpayerId ? props.res.receiptTitle || '' : '')
], submitData.taxpayerId = props.res.taxpayerId
// 发票抬头 submitData.receiptContent = props.res.receiptContent
invoiceHeader: [ submitData.companyAddress = props.res.companyAddress || ''
{ submitData.companyPhone = props.res.companyPhone || ''
title: "个人", submitData.bankName = props.res.bankName || ''
active: false, submitData.bankAccount = props.res.bankAccount || ''
}, submitData.receiptPhone = props.res.receiptPhone || ''
{ submitData.receiptEmail = props.res.receiptEmail || ''
title: "单位", if (submitData.receiptType === '2') {
active: false, setActiveByTitle(invoiceType, '增值税专用发票')
}, setActiveByTitle(invoiceHeader, '单位')
], setActiveByTitle(goodsType, '商品明细')
// 商品类型
goodsType: [
{
title: "商品明细",
active: false,
},
{
title: "商品类别",
active: false,
},
],
};
},
mounted() {
if (this.res) {
this.submitData.receiptType = this.normalizeReceiptType(this.res.receiptType);
this.submitData.personalName =
this.res.personalName ||
(!this.res.companyName && !this.res.taxpayerId ? this.res.receiptTitle || "" : "");
this.submitData.companyName =
this.res.companyName ||
(this.res.taxpayerId ? this.res.receiptTitle || "" : "");
this.submitData.taxpayerId = this.res.taxpayerId; //纳税人
this.submitData.receiptContent = this.res.receiptContent;
this.submitData.companyAddress = this.res.companyAddress || "";
this.submitData.companyPhone = this.res.companyPhone || "";
this.submitData.bankName = this.res.bankName || "";
this.submitData.bankAccount = this.res.bankAccount || "";
this.submitData.receiptPhone = this.res.receiptPhone || "";
this.submitData.receiptEmail = this.res.receiptEmail || "";
if (this.submitData.receiptType === "2") {
this.setActiveByTitle(this.invoiceType, "增值税专用发票");
this.setActiveByTitle(this.invoiceHeader, "单位");
this.setActiveByTitle(this.goodsType, "商品明细");
} else { } else {
this.setActiveByTitle(this.invoiceType, "电子普通发票"); setActiveByTitle(invoiceType, '电子普通发票')
this.res.receiptContent == "商品类别" props.res.receiptContent == '商品类别'
? this.setActiveByTitle(this.goodsType, "商品类别") ? setActiveByTitle(goodsType, '商品类别')
: this.setActiveByTitle(this.goodsType, "商品明细"); : setActiveByTitle(goodsType, '商品明细')
this.res.taxpayerId props.res.taxpayerId
? this.setActiveByTitle(this.invoiceHeader, "单位") ? setActiveByTitle(invoiceHeader, '单位')
: this.setActiveByTitle(this.invoiceHeader, "个人"); : setActiveByTitle(invoiceHeader, '个人')
} }
this.syncReceiptTitle(); syncReceiptTitle()
} else { } else {
this.setActiveByTitle(this.invoiceType, "电子普通发票"); setActiveByTitle(invoiceType, '电子普通发票')
this.setActiveByTitle(this.invoiceHeader, "个人"); setActiveByTitle(invoiceHeader, '个人')
this.setActiveByTitle(this.goodsType, "商品明细"); setActiveByTitle(goodsType, '商品明细')
this.syncReceiptTitle(); syncReceiptTitle()
}
})
function normalizeReceiptType(type: string) {
return type === '2' || type === 'VATOSPECIAL' ? '2' : '1'
} }
}, function getActiveTitle(list: InvoiceOption[]) {
methods: { const current = list.find((item) => item.active)
normalizeReceiptType(type) { return current ? current.title : ''
return type === "2" || type === "VATOSPECIAL" ? "2" : "1"; }
},
getActiveTitle(list) { function setActiveByTitle(list: InvoiceOption[], activeTitle: string) {
const current = list.find((item) => item.active);
return current ? current.title : "";
},
setActiveByTitle(list, title) {
list.forEach((item) => { list.forEach((item) => {
item.active = item.title === title; item.active = item.title === activeTitle
}); })
},
isUnitTitle() {
return this.isSpecialInvoice || this.title === "单位";
},
syncReceiptTitle() {
this.submitData.receiptTitle = this.isUnitTitle()
? this.submitData.companyName
: this.submitData.personalName;
},
clearInvoiceInfo() {
this.submitData.receiptTitle = "";
this.submitData.personalName = "";
this.submitData.companyName = "";
this.submitData.taxpayerId = "";
this.submitData.receiptContent = "";
this.submitData.companyAddress = "";
this.submitData.companyPhone = "";
this.submitData.bankName = "";
this.submitData.bankAccount = "";
this.submitData.receiptPhone = "";
this.submitData.receiptEmail = "";
},
handleClickHeader(val, index, arr) {
if (val.disabled) {
return;
} }
const previousTitle = this.getActiveTitle(arr);
if (arr === this.invoiceType && previousTitle !== val.title) { function isUnitTitle() {
this.shouldClearOnTypeChange = true; return isSpecialInvoice.value || title.value === '单位'
}
function syncReceiptTitle() {
submitData.receiptTitle = isUnitTitle()
? submitData.companyName
: submitData.personalName
}
function clearInvoiceInfo() {
submitData.receiptTitle = ''
submitData.personalName = ''
submitData.companyName = ''
submitData.taxpayerId = ''
submitData.receiptContent = ''
submitData.companyAddress = ''
submitData.companyPhone = ''
submitData.bankName = ''
submitData.bankAccount = ''
submitData.receiptPhone = ''
submitData.receiptEmail = ''
}
function handleClickHeader(
val: InvoiceOption,
_index: number,
arr: InvoiceOption[]
) {
if (val.disabled) {
return
}
const previousTitle = getActiveTitle(arr)
if (arr === invoiceType && previousTitle !== val.title) {
shouldClearOnTypeChange.value = true
} }
arr.forEach((item) => { arr.forEach((item) => {
item.active = false; item.active = false
}); })
val.active = true; val.active = true
}, }
/**
* 监听关闭 function close(val: SubmitData | boolean) {
*/ emit('callbackInvoice', val)
close(val) { }
this.$emit("callbackInvoice", val);
}, function submitInvoice() {
submitInvoice() {
/**
* 验证
*/
const { const {
receiptTitle, receiptTitle,
taxpayerId, taxpayerId,
@@ -340,92 +355,92 @@ export default {
bankAccount, bankAccount,
receiptPhone, receiptPhone,
receiptEmail, receiptEmail,
} = this.submitData; } = submitData
this.syncReceiptTitle(); syncReceiptTitle()
if (this.$u.test.isEmpty(receiptTitle)) { if (proxy.$u.test.isEmpty(receiptTitle)) {
uni.showToast({ uni.showToast({
title: "请您填写发票抬头!", title: '请您填写发票抬头!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
if ( if (
!this.$u.test.isEmpty(receiptTitle) && !proxy.$u.test.isEmpty(receiptTitle) &&
this.$u.test.isEmpty(taxpayerId) && proxy.$u.test.isEmpty(taxpayerId) &&
this.invoiceHeader[1].active == true invoiceHeader[1].active == true
) { ) {
uni.showToast({ uni.showToast({
title: "请您填写纳税人识别号!", title: '请您填写纳税人识别号!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false
return false;
} }
if (this.isSpecialInvoice && this.$u.test.isEmpty(companyAddress)) { if (isSpecialInvoice.value && proxy.$u.test.isEmpty(companyAddress)) {
uni.showToast({ uni.showToast({
title: "请您填写单位地址!", title: '请您填写单位地址!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
if (this.isSpecialInvoice && this.$u.test.isEmpty(companyPhone)) { if (isSpecialInvoice.value && proxy.$u.test.isEmpty(companyPhone)) {
uni.showToast({ uni.showToast({
title: "请您填写单位电话!", title: '请您填写单位电话!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
if (this.isSpecialInvoice && this.$u.test.isEmpty(bankName)) { if (isSpecialInvoice.value && proxy.$u.test.isEmpty(bankName)) {
uni.showToast({ uni.showToast({
title: "请您填写开户银行!", title: '请您填写开户银行!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
if (this.isSpecialInvoice && this.$u.test.isEmpty(bankAccount)) { if (isSpecialInvoice.value && proxy.$u.test.isEmpty(bankAccount)) {
uni.showToast({ uni.showToast({
title: "请您填写银行账号!", title: '请您填写银行账号!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
if (this.$u.test.isEmpty(receiptPhone)) { if (proxy.$u.test.isEmpty(receiptPhone)) {
uni.showToast({ uni.showToast({
title: "请您填写收票人手机!", title: '请您填写收票人手机!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
if (!this.$u.test.mobile(receiptPhone)) { if (!proxy.$u.test.mobile(receiptPhone)) {
uni.showToast({ uni.showToast({
title: "请输入正确的收票人手机号!", title: '请输入正确的收票人手机号!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
if (!this.$u.test.isEmpty(receiptEmail) && !this.$u.test.email(receiptEmail)) { if (
!proxy.$u.test.isEmpty(receiptEmail) &&
!proxy.$u.test.email(receiptEmail)
) {
uni.showToast({ uni.showToast({
title: "请输入正确的收票人邮箱!", title: '请输入正确的收票人邮箱!',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
return false; return false
} }
this.show = false; show.value = false
this.close(this.submitData); close(submitData)
}, }
},
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.form-item { .form-item {

View File

@@ -11,7 +11,7 @@
<u-empty text="暂无订单" mode="list" <u-empty text="暂无订单" mode="list"
v-if="tabItem.loaded === true && tabItem.orderList.length === 0"></u-empty> v-if="tabItem.loaded === true && tabItem.orderList.length === 0"></u-empty>
<!-- 订单列表 --> <!-- 订单列表 -->
<view class="seller-view" :key="oderIndex" v-for="(order, oderIndex) in tabItem.orderList"> <view class="seller-view" :key="orderIndex" v-for="(order, orderIndex) in tabItem.orderList">
<!-- 店铺名称 --> <!-- 店铺名称 -->
<view class="seller-info u-flex u-row-between"> <view class="seller-info u-flex u-row-between">
<view class="seller-name wes" @click="navigateToStore(order)"> <view class="seller-name wes" @click="navigateToStore(order)">
@@ -108,458 +108,339 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import uniLoadMore from "@/components/uni-load-more/uni-load-more.vue"; import { ref, reactive, computed, watch, getCurrentInstance } from 'vue'
import { onLoad, onShow, onPullDownRefresh, onBackPress } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
import { getOrderList, cancelOrder, confirmReceipt } from '@/api/order.js'
import { getClearReason } from '@/api/after-sale.js'
import LiLiWXPay from '@/js_sdk/lili-pay/wx-pay.js'
import { import {
getOrderList, unitPrice,
cancelOrder, parseGoodsImageUrl,
confirmReceipt tipsToLogin,
} from "@/api/order.js"; orderStatusList,
import { } from '@/utils/filters.js'
getClearReason
} from "@/api/after-sale.js"; const store = useStore()
import LiLiWXPay from "@/js_sdk/lili-pay/wx-pay.js"; const { proxy } = getCurrentInstance()!
export default { const lightColor = computed(() => store.getters.lightColor)
components: { const mainColor = computed(() => store.getters.mainColor)
uniLoadMore,
}, interface NavTabItem {
data() { state: number
return { text: string
lightColor: this.$lightColor, loadStatus: string
tabCurrentIndex: 0, //导航栏索引 orderList: any[]
navList: [ pageNumber: number
//导航栏list loaded?: boolean
{ }
state: 0,
text: "全部", const tabCurrentIndex = ref(0)
loadStatus: "more", const navList = reactive<NavTabItem[]>([
orderList: [], { state: 0, text: '全部', loadStatus: 'more', orderList: [], pageNumber: 1 },
pageNumber: 1, { state: 1, text: '待付款', loadStatus: 'more', orderList: [], pageNumber: 1 },
}, { state: 2, text: '待发货', loadStatus: 'more', orderList: [], pageNumber: 1 },
{ { state: 3, text: '待收货', loadStatus: 'more', orderList: [], pageNumber: 1 },
state: 1, { state: 4, text: '已完成', loadStatus: 'more', orderList: [], pageNumber: 1 },
text: "待付款", { state: 5, text: '已取消', loadStatus: 'more', orderList: [], pageNumber: 1 },
loadStatus: "more", ])
orderList: [],
pageNumber: 1, const status = ref<number>(0)
}, const params = reactive({
{
state: 2,
text: "待发货",
loadStatus: "more",
orderList: [],
pageNumber: 1,
},
{
state: 3,
text: "待收货",
loadStatus: "more",
orderList: [],
pageNumber: 1,
},
{
state: 4,
text: "已完成",
loadStatus: "more",
orderList: [],
pageNumber: 1,
},
{
state: 5,
text: "已取消",
loadStatus: "more",
orderList: [],
pageNumber: 1,
},
],
status: "", //接收导航栏状态
params: {
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10,
tag: "ALL", tag: 'ALL',
}, })
orderStatus: [
//订单状态
{
orderStatus: "ALL", //全部
},
{
orderStatus: "WAIT_PAY", //代付款
},
{
orderStatus: "WAIT_SHIP",
},
{
orderStatus: "WAIT_ROG", //待收货
},
{
orderStatus: "COMPLETE", //已完成
},
{
orderStatus: "CANCELLED", //已取消
},
{
orderStatus: "STAY_PICKED_UP", //待自提
},
],
cancelShow: false, //是否显示取消
orderSn: "", //ordersn
reason: "", //取消原因
cancelList: [], //取消列表
rogShow: false, //显示是否收货
};
},
/** const orderStatus = [
* 跳转到个人中心 { orderStatus: 'ALL' },
*/ { orderStatus: 'WAIT_PAY' },
onBackPress(e) { { orderStatus: 'WAIT_SHIP' },
if (e.from == "backbutton") { { orderStatus: 'WAIT_ROG' },
uni.switchTab({ { orderStatus: 'COMPLETE' },
url: "/pages/tabbar/user/my", { orderStatus: 'CANCELLED' },
}); { orderStatus: 'STAY_PICKED_UP' },
return true; //阻止默认返回行为 ]
const cancelShow = ref(false)
const orderSn = ref('')
const reason = ref('')
const cancelList = ref<any[]>([])
const rogShow = ref(false)
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
} }
},
onPullDownRefresh() { onBackPress((e) => {
if (this.tabCurrentIndex) { if (e.from == 'backbutton') {
this.initData(this.tabCurrentIndex); uni.switchTab({ url: '/pages/tabbar/user/my' })
return true
}
return false
})
onPullDownRefresh(() => {
if (tabCurrentIndex.value) {
initData(tabCurrentIndex.value)
} else { } else {
this.initData(0); initData(0)
} }
// this.loadData(this.status); })
},
onShow() { onShow(() => {
if (this.tipsToLogin()) { if (tipsToLogin()) {
if (!this.tabCurrentIndex) { if (!tabCurrentIndex.value) {
this.initData(0); initData(0)
} }
} }
// this.loadData(this.status); })
},
onLoad(options) { onLoad((options) => {
/** const statusNum = Number(options?.status)
* 修复app端点击除全部订单外的按钮进入时不加载数据的问题 status.value = statusNum
* 替换onLoad下代码即可 tabCurrentIndex.value = statusNum
*/ })
let status = Number(options.status);
this.status = status;
this.tabCurrentIndex = status; watch(tabCurrentIndex, (val) => {
// if (status == 0) { params.tag = orderStatus[val].orderStatus
// this.loadData(status); navList.forEach((res) => {
// } res.pageNumber = 1
}, res.loadStatus = 'more'
res.orderList = []
})
loadData(val)
})
watch: { function applyService(order: any) {
/**监听更改请求数据 */
tabCurrentIndex(val) {
this.params.tag = this.orderStatus[val].orderStatus;
//切换标签页将所有的页数都重置为1
this.navList.forEach((res) => {
res.pageNumber = 1;
res.loadStatus = "more";
res.orderList = [];
});
this.loadData(val);
},
},
methods: {
// 售后
applyService(order) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/order/afterSales/afterSales?orderSn=${order.sn}`, url: `/pages/order/afterSales/afterSales?orderSn=${order.sn}`,
}); })
}, }
// 店铺详情 function navigateToStore(val: any) {
navigateToStore(val) {
uni.navigateTo({ uni.navigateTo({
url: "/pages/product/shopPage?id=" + val.storeId, url: '/pages/product/shopPage?id=' + val.storeId,
}); })
},
renderOrderTag(orderPromotionType) {
switch (orderPromotionType) {
case "NORMAL":
return "";
case "PINTUAN":
return "拼团订单";
break;
case "GIFT":
return "赠品订单";
break;
case "POINTS":
return "积分订单";
break;
case "KANJIA":
return "砍价订单";
default:
return "";
} }
},
renderOrderTagType(orderPromotionType) { function renderOrderTag(orderPromotionType: string) {
switch (orderPromotionType) { switch (orderPromotionType) {
case "PINTUAN": case 'NORMAL':
return "error"; return ''
case "GIFT": case 'PINTUAN':
return "primary"; return '拼团订单'
case "POINTS": case 'GIFT':
return "info"; return '赠品订单'
case "KANJIA": case 'POINTS':
return "warning"; return '积分订单'
case 'KANJIA':
return '砍价订单'
default: default:
return "info"; return ''
} }
}, }
getOrderItemImage(goods, order, index) {
let image = goods.image; function renderOrderTagType(orderPromotionType: string) {
switch (orderPromotionType) {
case 'PINTUAN':
return 'error'
case 'GIFT':
return 'primary'
case 'POINTS':
return 'info'
case 'KANJIA':
return 'warning'
default:
return 'info'
}
}
function getOrderItemImage(goods: any, order: any, index: number) {
let image = goods.image
if (!image && order.groupImages) { if (!image && order.groupImages) {
const images = String(order.groupImages).split(","); const images = String(order.groupImages).split(',')
image = images[index] || images[0]; image = images[index] || images[0]
} }
return this.parseGoodsImageUrl(image); return parseGoodsImageUrl(image)
}, }
/**
* 取消订单 function onCancel(sn: string) {
*/ orderSn.value = sn
onCancel(sn) { cancelShow.value = true
this.orderSn = sn; uni.showLoading({ title: '加载中' })
this.cancelShow = true;
uni.showLoading({
title: "加载中",
});
getClearReason().then((res) => { getClearReason().then((res) => {
if (res.data.result.length >= 1) { if (res.data.result.length >= 1) {
this.cancelList = res.data.result; cancelList.value = res.data.result
}
hideLoadingIfNeeded()
})
} }
if (this.$store.state.isShowToast) {
uni.hideLoading()
};
});
},
/** function initData(index: number) {
* 初始化数据 navList[index].pageNumber = 1
*/ navList[index].loadStatus = 'more'
initData(index) { navList[index].orderList = []
this.navList[index].pageNumber = 1; loadData(index)
this.navList[index].loadStatus = "more"; }
this.navList[index].orderList = [];
this.loadData(index);
},
/** function waitPay(val: any) {
* 等待支付 proxy?.$u?.debounce?.(() => pay(val), 3000, true)?.()
*/ }
waitPay(val) {
this.$u.debounce(this.pay(val), 3000);
},
/** function pay(val: any) {
* 支付
*/
pay(val) {
if (val.sn) { if (val.sn) {
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
new LiLiWXPay({ new LiLiWXPay({
sn: val.sn, sn: val.sn,
price: val.flowPrice, price: val.flowPrice,
orderType: "ORDER", orderType: 'ORDER',
}).pay(); }).pay()
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
uni.navigateTo({ uni.navigateTo({
url: "/pages/cart/payment/payOrder?order_sn=" + val.sn, url: '/pages/cart/payment/payOrder?order_sn=' + val.sn,
}); })
// #endif // #endif
} }
}, }
/** function loadData(index: number) {
* 获取订单列表 params.pageNumber = navList[index].pageNumber
*/ getOrderList(params).then((res) => {
loadData(index) { uni.stopPullDownRefresh()
this.params.pageNumber = this.navList[index].pageNumber;
// this.params.tag = this.orderStatus[index].orderStatus;
getOrderList(this.params).then((res) => {
uni.stopPullDownRefresh();
if (!res.data.success) { if (!res.data.success) {
this.navList[index].loadStatus = "noMore"; navList[index].loadStatus = 'noMore'
return false; return false
} }
let orderList = res.data.result.records; const records = res.data.result.records
if (orderList.length == 0) { if (records.length == 0) {
this.navList[index].loadStatus = "noMore"; navList[index].loadStatus = 'noMore'
} else if (orderList.length < 10) { } else if (records.length < 10) {
this.navList[index].loadStatus = "noMore"; navList[index].loadStatus = 'noMore'
} }
if (orderList.length > 0) { if (records.length > 0) {
this.navList[index].orderList = navList[index].orderList = navList[index].orderList.concat(records)
this.navList[index].orderList.concat(orderList); navList[index].pageNumber += 1
this.navList[index].pageNumber += 1;
} }
}); })
}, }
//swiper 切换监听
changeTab(e) { function changeTab(e: any) {
this.tabCurrentIndex = e.target.current; tabCurrentIndex.value = e.target.current
}, }
//顶部tab点击
tabClick(index) { function tabClick(index: number) {
this.tabCurrentIndex = index; tabCurrentIndex.value = index
}, }
//删除订单
deleteOrder(index) { function deleteOrder(index: number) {
uni.showLoading({ uni.showLoading({ title: '请稍后' })
title: "请稍后",
});
setTimeout(() => { setTimeout(() => {
this.navList[this.tabCurrentIndex].orderList.splice(index, 1); navList[tabCurrentIndex.value].orderList.splice(index, 1)
if (this.$store.state.isShowToast) { hideLoadingIfNeeded()
uni.hideLoading() }, 600)
}; }
}, 600);
}, function cancelOrderLocal(item: any) {
//取消订单 uni.showLoading({ title: '请稍后' })
cancelOrder(item) {
uni.showLoading({
title: "请稍后",
});
setTimeout(() => { setTimeout(() => {
let { const { stateTip, stateTipColor } = orderStateExp(9)
stateTip, Object.assign(item, {
stateTipColor
} = this.orderStateExp(9);
item = Object.assign(item, {
state: 9, state: 9,
stateTip, stateTip,
stateTipColor, stateTipColor,
}); })
const list = navList[1].orderList
const idx = list.findIndex((val) => val.id === item.id)
if (idx !== -1) list.splice(idx, 1)
hideLoadingIfNeeded()
}, 600)
}
//取消订单后删除待付款中该项 function orderStateExp(state: number) {
let list = this.navList[1].orderList; let stateTip = ''
let index = list.findIndex((val) => val.id === item.id); let stateTipColor = lightColor.value
index !== -1 && list.splice(index, 1);
if (this.$store.state.isShowToast) {
uni.hideLoading()
};
}, 600);
},
//订单状态文字和颜色
orderStateExp(state) {
let stateTip = "",
stateTipColor = this.$lightColor;
switch (+state) { switch (+state) {
case 1: case 1:
stateTip = "待付款"; stateTip = '待付款'
break; break
case 2: case 2:
stateTip = "待发货"; stateTip = '待发货'
break; break
case 9: case 9:
stateTip = "订单已关闭"; stateTip = '订单已关闭'
stateTipColor = "#909399"; stateTipColor = '#909399'
break; break
}
//更多自定义 return { stateTip, stateTipColor }
} }
return {
stateTip,
stateTipColor,
};
},
/** function navigateToOrderDetail(sn: string) {
* 跳转到订单详情
*/
navigateToOrderDetail(sn) {
uni.navigateTo({ uni.navigateTo({
url: "./orderDetail?sn=" + sn, url: './orderDetail?sn=' + sn,
}); })
}, }
/** function reasonChange(val: string) {
* 选择取消原因 reason.value = val
*/ }
reasonChange(reason) {
this.reason = reason;
},
/** function submitCancel() {
* 提交取消订单(未付款) cancelOrder(orderSn.value, { reason: reason.value }).then((res) => {
*/
submitCancel() {
cancelOrder(this.orderSn, {
reason: this.reason
}).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({
title: "订单已取消", title: '订单已取消',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
this.initData(this.tabCurrentIndex); initData(tabCurrentIndex.value)
cancelShow.value = false
this.cancelShow = false;
} else { } else {
uni.showToast({ uni.showToast({
title: res.data.message, title: res.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
this.cancelShow = false; cancelShow.value = false
}
})
} }
});
},
/** function onRog(sn: string) {
* 确认收货显示 orderSn.value = sn
*/ rogShow.value = true
onRog(sn) { }
this.orderSn = sn;
this.rogShow = true;
},
/** function confirmRog() {
* 点击确认收货 confirmReceipt(orderSn.value).then((res) => {
*/
confirmRog() {
confirmReceipt(this.orderSn).then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
uni.showToast({ uni.showToast({
title: "已确认收货", title: '已确认收货',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
this.initData(this.tabCurrentIndex); initData(tabCurrentIndex.value)
this.rogShow = false; rogShow.value = false
}
})
} }
});
},
/** function onComment(_sn: string) {
* 评价商品
*/
onComment(sn) {
uni.navigateTo({ uni.navigateTo({
url: "./evaluate/myEvaluate", url: './evaluate/myEvaluate',
}); })
}, }
/** function reBuy(order: any) {
* 重新购买 const goods = order.orderItems?.[0]
*/ if (!goods) return
reBuy(order) {
console.log(order);
return;
uni.navigateTo({ uni.navigateTo({
url: "/pages/product/goods?id=" + order.id + "&goodsId=" + order.goodsId, url: '/pages/product/goods?id=' + goods.id + '&goodsId=' + goods.goodsId,
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -51,7 +51,7 @@
<view class="title">自提点地址:</view> <view class="title">自提点地址:</view>
<view class="value address-line-height">{{ order.storeAddressPath }}</view> <view class="value address-line-height">{{ order.storeAddressPath }}</view>
</view> </view>
<view class="order-info-view" @click="callPhone" > <view class="order-info-view" @click="handleCallPhone" >
<view class="title">联系方式:</view> <view class="title">联系方式:</view>
<view class="value">{{ order.storeAddressMobile }}<u-icon name='phone-fill' ></u-icon></view> <view class="value">{{ order.storeAddressMobile }}<u-icon name='phone-fill' ></u-icon></view>
</view> </view>
@@ -245,287 +245,258 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getExpress, getPackage } from "@/api/trade.js"; import { ref, computed } from 'vue'
import { cancelOrder, confirmReceipt, getOrderDetail } from "@/api/order.js"; import { onLoad } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { getExpress, getPackage } from '@/api/trade.js'
import { cancelOrder, confirmReceipt, getOrderDetail } from '@/api/order.js'
import shares from '@/components/m-share/index'
import { getClearReason } from '@/api/after-sale.js'
import {
unitPrice,
secrecyMobile,
setClipboard,
talkIm,
callPhone,
} from '@/utils/filters.js'
import shares from "@/components/m-share/index"; //分享 const store = useStore()
const lightColor = computed(() => store.getters.lightColor)
const mainColor = computed(() => store.getters.mainColor)
import { getClearReason } from "@/api/after-sale.js"; const orderStatusMap: Record<string, { title: string; value?: string }> = {
UNPAID: { title: '未付款', value: '商品暂未付款' },
PAID: { title: '已付款', value: '买家已付款' },
UNDELIVERED: { title: '待发货', value: '商品等待发货中' },
PARTS_DELIVERED: { title: '部分发货', value: '商品已部分发货。' },
DELIVERED: { title: '已发货', value: '商品已发货,请您耐心等待' },
CANCELLED: { title: '已取消', value: '订单已取消' },
COMPLETED: { title: '已完成', value: '订单已完成,祝您生活愉快' },
STAY_PICKED_UP: { title: '待自提', value: '商品正在等待提取' },
TAKE: { title: '待核验' },
}
export default { const logisticsList = ref<any>('')
components: { const shareFlag = ref(false)
shares, const order = ref<Record<string, any>>({})
}, const cancelShow = ref(false)
data() { const orderSn = ref('')
return { const orderGoodsList = ref<any[]>([])
lightColor: this.$lightColor, const orderDetail = ref<Record<string, any>>({})
logisticsList: "", //物流信息 const sn = ref('')
shareFlag: false, //拼团分享开关 const cancelList = ref<any[]>([])
orderStatusMap: { const rogShow = ref(false)
UNPAID: { const reason = ref('')
title: "未付款", const orderPackage = ref<any>('')
value: "商品暂未付款",
}, function hideLoadingIfNeeded() {
PAID: { if (store.state.isShowToast) uni.hideLoading()
title: "已付款", }
value: "买家已付款",
}, onLoad((options) => {
UNDELIVERED: { const orderSnParam = options?.sn || ''
title: "待发货", sn.value = orderSnParam
value: "商品等待发货中", loadData(orderSnParam)
}, })
PARTS_DELIVERED: {
title: "部分发货", function getOrderPackage() {
value: "商品已部分发货。", getPackage(order.value.sn).then((res) => {
},
DELIVERED: {
title: "已发货",
value: "商品已发货,请您耐心等待",
},
CANCELLED: {
title: "已取消",
value: "订单已取消",
},
COMPLETED: {
title: "已完成",
value: "订单已完成,祝您生活愉快",
},
STAY_PICKED_UP: {
title: "待自提",
value: "商品正在等待提取",
},
TAKE: {
title: "待核验",
},
},
order: {},
cancelShow: false, //取消订单
orderSn: "",
orderGoodsList: "", //订单中商品集合
orderDetail: "", //订单详情信息
sn: "",
cancelList: "",
rogShow: false,
reason: "",
orderPackage:"",
};
},
onLoad(options) {
this.loadData(options.sn);
this.sn = options.sn;
},
methods: {
//获取包裹
async getOrderPackage() {
getPackage(this.order.sn).then(res => {
if (res.data.success) { if (res.data.success) {
this.orderPackage = res.data.result orderPackage.value = res.data.result
} }
}) })
}, }
handleClickDeliver(){
function handleClickDeliver() {
uni.navigateTo({ uni.navigateTo({
url: `/pages/order/deliverDetail?order_sn=${this.order.sn}`, url: `/pages/order/deliverDetail?order_sn=${order.value.sn}`,
}); })
}, }
// 退款状态枚举
refundPriceList(status) { function refundPriceList(status: string) {
switch (status) { switch (status) {
case 'ALL_REFUND': case 'ALL_REFUND':
return "全部退款"; return '全部退款'
case 'PART_REFUND': case 'PART_REFUND':
return "部分退款"; return '部分退款'
case 'NO_REFUND': case 'NO_REFUND':
return "未退款"; return '未退款'
case 'REFUNDING': case 'REFUNDING':
return "退款中"; return '退款中'
default: default:
return ""; return ''
}
} }
},
callPhone(){
this.callPhone(this.order.storeAddressMobile )
},
//联系客服
contact(storeId){
this.talkIm(storeId)
},
goToShopPage(val) {
uni.navigateTo({
url: "/pages/product/shopPage?id=" + val.storeId,
});
},
// 获取物流信息
loadLogistics(sn) {
getExpress(sn).then((res) => {
this.logisticsList = res.data.result;
});
},
// 分享当前拼团信息 function handleCallPhone() {
inviteGroup() { if (order.value.storeAddressMobile) {
this.shareFlag = true; callPhone(order.value.storeAddressMobile)
}, }
// #TODO 这块需要写一下 目前没有拼团的详细信息 }
ByUserMessage(order) {
function contact(storeId: string) {
talkIm(storeId)
}
function goToShopPage(val: any) {
uni.navigateTo({
url: '/pages/product/shopPage?id=' + val.storeId,
})
}
function loadLogistics(orderSnParam: string) {
getExpress(orderSnParam).then((res) => {
logisticsList.value = res.data.result
})
}
function inviteGroup() {
shareFlag.value = true
}
function ByUserMessage(orderItem: any) {
uni.navigateTo({ uni.navigateTo({
url: url:
"/pages/cart/payment/shareOrderGoods?sn=" + '/pages/cart/payment/shareOrderGoods?sn=' +
order.sn + orderItem.sn +
"&sku=" + '&sku=' +
this.orderGoodsList[0].skuId + orderGoodsList.value[0].skuId +
"&goodsId=" + '&goodsId=' +
this.orderGoodsList[0].goodsId, orderGoodsList.value[0].goodsId,
}); })
},
async loadData(sn) {
uni.showLoading({
title: "加载中",
});
getOrderDetail(sn).then((res) => {
const order = res.data.result;
this.order = order.order;
this.orderGoodsList = order.orderItems;
this.orderDetail = res.data.result;
if (this.order.deliveryMethod === 'LOGISTICS') {
this.loadLogistics(sn);
this.getOrderPackage();
} }
if (this.$store.state.isShowToast){ uni.hideLoading() };
});
}, function loadData(orderSnParam: string) {
onReceipt(val) { uni.showLoading({ title: '加载中' })
getOrderDetail(orderSnParam).then((res) => {
const result = res.data.result
order.value = result.order
orderGoodsList.value = result.orderItems
orderDetail.value = result
if (order.value.deliveryMethod === 'LOGISTICS') {
loadLogistics(orderSnParam)
getOrderPackage()
}
hideLoadingIfNeeded()
})
}
function onReceipt(val: any) {
uni.navigateTo({ uni.navigateTo({
url: "/pages/order/invoice/invoiceDetail?id=" + val.id, url: '/pages/order/invoice/invoiceDetail?id=' + val.id,
}); })
}, }
gotoGoodsDetail(sku) {
function gotoGoodsDetail(sku: any) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/product/goods?id=${sku.skuId}&goodsId=${sku.goodsId}`, url: `/pages/product/goods?id=${sku.skuId}&goodsId=${sku.goodsId}`,
}); })
}, }
onCopy(sn) {
setClipboard(sn)
},
//售后按钮 function onCopy(orderSnText: string) {
onAfterSales(sn, sku) { setClipboard(orderSnText)
}
function onAfterSales(orderSnText: string, sku: any) {
uni.navigateTo({ uni.navigateTo({
url: `./afterSales/afterSalesSelect?sn=${sn}&sku=${encodeURIComponent( url: `./afterSales/afterSalesSelect?sn=${orderSnText}&sku=${encodeURIComponent(
JSON.stringify(sku) JSON.stringify(sku)
)}`, )}`,
});
},
// 去支付
toPay(val) {
val.sn
? uni.navigateTo({
url: "/pages/cart/payment/payOrder?order_sn=" + val.sn,
}) })
: false; }
}, //删除订单
deleteOrder(index) {
uni.showLoading({
title: "请稍后",
});
setTimeout(() => {
this.navList[this.tabCurrentIndex].orderList.splice(index, 1);
if (this.$store.state.isShowToast){ uni.hideLoading() };
}, 600);
},
//取消订单
onCancel(sn) {
this.orderSn = sn;
uni.showLoading({ function toPay(val: any) {
title: "加载中", if (val.sn) {
}); uni.navigateTo({
url: '/pages/cart/payment/payOrder?order_sn=' + val.sn,
})
}
}
function onCancel(orderSnText: string) {
orderSn.value = orderSnText
uni.showLoading({ title: '加载中' })
getClearReason().then((res) => { getClearReason().then((res) => {
if (res.data.result.length >= 1) { if (res.data.result.length >= 1) {
this.cancelList = res.data.result; cancelList.value = res.data.result
}
hideLoadingIfNeeded()
})
cancelShow.value = true
} }
if (this.$store.state.isShowToast){ uni.hideLoading() };
});
this.cancelShow = true; function submitCancel() {
}, cancelOrder(orderSn.value, { reason: reason.value }).then((res) => {
//提交取消订单(未付款)
submitCancel() {
cancelOrder(this.orderSn, { reason: this.reason }).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({
title: "已取消", title: '已取消',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
this.cancelShow = false; cancelShow.value = false
setTimeout(() => { setTimeout(() => {
uni.reLaunch({ uni.reLaunch({
url: "/pages/order/myOrder?status=0", url: '/pages/order/myOrder?status=0',
}); })
}, 500); }, 500)
} else { } else {
uni.showToast({ uni.showToast({
title: res.data.message, title: res.data.message,
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
this.cancelShow = false; cancelShow.value = false
}
})
} }
});
},
//确认收货 function onRog(orderSnText: string) {
onRog(sn) { orderSn.value = orderSnText
this.orderSn = sn; rogShow.value = true
this.rogShow = true; }
},
confirmRog() { function confirmRog() {
confirmReceipt(this.orderSn).then((res) => { confirmReceipt(orderSn.value).then((res) => {
if (res.data.success) { if (res.data.success) {
uni.showToast({ uni.showToast({
title: "已确认收货", title: '已确认收货',
duration: 2000, duration: 2000,
icon: "none", icon: 'none',
}); })
this.rogShow = false; rogShow.value = false
this.loadData(this.sn); loadData(sn.value)
}
})
} }
});
},
//评价商品
onComment(sn) {
uni.navigateTo({
url: "./evaluate/myEvaluate",
});
}, //查看物流
onLogistics(order) {
uni.navigateTo({
url:
"/pages/mine/msgTips/packageMsg/logisticsDetail?logi_id=" +
order.logi_id +
"&ship_no=" +
order.ship_no +
"&order_sn=" +
order.sn,
});
},
//选择取消原因 function onComment(_orderSnText: string) {
reasonChange(reason) { uni.navigateTo({
this.reason = reason; url: './evaluate/myEvaluate',
}, })
reBuy(order) { }
function onLogistics(orderItem: any) {
uni.navigateTo({ uni.navigateTo({
url: url:
"/pages/product/goods?id=" + order.id + "&goodsId=" + order.goodsId, '/pages/mine/msgTips/packageMsg/logisticsDetail?logi_id=' +
}); orderItem.logi_id +
}, '&ship_no=' +
}, orderItem.ship_no +
}; '&order_sn=' +
orderItem.sn,
})
}
function reasonChange(val: string) {
reason.value = val
}
function reBuy(orderItem: any) {
uni.navigateTo({
url: '/pages/product/goods?id=' + orderItem.id + '&goodsId=' + orderItem.goodsId,
})
}
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@@ -10,31 +10,23 @@
</view> </view>
</template> </template>
<script> <script setup lang="ts">
import { getArticleDetail } from "@/api/article.js"; import { ref } from 'vue'
export default { import { onLoad } from '@dcloudio/uni-app'
data() { import { getArticleDetail } from '@/api/article.js'
return {
// 用于接收上一级通过路径传输的数据 const articleData = ref('')
routers: "",
// 请求文章接口后存储文章信息 onLoad((val) => {
articleData: "",
};
},
onLoad(val) {
this.routers = val;
getArticleDetail(val.id).then((res) => { getArticleDetail(val.id).then((res) => {
if (res.data.result) { if (res.data.result) {
// 将请求的文章数据赋值 articleData.value = res.data.result.content
this.articleData = res.data.result.content;
} }
// 修改当前NavigationBar(标题头)为文章头部
uni.setNavigationBarTitle({ uni.setNavigationBarTitle({
title: val.title, title: val.title,
}); })
}); })
}, })
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
page { page {

View File

@@ -1,5 +1,5 @@
<template> <template>
<div> <div class="seller-control" :style="themeStyle">
<u-navbar <u-navbar
:border="false" :border="false"
:fixed="true" :fixed="true"
@@ -18,56 +18,71 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { getCompanyDetail } from "@/api/entry"; import { ref, computed, onMounted } from 'vue'
import step1 from "./step1"; import { useStore } from '@/store'
import step2 from "./step2"; import { getCompanyDetail } from '@/api/entry'
import step3 from "./step3"; import step1 from './step1.vue'
export default { import step2 from './step2.vue'
data() { import step3 from './step3.vue'
return { import { getThemeStyle } from '@/utils/theme'
companyData: "",
current: 1, const store = useStore()
};
}, const themeStyle = computed(() => getThemeStyle(store.state.theme))
components: {
step1, const companyData = ref<any>('')
step2, const current = ref(1)
step3,
}, onMounted(() => {
mounted() { init()
this.init(); })
},
methods: { function back() {
back() { if (current.value > 1) {
if (this.current > 1) { current.value--
this.current--; return
return;
} }
uni.navigateBack({ uni.navigateBack({
delta: 1, delta: 1,
fail: () => { fail: () => {
uni.switchTab({ url: "/pages/tabbar/home/index" }); uni.switchTab({ url: '/pages/tabbar/home/index' })
}, },
}); })
},
async init(next) {
const res = await getCompanyDetail();
if (res.data.success) {
this.companyData = res.data.result;
next ? this.current++ : "";
} }
},
next() { async function init(next?: string) {
this.init("next"); const res = await getCompanyDetail()
}, if (res.data.success) {
finished() { companyData.value = res.data.result
if (next) {
current.value++
}
}
}
function next() {
init('next')
}
function finished() {
uni.navigateTo({ uni.navigateTo({
url: "/pages/passport/entry/seller/index", url: '/pages/passport/entry/seller/index',
}); })
}, }
},
};
</script> </script>
<style lang="scss" scoped></style> <style lang="scss">
page {
background: #f7f7f7;
}
</style>
<style lang="scss" scoped>
@import "./entry.scss";
.seller-control {
min-height: 100vh;
background: #f7f7f7;
}
</style>

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