整理框架完成

This commit is contained in:
2024-08-03 01:29:20 +08:00
parent ff46808425
commit d0adbaff13
68 changed files with 6644 additions and 1540 deletions
+1 -5
View File
@@ -33,11 +33,7 @@ export default {
@import '@/uni_modules/uni-scss/index.scss';
/* websoft 样式表 */
@import '@/uni_modules/ws-common/utils/app.scss';
/* iconfont图标库 */
@import url("utils/iconfont.css");
// @import url("./static/css/tailwind.css");
//@import "@/static/tailwind.css";
// @import '@/tailwindcss.scss';
@import "@/static/style/common.scss";
</style>
-41
View File
@@ -1,41 +0,0 @@
<template>
<u-sticky zIndex="99999">
<u-navbar fixed :auto-back="false" :bgColor="bgColor" :status-bar-bg-color="bgColor" placeholder :title="title"
:title-style="{color: 'white'}" auto-back left-icon-color="white" @leftClick="leftClick">
<template slot="left">
<u-icon :name="currentPages.length > 1 ? 'arrow-left' : 'home'" size="20" color="white" v-if="showBack"/>
</template>
</u-navbar>
</u-sticky>
</template>
<script>
import {LINEAR} from "@/config/color";
export default {
name: "HeaderItem",
props: {
title: String,
showBack: {
type: Boolean,
default: true
}
},
data() {
return {
bgColor: LINEAR,
currentPages: []
}
},
methods: {
leftClick() {
console.log(this.currentPages)
if (this.currentPages.length === 1) uni.switchTab({url: '/pages/index/index'})
// else uni.navigateBack()
}
},
mounted() {
this.currentPages = getCurrentPages()
}
}
</script>
+1 -1
View File
@@ -1,5 +1,5 @@
// 租户ID
export const TENANT_ID = 10150;
export const TENANT_ID = '10150';
// appSecret
export const APP_SECRET = 'ffd6eee985af45e4a75098422d1decbb';
// 模块接口地址
+388
View File
@@ -0,0 +1,388 @@
<template>
<layout @done="onLayout">
<uv-empty :show="cart.totalNums === 0" mode="car" class="none"
icon="https://cdn.uviewui.com/uview/empty/car.png"></uv-empty>
<block v-for="(item,index) in cart.shops" :key="index">
<uni-card :border="false" :padding="0">
<template v-slot:title>
<view class="title-bar flex items-center">
<uv-avatar :src="item.shopLogo" size="24"></uv-avatar>
<view class="title ml-1">{{ item.shopName }}</view>
</view>
</template>
<!-- <view class="preferential web-text-secondary">满2件总价9折,还差 1 件</view>-->
<uv-cell-group :customStyle="{backgroundColor: '#ffffff', marginBottom: '20px'}" :border="false">
<uv-cell v-for="(cart,index2) in item.carts" :cellStyle="{padding: '12px 6px'}" :border="false">
<template v-slot:icon>
<uv-avatar v-if="cart.selected" src="https://oss.wsdns.cn/20240723/cc887e4a1cd749ebb5a1cfa2484c01f2.png"
size="16" @click="onSelected(cart)"></uv-avatar>
<uv-avatar v-else src="https://oss.wsdns.cn/20240723/2f9ae761ebb343fcbcaccd7441c88e20.png" size="16"
@click="onSelected(cart)"></uv-avatar>
</template>
<template v-slot:title>
<view class="goods-title flex items-center w-full">
<uv-image
:src="cart.image"
width="80" height="80" radius="5"/>
<view class="goods-info flex w-full flex-col justify-between">
<view class="goods-name">
<uv-text :lines="1" bold :text="cart.goodsName"></uv-text>
<uv-text v-if="cart.spec" class="py-2" type="info" :text="cart.spec" suffixIcon="arrow-down"
:iconStyle="{marginLeft: '8px', fontSize: '10px'}" @click="openCarInfo"></uv-text>
</view>
<view class="goods-price flex justify-between">
<view class="price text-red-500">¥{{ cart.price }}</view>
<view class="tool-btn">
<uv-number-box :min="0" :max="1000" v-model="cart.cartNum"
@change="onAdultNum(cart,index)"></uv-number-box>
</view>
</view>
</view>
</view>
</template>
</uv-cell>
</uv-cell-group>
</uni-card>
</block>
<uv-gap height="100"></uv-gap>
<view class="cart-count w-full fixed flex bg-white justify-between items-center py-3"
:style="'bottom: ' + bottom + 'px;'">
<view class="flex flex-row items-center ml-15" @click="onSelectAll">
<uv-avatar src="https://oss.wsdns.cn/20240723/2f9ae761ebb343fcbcaccd7441c88e20.png"
v-if="cart.totalNums !== cart.selectNums"
size="16"></uv-avatar>
<uv-avatar src="https://oss.wsdns.cn/20240723/cc887e4a1cd749ebb5a1cfa2484c01f2.png" v-else
size="16"></uv-avatar>
<text class="ml-10 text-22">全选</text>
<view class="text-22 flex flex-col text-red-500 ml-15 items-center"
v-if="cart.totalNums === cart.selectNums" @click="onRemove">清空购物车
</view>
</view>
<view class="price-bar flex flex-row items-center">
<view class="total-price flex flex-col mr-20 items-center">
<view class="text-right">
<text class="web-text-heading text-22">合计:</text>
<text class="text-22 web-text-danger">¥</text>
<uv-count-to :startVal="0" decimals="2" duration="100" color="#ff0000" bold
:endVal="cart.totalPrice"></uv-count-to>
</view>
<!-- <text class="text-red-500 text-22 text-right">已优惠¥0.00</text>-->
</view>
<view class="go-buy mr-15">
<uv-button :text="`去结算(${cart?.selectNums ? cart.selectNums : 0})`"
:customStyle="{background: 'linear-gradient(to right, #f5a4a4, #ff0000)',borderRadius: '30px',color: '#ffffff', padding: '0 30px'}"
@click="save"></uv-button>
</view>
</view>
</view>
<uni-popup ref="popup" style="margin-bottom: 200px;">
<uni-card :title="`规格`" extra="关闭" :border="false" :is-shadow="false" :padding="0" @click="closeCarInfo">
<uv-cell-group :customStyle="{backgroundColor: '#ffffff'}" :border="false">
<block v-for="(item,index) in orderInfo" :key="index">
<uv-cell :title="`${item.fieldName} ¥${item.price}`" :label="`${item.dateTime}`"
:cellStyle="{padding: '10px 5px'}">
<template v-slot:right-icon>
<uni-icons type="trash" size="20" color="#f76b4e" @click="remove(item)"></uni-icons>
<text class="web-text-secondary" style="font-size: 24rpx;" @click="remove(item)">移除</text>
</template>
</uv-cell>
</block>
</uv-cell-group>
</uni-card>
</uni-popup>
</layout>
</template>
<script>
import * as CartApi from '@/api/shop/cart';
import * as OrderApi from '@/api/shop/order'
import {
getWeek
} from '@/utils/common';
import {
storeToRefs
} from 'pinia';
import {useMpStore} from "@/store/modules/mp";
import Layout from "@/components/layout.vue";
import UniCard from "@/uni_modules/uni-card/components/uni-card/uni-card.vue";
import UvAvatar from "@/uni_modules/uv-avatar/components/uv-avatar/uv-avatar.vue";
import UvCell from "@/uni_modules/uv-cell/components/uv-cell/uv-cell.vue";
import UvImage from "@/uni_modules/uv-image/components/uv-image/uv-image.vue";
import UvButton from "@/uni_modules/uv-button/components/uv-button/uv-button.vue";
import UvGap from "@/uni_modules/uv-gap/components/uv-gap/uv-gap.vue";
import {useCartStore} from "@/store/modules/cart";
const mpStore = useMpStore();
const cartStore = useCartStore();
const {
isNew
} = storeToRefs(cartStore)
export default {
components: {UvGap, UvButton, UvImage, UvCell, UvAvatar, UniCard, Layout},
data() {
return {
// 购物车搜索条件
where: {
keywords: undefined,
type: 0,
limit: 100
},
index: 0,
cart: {
totalNums: 0,
selectNums: undefined,
totalPrice: undefined
},
shops: [],
tabBar: null,
safeAreaInsets: {},
bottom: 0,
isRefresh: false,
isLogin: false,
userId: 0,
config: {},
isNew,
canReset: false,
loadMore: 'more',
logo: '',
items: ['全部订单', '未支付', '已支付', '已完成', '押金'],
orderList: [],
styles: [{
value: 'button',
text: '按钮',
checked: true
},
{
value: 'text',
text: '文字'
}
],
colors: ['#333333', '#4cd964', '#dd524d'],
current: 0,
colorIndex: 0,
activeColor: '#108001',
styleType: 'text',
getWeek,
// 骨架屏
hideTools: true
}
},
onLoad() {
},
onShow() {
this.reload();
},
// 触底函数
onReachBottom() {
const app = this
const {
where
} = this
if (app.canReset) {
app.where.page = ++where.page;
app.reload()
}
},
methods: {
async reload() {
const app = this
const {where} = this
// 获取系统信息
uni.getSystemInfo({
success(data) {
if (data) {
app.safeAreaInsets = data.safeAreaInsets;
}
}
});
// #ifdef H5
app.bottom = 0;
// #endif
// 获取小程序信息包
const info = await mpStore.fetchMpInfo();
// 配置信息
app.config = info.config
// 登录状态
if (uni.getStorageSync('user_id') && uni.getStorageSync('access_token')) {
app.isLogin = true;
}
// uni.showLoading({
// title: '数据读取中.'
// })
app.loadMore = 'loading'
// 加载购物车数据
CartApi.listCart(where).then(data => {
if(data){
app.cart = data
}
}).finally(() => {
app.loadMore = 'more'
uni.hideLoading()
})
},
onLayout({mpMenus}) {
this.mpMenus = mpMenus;
},
openUrl(url) {
uni.navigateTo({
url
})
},
onDone(index) {
this.index = index
const {path} = this.tabBar[index]
uni.switchTab({url: path})
},
toPay(orderId) {
uni.navigateTo({
url: '/package/booking/confirm?id=' + orderId
})
},
closeOrder(item) {
uni.showModal({
title: '确定取消此订单?',
success(o) {
if (o.confirm) {
OrderApi.updateOrder({
orderStatus: 2,
orderId: item.orderId
}).then(msg => {
uni.showToast({
title: msg,
icon: 'none'
})
item.orderStatus = 2;
}).catch(() => {
uni.showToast({
title: '请检查您的网络.',
icon: 'none'
})
uni.hideLoading()
})
}
}
});
},
// 弹出登录提示框
async openLogin() {
// 当前租户信息
const info = await mpStore.fetchMpInfo();
// 配置信息
this.config = info.config
this.userId = uni.getStorageSync('user_id');
if (!this.userId) {
this.$refs.login.open('bottom')
return false;
}
},
// 申请开票
onInvoice(id) {
uni.navigateTo({
url: '/package/user/invoice?id=' + id
})
},
showInvoice(id) {
uni.navigateTo({
url: `/package/user/invoice-show?id=${id}`
})
},
openCarInfo() {
this.$refs.popup.open('bottom')
},
closeCarInfo() {
this.$refs.popup.close()
},
onAdultNum(cart) {
const app = this
CartApi.updateCart(cart).then(data => {
if (cart.cartNum < 1) {
uni.showModal({
title: '确定要删除该商品吗?',
success(o) {
if (o.confirm) {
CartApi.removeCart(cart.id)
app.shops = []
app.reload()
}
}
});
}
this.reload()
})
},
onShopSelected(merchantId) {
CartApi.updateCartByMerchantId(merchantId)
},
onSelected(cart) {
cart.selected = !cart.selected
CartApi.updateCart(cart).then(data => {
this.reload()
})
},
onSelectAll() {
const {selectNums, totalNums} = this.cart
CartApi.onSelectAll(!(selectNums === totalNums)).then(res => {
this.reload()
});
},
onRemove() {
const {shops} = this.cart
CartApi.removeBatchCart(shops[0]?.carts?.map(d => d.id)).then(res => {
uni.showToast({
title: '删除成功',
icon: 'success',
})
this.shops = []
// 更新购物车角标
uni.removeTabBarBadge({
index: 2
})
});
},
save() {
// if (this.shops.length === 0) {
// return false
// }
uni.redirectTo({url: `/package/goods/checkout?selected=true&isNew=false`})
}
}
}
</script>
<style lang="scss">
.admin-tools {
width: 700rpx;
margin: 20rpx auto;
padding: 0 16rpx;
font-size: 24rpx;
}
.title-bar {
padding: 20rpx 10rpx;
}
.preferential {
margin-left: 52rpx;
}
.goods-title {
display: flex;
margin-left: 8rpx;
.goods-info {
margin-left: 10rpx;
}
}
</style>
+301
View File
@@ -0,0 +1,301 @@
<template>
<view class="waterfall">
<!-- 推荐美食 -->
<ws-food :config="config" :foods="foods" />
</view>
</template>
<script>
import * as GoodsApi from '@/api/shop/goods';
import * as GoodsCategoryApi from '@/api/shop/goodsCategory';
import {
guid
} from '@/uni_modules/uv-ui-tools/libs/function/index.js'
import {
useTenantStore
} from '@/store/modules/tenant';
const tenantStore = useTenantStore();
export default {
data() {
return {
goods: [],
foods: [],
config: {},
industryName: '',
goodsList: [], // 瀑布流全部数据
list1: [], // 瀑布流第一列数据
list2: [], // 瀑布流第二列数据
goodsCategoryList: [], // 商品分类
leftGap: 10,
rightGap: 10,
columnGap: 10,
// 小程序导航图标
navigation: [],
// 骨架屏
hideTools: true,
// 商品分类
categoryId: undefined
}
},
computed: {
imageStyle(item) {
return item => {
const v = uni.upx2px(750) - this.leftGap - this.rightGap - this.columnGap;
const w = v / 2;
const rate = w / item.w;
const h = rate * item.h;
return {
width: w + 'px',
height: h + 'px'
}
}
}
},
async onLoad({name}) {
this.industryName = name
// 获取服务租户信息包
const info = await tenantStore.fetchTenantInfo();
// 请求数据
this.reload()
},
methods: {
async reload() {
const app = this
// 获取服务租户信息包
const info = await tenantStore.fetchTenantInfo();
app.config = info.config
// 登录状态
if (uni.getStorageSync('user_id') && uni.getStorageSync('access_token')) {
app.isLogin = true;
}
// 请求数据
Promise.all([app.pageGoods(),app.getGoodsCategory(), app.getFoods()])
.then((res) => {
app.goodsList = res[0];
app.goodsCategoryList = res[1];
app.hideTools = false
console.log(res)
if(res[2]){
app.foods = res[2]?.list;
}
})
},
getFoods(){
const { industryName } = this
return new Promise((resolve, reject) => {
GoodsApi.pageGoods({type: 1, industryName})
.then((result) => {
resolve(result);
})
.catch(reject);
});
},
pageGoods() {
const app = this
const { categoryId } = this
return new Promise((resolve, reject) => {
GoodsApi.pageGoods({parentId: categoryId})
.then(result => {
resolve(result.list)
})
.catch(reject)
})
},
getGoodsCategory(){
const app = this
return new Promise((resolve, reject) => {
GoodsCategoryApi.pageGoodsCategory({parentId: 0})
.then(result => {
resolve(result.list)
})
.catch(reject)
})
},
navTo(item) {
uni.navigateTo({
url: '/package/goods/detail?id=' + item.goodsId
})
},
onCategory(item){
this.categoryId = item.categoryId
this.goodsList = []
this.list1 = []
this.list2 = []
this.reload()
},
// 这点非常重要:e.name在这里返回是list1或list2,要手动将数据追加到相应列
changeList(e) {
console.log('e: ', e);
this[e.name].push(e.value);
},
// 模拟的后端数据
getData() {
return new Promise((resolve) => {
const imgs = [{
url: 'https://via.placeholder.com/100x110.png/3c9cff/fff',
width: 100,
height: 110
},
{
url: 'https://via.placeholder.com/200x220.png/f9ae3d/fff',
width: 200,
height: 220
},
{
url: 'https://via.placeholder.com/300x340.png/5ac725/fff',
width: 300,
height: 340
},
{
url: 'https://via.placeholder.com/400x400.png/f56c6c/fff',
width: 400,
height: 400
},
{
url: 'https://via.placeholder.com/500x510.png/909399/fff',
width: 500,
height: 510
},
{
url: 'https://via.placeholder.com/600x606.png/3c9cff/fff',
width: 600,
height: 606
},
{
url: 'https://via.placeholder.com/310x422.png/f1a532/fff',
width: 310,
height: 422
},
{
url: 'https://via.placeholder.com/320x430.png/3c9cff/fff',
width: 320,
height: 430
},
{
url: 'https://via.placeholder.com/330x424.png/f9ae3d/fff',
width: 330,
height: 424
},
{
url: 'https://via.placeholder.com/340x435.png/5ac725/fff',
width: 340,
height: 435
},
{
url: 'https://via.placeholder.com/350x440.png/f56c6c/fff',
width: 350,
height: 440
},
{
url: 'https://via.placeholder.com/380x470.png/909399/fff',
width: 380,
height: 470
}
];
let list = [];
const doFn = (i) => {
const randomIndex = Math.floor(Math.random() * 10);
return {
id: guid(),
allowEdit: i == 0,
image: imgs[randomIndex].url,
w: imgs[randomIndex].width,
h: imgs[randomIndex].height,
title: i % 2 == 0 ? `(${this.list.length + i + 1})体验uv-ui框架` :
`(${this.list.length + i +1})uv-ui支持多平台`,
desc: i % 2 == 0 ? `(${this.list.length + i + 1})欢迎使用uv-ui,uni-app生态专用的UI框架` :
`(${this.list.length + i})开发者编写一套代码, 可发布到iOS、Android、H5、以及各种小程序`
}
};
// 模拟异步
setTimeout(() => {
for (let i = 0; i < 20; i++) {
list.push(doFn(i));
}
resolve({
data: list
});
}, 200)
})
}
}
}
</script>
<style>
page {
/* background: url('https://oss.wsdns.cn/20240505/eaa18a0271fa42aa8395bd5eb874808a.png') no-repeat; */
background-size: 100%;
background-repeat: no-repeat;
background-color: #f0f2f5;
width: 750rpx;
overflow-x: hidden;
}
</style>
<style scoped lang="scss">
$show-lines: 1;
@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
.waterfall-item {
overflow: hidden;
margin-top: 10px;
border-radius: 6px;
&__image {
background-color: #fff;
}
}
.waterfall-item__ft {
padding: 20rpx;
background: #fff;
&__title {
margin-bottom: 10rpx;
line-height: 48rpx;
font-weight: 700;
.value {
font-size: 32rpx;
color: #303133;
}
}
&__desc .value {
font-size: 28rpx;
color: #606266;
}
&__btn {
padding: 10px 0;
}
}
.user-oreder {
width: 720rpx;
margin: 20rpx auto 8rpx auto;
padding: 28rpx 0;
border-radius: 16rpx;
background: #fff;
.web-cell-content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.web-text-center {
text-align: center;
}
}
</style>
File diff suppressed because it is too large Load Diff
+539 -326
View File
@@ -1,357 +1,570 @@
<template>
<view class="">
<view class="goods-info">
<uv-swiper :list="photo" indicator indicatorMode="line" circular height="750rpx" radius="0"></uv-swiper>
</view>
<!-- <view class="merchant-name">{{ form.merchantName }}</view> -->
<uni-card :border="false" :is-shadow="false" :padding="0">
<uv-cell-group :customStyle="{backgroundColor: '#ffffff'}" :border="false">
<uv-cell :cellStyle="{padding: '10px 5px'}">
<template v-slot:title>
<view class="pirce-bar" style="display: flex;">
<view class="web-text-danger">¥</view>
<view class="web-text-danger" style="font-size: 40rpx;">{{ form.price }}</view>
</view>
</template>
<template v-slot:right-icon>
<text class="web-text-secondary" style="text-decoration: line-through">划线价¥{{ form.price*2 }}</text>
</template>
</uv-cell>
<uv-cell :title="form.goodsName" label="商品名称" :cellStyle="{padding: '10px 5px'}">
</uv-cell>
<uv-cell title="选择款式" :label="`100zz【藏青色】、100zz【古红色】`" isLink
:cellStyle="{padding: '10px 5px'}">
<template v-slot:right-icon>
<!-- <uv-icon size="50rpx" name="map-fill" color="#5ac725" style="color: #ff0000;"></uv-icon> -->
</template>
</uv-cell>
<uv-cell title="参数" :label="form.goodsName" :cellStyle="{padding: '10px 5px'}">
</uv-cell>
<uv-cell title="客服电话" label="0771-8888888" :border="false" :cellStyle="{padding: '10px 5px'}"
@click="callPhone('0771-8888888')">
<view class="">
<view class="goods-info">
<uv-swiper :list="photo" indicator indicatorMode="line" circular height="750rpx" radius="0"></uv-swiper>
</view>
<!-- <view class="merchant-name">{{ form.merchantName }}</view> -->
<uni-card :border="false" :is-shadow="false" :padding="0">
<uv-cell-group :customStyle="{backgroundColor: '#ffffff'}" :border="false">
<uv-cell :cellStyle="{padding: '10px 5px'}">
<template v-slot:title>
<view class="pirce-bar" style="display: flex;">
<view class="web-text-danger">¥</view>
<view class="web-text-danger" style="font-size: 40rpx;">{{ form.price }}</view>
</view>
</template>
<template v-slot:right-icon>
<text class="web-text-secondary" style="text-decoration: line-through">划线价¥{{ form.price * 2 }}</text>
</template>
</uv-cell>
<uv-cell :title="form.goodsName" label="商品名称" :cellStyle="{padding: '10px 5px'}">
</uv-cell>
<!-- <uv-cell title="选择款式" :label="`100zz【藏青色】、100zz【古红色】`" isLink-->
<!-- :cellStyle="{padding: '10px 5px'}">-->
<!-- </uv-cell>-->
<uv-cell title="参数" :label="form.goodsName" :cellStyle="{padding: '10px 5px'}">
</uv-cell>
<uv-cell title="客服电话" label="0771-8888888" :border="false" :cellStyle="{padding: '10px 5px'}"
@click="callPhone('0771-8888888')">
</uv-cell>
</uv-cell-group>
</uni-card>
</uv-cell>
</uv-cell-group>
</uni-card>
<uni-card title="商品详情" :is-shadow="false" :border="false" :padding="0">
<view class="web-text-heading booking-content">
<view v-html="form.content"></view>
</view>
</uni-card>
<uni-card title="商品详情" :is-shadow="false" :border="false" :padding="0">
<view class="web-text-heading booking-content">
<view v-html="form.content"></view>
</view>
</uni-card>
<view class="xieyi web-cell web-text-secondary web-cell-align-top">
<view class="web-cell web-cell-content web-cell-align-top">
<uni-icons type="circle" size="20" color="#a4a5a7" v-if="!disabled" @click="onDisabled"></uni-icons>
<uni-icons type="checkbox" size="20" color="#11a954" v-else @click="onDisabled"></uni-icons>
<view class="text" @click="onDisabled">
<text>我已阅读并同意</text>
<text class="link"
@click.stop="navTo('/package/article/detail?articleId=503')">《购买协议》</text>
</view>
</view>
</view>
<!-- {{ goodsList }}-->
<uv-gap height="50"></uv-gap>
<view class="save-btn">
<uv-button
:customStyle="{background: 'linear-gradient(to right, #ccff66, #008e04)',borderRadius: '30px',color: '#ffffff'}"
text="立即购买" @click="save"></uv-button>
</view>
<!-- <view class="goods-nav-btn">
<uni-goods-nav :fill="true" :options="options" :button-group="buttonGroup" @click="onClick"
@buttonClick="buttonClick" />
</view> -->
<view class="xieyi web-cell web-text-secondary web-cell-align-top">
<view class="web-cell web-cell-content web-cell-align-top">
<uv-avatar src="https://oss.wsdns.cn/20240723/2f9ae761ebb343fcbcaccd7441c88e20.png" size="20" v-if="!disabled"
@click="onDisabled"></uv-avatar>
<uv-avatar src="https://oss.wsdns.cn/20240723/cc887e4a1cd749ebb5a1cfa2484c01f2.png" size="20" v-else
@click="onDisabled"></uv-avatar>
<!-- <uni-icons type="circle" size="20" color="#a4a5a7" v-if="!disabled" @click="onDisabled"></uni-icons>-->
<!-- <uni-icons type="checkbox" size="20" color="#11a954" v-else @click="onDisabled"></uni-icons>-->
<view class="text" @click="onDisabled">
<text>我已阅读并同意</text>
<text class="link"
@click.stop="navTo('/package/article/detail?articleId=503')">《购买协议》
</text>
</view>
</view>
</view>
<uv-gap height="50"></uv-gap>
<!-- <view class="save-btn">-->
<!-- <uv-button-->
<!-- :customStyle="{background: 'linear-gradient(to right, #f5a4a4, #ff0000)',borderRadius: '30px',color: '#ff6e0c'}"-->
<!-- text="立即购买" @click="save"></uv-button>-->
<!-- </view>-->
<view class="goods-nav-btn">
<uni-goods-nav :fill="true" :options="options" :button-group="buttonGroup" @click="onClick"
@buttonClick="save"/>
<uv-gap :height="safeAreaInsets.bottom"/>
</view>
</view>
<!-- 活动订场弹窗 -->
<uni-popup ref="popup" type="center">
<view class="popup-booking-tel">
<text class="title">场馆热线</text>
<text class="desc">主体育场、足球训练场:0771-4953380</text>
<text class="desc">体育馆、综合训练馆、网球馆:0771-4953380</text>
<text class="desc">游泳跳水馆:0771-4736008</text>
</view>
<text class="title">参观接待</text>
<text class="desc">预约电话:0771-4736955</text>
<text class="desc">传真号码:0771-4736955</text>
<text class="title">大型活动订场</text>
<text class="desc">预约电话:0771-4736970、0771-4736994</text>
<!-- 选择规格弹窗 -->
<uni-popup ref="specForm" type="center" border-radius="10px 10px 0 0">
<uni-card :title="form.goodsName" :border="false" :is-shadow="false" :padding="0">
<view class="spec-card" style="width: 660rpx;">
<block v-if="form.goodsSpecValue">
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff' }" :border="false">
<block v-for="(item, index) in form.goodsSpecValue" :key="index">
<uv-cell :title="item.value" :cellStyle="{ padding: '10px 0' }" :label="item.address">
<template v-slot:label>
<view class="tags flex mt-10">
<view class="tag mr-15" v-for="value in item.detail">
<uv-tags :text="value" v-if="onPlain(value)" plain border-color="#eeeeee" color="#808080"
@click="onTag(value,index)"></uv-tags>
<uv-tags :text="value" v-else plain color="#ff0000" border-color="#ff0000"
@click="onTag(value,index)"></uv-tags>
</view>
</view>
</template>
</uv-cell>
</block>
<uv-cell :cellStyle="{ padding: '40px 0' }">
<text class="title">威拓普健身馆</text>
<text class="desc">联系电话:0771-5588699</text>
</view>
<view class="web-cell popup-close" @click="closeBookingTel">
<uv-icon name="close-circle" color="#ffffff" size="30"></uv-icon>
</view>
</uni-popup>
<!-- 登录组件 -->
<ws-login ref="login" :logo="logo" @done="reload" />
</uv-cell>
<uv-cell :cellStyle="{ padding: '10px 0', backgroundColor: '#f3f3f3' }">
<template v-slot:label>
<view class="web-text-secondary">
已选规格:{{ skuText }}
</view>
</template>
</uv-cell>
</uv-cell-group>
<view class="flex m-20 justify-between items-center">
<view class="total-price web-text-heading">
总计{{ isNew }}
<text class="text-red-500" style="font-weight: 500; font-size: 36rpx">¥{{ form.price }}</text>
</view>
<view class="add-cart">
<uv-button type="warning" class="add-address" iconSize="16" :customStyle="{ borderRadius: '6px', padding: '5px 20px',
backgroundColor: '#ff0000', color: '#ffffff', fontWeight: 'bold' }" :text="isNew ? '立即购买' : '加入购物车'"
@click="gotoBuy"></uv-button>
</view>
</view>
</block>
</view>
</uni-card>
</uni-popup>
<!-- 活动订场弹窗 -->
<!-- <uni-popup ref="popup" type="center">-->
<!-- <view class="popup-booking-tel">-->
<!-- <text class="title">场馆热线</text>-->
<!-- <text class="desc">主体育场、足球训练场:0771-4953380</text>-->
<!-- <text class="desc">体育馆、综合训练馆、网球馆:0771-4953380</text>-->
<!-- <text class="desc">游泳跳水馆:0771-4736008</text>-->
<!-- <text class="title">参观接待</text>-->
<!-- <text class="desc">预约电话:0771-4736955</text>-->
<!-- <text class="desc">传真号码:0771-4736955</text>-->
<!-- <text class="title">大型活动订场</text>-->
<!-- <text class="desc">预约电话:0771-4736970、0771-4736994</text>-->
<!-- <text class="title">威拓普健身馆</text>-->
<!-- <text class="desc">联系电话:0771-5588699</text>-->
<!-- </view>-->
<!-- <view class="web-cell popup-close" @click="closeBookingTel">-->
<!-- <uv-icon name="close-circle" color="#ffffff" size="30"></uv-icon>-->
<!-- </view>-->
<!-- </uni-popup>-->
<!-- 登录组件 -->
<ws-login ref="login" @done="reload"/>
</template>
<script>
import {
storeToRefs
} from 'pinia';
import * as GoodsApi from '@/api/shop/goods';
import {
useCarStore
} from '@/store/modules/car';
const carStore = useCarStore();
const {
goodsList,
orderInfo,
totalPrice,
carNum,
merchantId,
merchantName,
merchantCode,
type,
dateTime
} = storeToRefs(carStore)
import {
storeToRefs
} from 'pinia';
import * as GoodsApi from '@/api/shop/goods';
import * as CartApi from '@/api/shop/cart';
import {
useCartStore
} from '@/store/modules/cart';
import UvAvatar from "@/uni_modules/uv-avatar/components/uv-avatar/uv-avatar.vue";
import UvGap from "@/uni_modules/uv-gap/components/uv-gap/uv-gap.vue";
import UvButton from "@/uni_modules/uv-button/components/uv-button/uv-button.vue";
export default {
data() {
return {
id: 0,
form: {},
// 场馆相册
photo: [],
isLogin: false,
disabled: true,
orderInfo,
goodsList,
totalPrice,
carNum,
merchantId,
merchantName,
merchantCode,
type,
dateTime,
options: [{
icon: 'headphones',
text: '客服'
}, {
icon: 'cart',
text: '购物车',
info: 2
}],
buttonGroup: [
{
text: '立即购买',
backgroundColor: 'linear-gradient(90deg, #ccff66, #008e04)',
color: '#fff'
}
],
customButtonGroup1: [{
text: '立即购买',
backgroundColor: 'linear-gradient(90deg, #ccff66, #008e04)',
color: '#fff'
}]
}
},
onLoad(option) {
this.id = option.id
this.reload();
},
onShow() {
// 登录状态
if (uni.getStorageSync('user_id') && uni.getStorageSync('access_token')) {
this.isLogin = true;
}
},
methods: {
async reload() {
const app = this
const cartStore = useCartStore();
const {
goodsList,
orderInfo,
totalPrice,
carNum,
merchantId,
merchantName,
merchantCode,
type,
dateTime,
isNew,
isLogin
} = storeToRefs(cartStore)
// 请求数据
Promise.all([app.getGoods()]).then(data => {
console.log('data: ', data);
const form = data[0]
app.form = form;
carStore.merchantId = form.merchantId
carStore.merchantName = form.merchantName
carStore.merchantCode = form.merchantCode
export default {
components: {UvButton, UvGap, UvAvatar},
data() {
return {
id: 0,
form: {},
// 场馆相册
photo: [],
cart: {},
safeAreaInsets: {},
isLogin: false,
disabled: true,
specForm: false,
sku: [],
skuText: '',
orderInfo,
goodsList,
totalPrice,
carNum,
merchantId,
merchantName,
merchantCode,
type,
isNew,
dateTime,
options: [{
icon: 'server-fill',
text: '客服'
}, {
icon: 'bag',
text: '购物车',
info: 0
}],
buttonGroup: [
{
text: '加入购物车',
backgroundColor: 'linear-gradient(to right, #ffc940, #ff6e0c)',
color: '#fff'
}, {
text: '立即购买',
backgroundColor: 'linear-gradient(90deg, #ff0000, #ff6767)',
color: '#fff'
}
],
customButtonGroup1: [{
text: '立即购买',
backgroundColor: 'linear-gradient(90deg, #ccff66, #008e04)',
color: '#fff'
}]
}
},
onLoad(option) {
this.id = option.id
this.reload();
},
onShow() {
// 登录状态
if (uni.getStorageSync('user_id') && uni.getStorageSync('access_token')) {
this.isLogin = true;
}
},
methods: {
async reload() {
const app = this
// 获取系统信息
uni.getSystemInfo({
success(data) {
if (data) {
app.safeAreaInsets = data.safeAreaInsets;
app.statusBarHeight = data.statusBarHeight + 50;
}
}
});
// 修改标题
uni.setNavigationBarTitle({
title: form.goodsName
})
// 加载场馆相册
if (form.files) {
app.photo = JSON.parse(form.files)
}
})
},
getGoods() {
return new Promise((resolve, reject) => {
GoodsApi.getGoods(this.id).then(result => {
resolve(result)
}).catch(reject)
})
},
onDisabled() {
this.disabled = !this.disabled;
},
navTo(url) {
uni.navigateTo({
url
})
},
openBookingTel() {
// 通过组件定义的ref调用uni-popup方法 ,如果传入参数 ,type 属性将失效 ,仅支持 ['top','left','bottom','right','center']
this.$refs.popup.open('center')
},
closeBookingTel() {
this.$refs.popup.close()
},
callPhone(phone) {
uni.makePhoneCall({
phoneNumber: phone
});
},
onMap() {
uni.getLocation({
type: 'gcj02', //返回可以用于uni.openLocation的经纬度
success: function(res) {
console.log('返回可以用于uni.openLocation的经纬度: ', res);
const latitude = this.merchant.latitude;
const longitude = this.merchant.longitude;
uni.openLocation({
latitude: latitude,
longitude: longitude,
success: function() {
console.log('success');
}
});
}
});
},
save() {
if (!this.disabled) {
uni.showToast({
title: '请先阅读并同意订票协议',
icon: 'none'
})
return false
}
const app = this
const { form } = this
carStore.totalPrice = form.price
app.goodsList = []
form.image = JSON.parse(form.image)[0]
app.goodsList.push(form)
carStore.goodsList = app.goodsList
// 跳转页面
uni.navigateTo({
url: '/package/goods/checkout?goodsId=' + this.id
})
}
}
}
// 请求数据
Promise.all([app.getGoods(), app.listCart()]).then(data => {
const form = data[0]
form.content = this.formatRichText(form.content)
app.form = form;
cartStore.merchantId = form.merchantId
cartStore.merchantName = form.merchantName
cartStore.merchantCode = form.merchantCode
// 修改标题
uni.setNavigationBarTitle({
title: form.goodsName
})
// 加载场馆相册
if (form.files) {
app.photo = JSON.parse(form.files)
}
// 购物车信息
app.cart = data[1]
console.log(app.cart.totalNums)
// 更新购物车角标
if(app.cart?.totalNums){
app.options[1].info = app.cart.totalNums
}
})
},
getGoods() {
return new Promise((resolve, reject) => {
GoodsApi.getGoods(this.id).then(result => {
resolve(result)
}).catch(reject)
})
},
listCart() {
return new Promise((resolve, reject) => {
CartApi.listCart().then(result => {
resolve(result)
}).catch(reject)
})
},
onDisabled() {
this.disabled = !this.disabled;
},
navTo(url) {
uni.navigateTo({
url
})
},
onPlain(text) {
const index = this.sku.findIndex(d => d === text)
return index < 0;
},
onTag(text, index) {
const app = this
const parent = this.sku.findIndex(d => d === text)
if (parent < 0) {
app.sku.push(text)
app.skuText = app.sku.join('、')
}
},
// openBookingTel() {
// // 通过组件定义的ref调用uni-popup方法 ,如果传入参数 ,type 属性将失效 ,仅支持 ['top','left','bottom','right','center']
// this.$refs.popup.open('center')
// },
// closeBookingTel() {
// this.$refs.popup.close()
// },
callPhone(phone) {
uni.makePhoneCall({
phoneNumber: phone
});
},
onMap() {
uni.getLocation({
type: 'gcj02', //返回可以用于uni.openLocation的经纬度
success: function (res) {
console.log('返回可以用于uni.openLocation的经纬度: ', res);
const latitude = this.merchant.latitude;
const longitude = this.merchant.longitude;
uni.openLocation({
latitude: latitude,
longitude: longitude,
success: function () {
console.log('success');
}
});
}
});
},
formatRichText(html) {
let newContent = html.replace(/<img[^>]*>/gi, function (match, capture) {
match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '');
match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '');
match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '');
return match;
});
newContent = newContent.replace(/style="[^"]+"/gi, function (match, capture) {
match = match.replace(/width:[^;]+;/gi, 'max-width:100%;').replace(/width:[^;]+;/gi,
'max-width:100%;');
return match;
});
newContent = newContent.replace(/<br[^>]*\/>/gi, '');
newContent = newContent.replace(/\<img/gi,
'<img style="max-width:100%;height:auto;display:inline-block;margin:10rpx auto;"');
return newContent;
},
onClick({index, content}) {
console.log(index, content)
// 客服按钮
if (index === 0) {
uni.contact({
type: 'updateCustomerService',
success: function () {
console.log('客服会话打开成功');
},
fail: function (err) {
console.error('客服会话打开失败:', err);
}
});
}
// 前往购物车
if (index === 1) {
uni.navigateTo({url: `/package/cart/index`})
}
},
save({index, content}) {
const app = this
const {form} = this
if (!app.isLogin && !cartStore.isLogin) {
this.$refs.login.open('bottom');
return false;
}
if (!this.disabled) {
uni.showToast({
title: '请先阅读并同意订票协议',
icon: 'none'
})
return false
}
// 加入购物车
if (index === 0) {
form.cartNum = 1;
form.isNew = false;
cartStore.isNew = false;
// 单规格
if (form.specs === 0) {
CartApi.addCart(form).then(data => {
app.reload()
uni.showToast({
title: '添加成功',
icon: 'success'
});
}).catch(res => {
uni.showToast({
title: res.message,
icon: 'none'
});
})
return false
}
// 多规格
if (form.specs === 1) {
this.$refs.specForm.open('center');
return false;
}
return false;
}
// 立即购买
if (index === 1) {
form.cartNum = 1;
form.isNew = true;
cartStore.isNew = true;
// 多规格
if (form.specs === 1) {
form.spec = app.skuText;
this.$refs.specForm.open('center');
return false;
}
CartApi.addCart(form).then(cartId => {
// 跳转页面
uni.navigateTo({
url: `/package/goods/checkout?id=${cartId}`
})
})
}
},
gotoBuy() {
const app = this
this.disabled = !this.disabled;
CartApi.addCart({
...app.form,
spec: app.skuText,
cartNum: 1,
isNew: app.isNew
}).then(data => {
app.options[1].info = data.totalNums
if (app.isNew) {
// CartApi.removeCart(data.id)
// 跳转页面
uni.navigateTo({
url: `/package/goods/checkout?id=${data.id}`
})
}else {
}
})
this.$refs.specForm.close();
},
}
}
</script>
<style>
page {
background-size: 100%;
background-repeat: no-repeat;
background-color: #f0f2f5;
width: 750rpx;
overflow-x: hidden;
}
page {
background-size: 100%;
background-repeat: no-repeat;
background-color: #f0f2f5;
//color: #ff6e0c;
width: 750rpx;
overflow-x: hidden;
}
img {
max-width: 100%;
}
</style>
<style lang="scss" scoped>
.container {}
.container {
}
.goods-info {
width: 750rpx;
height: 750rpx;
background-color: #fff;
}
.goods-info {
width: 750rpx;
height: 750rpx;
background-color: #fff;
}
.merchant-name {
padding: 30rpx;
font-weight: 500;
font-size: 42rpx;
background-color: #ffffff;
}
.merchant-name {
padding: 30rpx;
font-weight: 500;
font-size: 42rpx;
background-color: #ffffff;
}
.save-btn {
width: 700rpx;
left: 25rpx;
height: 80rpx;
position: fixed;
bottom: 30rpx;
}
.save-btn {
width: 700rpx;
left: 25rpx;
height: 80rpx;
position: fixed;
bottom: 30rpx;
}
.booking-tel {
position: fixed;
z-index: 1;
top: 270px;
right: 0;
width: 80px;
height: 38px;
border-radius: 50px 0 0 50px;
background: linear-gradient(to right, #ccff66, #008e04);
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
font-size: 13px;
}
.booking-tel {
position: fixed;
z-index: 1;
top: 270px;
right: 0;
width: 80px;
height: 38px;
border-radius: 50px 0 0 50px;
background: linear-gradient(to right, #f5a4a4, #008e04);
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
font-size: 13px;
}
.popup-booking-tel {
background-color: #ffffff;
width: 560rpx;
min-height: 400rpx;
border-radius: 20rpx;
margin: auto;
padding: 20px;
z-index: 9999;
display: flex;
flex-direction: column;
.popup-booking-tel {
background-color: #ffffff;
width: 560rpx;
min-height: 400rpx;
border-radius: 20rpx;
margin: auto;
padding: 20px;
z-index: 9999;
display: flex;
flex-direction: column;
.title {
font-weight: bold;
font-size: 38rpx;
text-align: center;
padding: 10px 0;
}
.title {
font-weight: bold;
font-size: 38rpx;
text-align: center;
padding: 10px 0;
}
.desc {
line-height: 2rem;
}
}
.desc {
line-height: 2rem;
}
}
.popup-close {
display: flex;
margin-top: 24rpx;
justify-content: center;
}
.popup-close {
display: flex;
margin-top: 24rpx;
justify-content: center;
}
.booking-content {
padding: 10px;
font-size: 30rpx;
line-height: 1.5rem;
}
.booking-content {
padding: 10px;
font-size: 30rpx;
line-height: 1.5rem;
}
.xieyi {
margin-bottom: 80rpx;
padding: 0 30rpx;
.xieyi {
margin-bottom: 80rpx;
padding: 0 30rpx;
.text {
margin-left: 5rpx;
.text {
margin-left: 5rpx;
.link {
color: #0f80ff;
}
}
}
.goods-nav-btn {
width: 750rpx;
position: fixed;
bottom: 0;
background-color: #fff;
}
</style>
.link {
color: #0f80ff;
}
}
}
.goods-nav-btn {
width: 750rpx;
position: fixed;
bottom: 0;
background-color: #fff;
}
</style>
+410
View File
@@ -0,0 +1,410 @@
<template>
<view class="order" v-if="form.orderId">
<uni-card :border="false" :is-shadow="false" :padding="0">
<view class="order-body web-cell web-cell-align-top">
<view class="web-cell-content">
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff' }" :border="false">
<!-- <uv-cell :title="`${form.merchantName}`" :label="` `" :cellStyle="{ padding: '0', paddingBottom: '5px' }" :border="false" />-->
<block v-for="(item, index) in form.goodsList" :key="index">
<uv-cell
:cellStyle="{ padding: '0', paddingBottom: '5px' }"
:border="false"
>
<template v-slot:icon>
<uv-image :src="item.image" width="100" height="100" />
</template>
<template v-slot:title>
<view class="goods-info flex flex-col">
<view class="flex">
<uv-text lines="2" bold :text="item.goodsName"></uv-text>
<text>¥{{ item.price }}</text>
</view>
<view class="web-text-secondary">
{{ item.comments }}
</view>
<view class="tools flex justify-between web-text-secondary items-center">
<text></text>
<text>x {{ item.totalNum }}</text>
</view>
</view>
</template>
</uv-cell>
<uv-cell :label="`成人票 ¥50`" :value="`x ${item.adultNum}`" v-if="item.isChildren" :cellStyle="{ padding: '0', paddingBottom: '5px' }" :border="false" />
<uv-cell :label="`儿童票 ¥35`" :value="`x ${item.childrenNum}`" v-if="item.isChildren" :cellStyle="{ padding: '0', paddingBottom: '5px' }" :border="false" />
</block>
</uv-cell-group>
</view>
</view>
<view slot="actions" class="card-actions">
<view class="web-text-heading">合计:¥{{ form.totalPrice }}</view>
<view class="web-text-danger">实付:¥{{ form.payPrice }}</view>
</view>
</uni-card>
<block v-if="form.orderNo">
<uni-card :border="false" :is-shadow="false" :padding="0">
<view class="web-cell web-cell-align-top">
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff', padding: '8px 0' }" :border="false">
<uv-cell :title="`姓名`" :value="`${form.realName}`" :cellStyle="{ padding: '8px' }" />
<uv-cell :title="`手机号码`" :value="`${form.phone}`" :cellStyle="{ padding: '8px' }" />
<uv-cell :title="`订单号`" :value="`${form.orderId}`" :cellStyle="{ padding: '8px' }" />
<uv-cell :title="`订单编号`" :cellStyle="{ padding: '8px' }">
<template v-slot:value>
<uv-parse :content="form.orderNo" :selectable="true"></uv-parse>
</template>
</uv-cell>
<uv-cell :title="`订单状态`" :cellStyle="{ padding: '8px' }">
<template v-slot:value>
<view v-if="form.payStatus == 0">
<!-- <uv-count-down :time="form.timestamp" format="mm:ss"></uv-count-down> -->
<span style="color: #ff0000">未支付</span>
</view>
<view v-else>{{ orderStatus[form.orderStatus] }}</view>
</template>
</uv-cell>
<uv-cell :title="`下单时间`" :value="`${form.createTime}`" :cellStyle="{ padding: '8px' }" />
<uv-cell :title="`支付方式`" :value="`${payType[form.payType]}`" :cellStyle="{ padding: '8px' }" />
<uv-cell :title="`优惠说明`" :value="`${form.couponDesc ? form.couponDesc : '无'}`" :cellStyle="{ padding: '8px' }" :border="false" />
</uv-cell-group>
</view>
</uni-card>
</block>
<uv-gap height="20"></uv-gap>
<view class="checkout-car" v-if="form.payStatus == 0">
<view class="car-total">
<text style="color: #ebcf00">¥</text>
<uv-count-to decimals="2" duration="30" color="#ebcf00" bold :endVal="form.payPrice"></uv-count-to>
</view>
<uv-button
class="save-btn"
:customStyle="{ background: 'linear-gradient(to right, #70b915, #008e04)', borderRadius: '0 30px 30px 0', color: '#ffffff', border: 'none', padding: '22px 30px' }"
text="去支付"
@click="navTo(`/package/booking/confirm?id=${form.orderId}`)"
></uv-button>
</view>
<!-- 登录组件 -->
<ws-login ref="login" @done="reload" />
</view>
</template>
<script>
import * as OrderApi from '@/api/shop/order';
import { pageWechatDeposit } from '@/api/shop/wechatDeposit';
import UvAvatar from "@/uni_modules/uv-avatar/components/uv-avatar/uv-avatar.vue";
import UvImage from "@/uni_modules/uv-image/components/uv-image/uv-image.vue";
export default {
components: {UvImage, UvAvatar},
data() {
return {
isLogin: false,
orderId: 0,
userId: 0,
form: {},
where: {
page: 1
},
canReset: false,
loadMore: 'more',
logo: '',
items: ['全部订单', '未支付', '已支付', '已完成', '押金'],
orderStatus: ['已支付', '已完成', '已取消', '取消中', '退款申请中', '退款被拒绝', '退款成功', '客户端申请退款'],
payType: [
'余额支付',
'微信支付',
'会员卡支付',
'支付宝',
'现金',
'POS机',
'VIP月卡',
'VIP年卡',
'VIP次卡',
'IC月卡',
'IC年卡',
'IC次卡',
'免费',
'VIP充值卡',
'IC充值卡',
'积分支付',
'VIP季卡',
'IC季卡'
],
orderList: [],
styles: [
{
value: 'button',
text: '按钮',
checked: true
},
{
value: 'text',
text: '文字'
}
],
h5_url: '',
colors: ['#333333', '#4cd964', '#dd524d'],
current: 0,
colorIndex: 0,
activeColor: '#108001',
styleType: 'text'
};
},
onLoad(option) {
this.orderId = option.id;
// 判断是否登录
this.openLogin();
// 加载数据
this.reload();
},
onShow() {
// 判断是否登录
this.openLogin();
},
// 触底函数
onReachBottom() {
const app = this;
const { where } = this;
if (app.canReset) {
app.where.page = ++where.page;
app.reload();
}
},
methods: {
reload() {
const app = this;
const { where, userId, orderId } = this;
if (userId == 0) {
app.openLogin();
return;
}
where.userId = userId;
uni.showLoading({
title: '数据读取中.'
});
OrderApi.getOrder(orderId).then((data) => {
console.log('data: ', data);
app.form = data;
// 页面标题
if (data.orderStatus == 1) {
uni.setNavigationBarTitle({
title: '订单详情(已完成)'
});
}
uni.hideLoading();
});
// H5版网址
const h5_url = uni.getStorageSync('h5_url');
const tid = uni.getStorageSync('TenantId');
if (h5_url) {
app.h5_url = h5_url;
} else {
app.h5_url = `http://${tid}.h5.wsdns.cn`;
}
},
navTo(url) {
uni.navigateTo({
url
});
},
onClickItem(e) {
const app = this;
const { where, userId } = this;
const index = e.currentIndex;
if (this.current !== e.currentIndex) {
this.current = e.currentIndex;
}
if (userId == 0) {
app.openLogin();
return;
}
// 全部
if (index == 0) {
where.payStatus = undefined;
where.orderStatus = undefined;
}
// 未支付
if (index == 1) {
where.payStatus = 2;
}
// 已支付
if (index == 2) {
where.payStatus = 1;
}
// 已完成
if (index == 3) {
where.orderStatus = 1;
}
// 押金
if (index == 4) {
pageWechatDeposit({
uid: uni.getStorageSync('user_id')
}).then((res) => {
console.log('res: ', res);
app.orderList = res.list;
});
return false;
}
this.reload();
},
// 弹出登录提示框
async openLogin() {
this.userId = uni.getStorageSync('user_id');
if (!this.userId) {
this.$refs.login.open('bottom');
return false;
}
}
}
};
</script>
<style lang="scss">
.content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
height: 150px;
text-align: center;
}
.content-text {
font-size: 14px;
color: #666;
}
.color-tag {
width: 25px;
height: 25px;
}
.uni-list {
flex: 1;
}
.order {
.order-title {
padding: 20rpx 0;
border-bottom: 1px #eee solid;
.merchant-avatar {
margin-right: 12rpx;
}
.merchant-name {
// padding-left: 12rpx;
}
.btn-status {
font-size: 30rpx;
display: flex;
}
}
.order-body {
padding: 16px 0;
.goods-info{
margin-left: 8rpx;
.goods-name{
font-weight: 500;
}
.goods-desc{
color: #808080;
}
}
.goods-image{
width: 160rpx;
height: 160rpx;
border-radius: 8rpx;
}
}
}
.ele-flex {
display: flex;
justify-content: space-between;
}
.card-actions {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 0 10px;
align-items: center;
height: 45px;
border-top: 1px #eee solid;
.web-text-heading {
font-size: 30rpx;
font-weight: 500;
}
.web-text-danger {
font-size: 30rpx;
font-weight: 500;
}
}
.card-actions-item {
display: flex;
flex-direction: row;
align-items: center;
}
.card-actions-item-text {
font-size: 12px;
color: #666;
margin-left: 5px;
}
.btn-status {
font-size: 30rpx;
display: flex;
}
.close {
top: 60rpx !important;
}
.qrcode {
margin-top: 30rpx;
text-align: center;
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;
}
.checkout-car {
width: 700rpx;
left: 25rpx;
position: fixed;
bottom: 30rpx;
display: flex;
justify-content: space-between;
background-color: #000000;
border-radius: 100px;
align-items: center;
.car-selected {
color: #ccc;
display: flex;
align-items: center;
padding: 0 20rpx;
}
.car-total {
display: flex;
color: #ebcf00;
align-items: center;
padding-left: 40rpx;
.save-btn {
}
}
}
</style>
+353 -353
View File
@@ -1,99 +1,99 @@
<template>
<view>
<view class="segmented">
<uni-segmented-control :current="current" :values="items" :styleType="styleType" :activeColor="activeColor" inActiveColor="#808080" @clickItem="onClickItem" />
</view>
<view class="order">
<block v-if="orderList.length > 0">
<block v-for="(item, index) in orderList" :key="index">
<uni-card :border="false" :is-shadow="false" :padding="0">
<template v-slot:title>
<div class="order-title web-cell">
<view class="web-cell web-cell-content">
<view class="merchant-avatar">
<uv-avatar :src="item.merchantAvatar" size="24"></uv-avatar>
</view>
<text class="merchant-name">{{ item.merchantName }}</text>
</view>
<block v-if="item.orderStatus == 2">
<text class="btn-status web-text-secondary">已取消</text>
</block>
<block v-else-if="item.orderStatus == 1">
<text class="btn-status web-text-success">已完成</text>
</block>
<block v-else>
<text v-if="item.payStatus == 1" class="btn-status web-text-success">已支付</text>
<view v-if="item.payStatus == 0" class="btn-status web-text-danger">
<uv-count-down :time="item.timestamp" format="mm:ss"></uv-count-down>
<text class="no-pay" style="margin-left: 10rpx">未支付</text>
</view>
</block>
</div>
</template>
<view class="order-body web-cell web-cell-align-top">
<view class="web-cell-content">
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff' }" :border="false">
<block v-for="(sub, subIndex) in item.goodsList" :key="subIndex">
<uv-cell
:title="`${sub.goodsName}`"
:label="`${sub.comments}`"
:cellStyle="{ padding: '0', paddingBottom: '5px' }"
:border="false"
@click="openUrl(`/package/order/detail?id=${item.orderId}`)"
>
<template v-slot:icon>
<uv-avatar :src="sub.image" fontSize="12" size="50" shape="square"></uv-avatar>
</template>
<template v-slot:value>
<view class="goods-price-bar">
<view class="goods-price web-text-heading">¥{{sub.price}}</view>
<view class="total-num web-text-secondary" style="font-size: 13px;letter-spacing: 1px;">共{{ item.totalNum }}件</view>
</view>
</template>
</uv-cell>
</block>
</uv-cell-group>
<!-- <view class="total-price">
<view class="web-text-heading">合计:¥{{ item.totalPrice }}</view>
<view class="web-text-heading" style="font-weight: 500">实付:¥{{ item.totalPrice - item.reducePrice }}</view>
</view> -->
</view>
</view>
<view slot="actions" class="card-actions">
<view class="card-actions-item" v-if="item.payStatus == 0 && item.orderStatus == 0">
<button class="mini-btn" size="mini" @click="closeOrder(item)" style="margin-right: 20rpx">取消订单</button>
<button class="mini-btn" type="primary" size="mini" @click="toPay(item.orderId)">去支付</button>
</view>
<view class="card-actions-item" v-if="item.payStatus == 1 && item.isInvoice == 0" @click="onInvoice(item.orderId)">
<button class="mini-btn" size="mini">申请开票</button>
</view>
</view>
</uni-card>
</block>
</block>
<block v-if="orderList.length == 0 && loadMore != 'no-more'">
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="3" avatar :loading="hideTools" :title="false"></uv-skeleton>
<uv-gap height="16"></uv-gap>
</uni-card>
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="3" avatar :loading="hideTools" :title="false"></uv-skeleton>
<uv-gap height="16"></uv-gap>
</uni-card>
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="3" avatar :loading="hideTools" :title="false"></uv-skeleton>
<uv-gap height="16"></uv-gap>
</uni-card>
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="3" avatar :loading="hideTools" :title="false"></uv-skeleton>
<uv-gap height="16"></uv-gap>
</uni-card>
</block>
<uni-load-more v-if="orderList.length > 0" :status="loadMore"></uni-load-more>
<!-- 登录组件 -->
<ws-login ref="login" :logo="logo" @done="reload" />
</view>
</view>
<view>
<view class="segmented">
<uni-segmented-control :current="current" :values="items" :styleType="styleType" :activeColor="activeColor" inActiveColor="#ff0000" @clickItem="onClickItem" />
</view>
<view class="order">
<block v-if="orderList.length > 0">
<block v-for="(item, index) in orderList" :key="index">
<uni-card :border="false" :is-shadow="false" :padding="0">
<template v-slot:title>
<div class="order-title web-cell">
<view class="web-cell web-cell-content">
<view class="merchant-avatar">
<uv-avatar :src="item.merchantAvatar" size="24"></uv-avatar>
</view>
<text class="merchant-name">{{ item.merchantName }}</text>
</view>
<block v-if="item.orderStatus == 2">
<text class="btn-status web-text-secondary">已取消</text>
</block>
<block v-else-if="item.orderStatus == 1">
<text class="btn-status web-text-success">已完成</text>
</block>
<block v-else>
<text v-if="item.payStatus == 1" class="btn-status web-text-success">已支付</text>
<view v-if="item.payStatus == 0" class="btn-status web-text-danger">
<!-- <uv-count-down :time="item.timestamp" format="mm:ss"></uv-count-down>-->
<text class="no-pay" style="margin-left: 10rpx">未支付</text>
</view>
</block>
</div>
</template>
<view class="order-body web-cell web-cell-align-top">
<view class="web-cell-content">
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff' }" :border="false">
<block v-for="(sub, subIndex) in item.goodsList" :key="subIndex">
<uv-cell
:title="`${sub.goodsName}`"
:label="`${sub.comments}`"
:cellStyle="{ padding: '0', paddingBottom: '5px' }"
:border="false"
@click="openUrl(`/package/goods/order-detail?id=${item.orderId}`)"
>
<template v-slot:icon>
<uv-avatar :src="sub.image" fontSize="12" size="50" shape="square"></uv-avatar>
</template>
<template v-slot:value>
<view class="goods-price-bar">
<view class="goods-price web-text-heading">¥{{sub.price}}</view>
<view class="total-num web-text-secondary" style="font-size: 13px;letter-spacing: 1px;">共{{ item.totalNum }}件</view>
</view>
</template>
</uv-cell>
</block>
</uv-cell-group>
<!-- <view class="total-price">
<view class="web-text-heading">合计:¥{{ item.totalPrice }}</view>
<view class="web-text-heading" style="font-weight: 500">实付:¥{{ item.totalPrice - item.reducePrice }}</view>
</view> -->
</view>
</view>
<view slot="actions" class="card-actions">
<view class="card-actions-item" v-if="item.payStatus == 0 && item.orderStatus == 0">
<button class="mini-btn" size="mini" @click="closeOrder(item)" style="margin-right: 20rpx">取消订单</button>
<button class="mini-btn" size="mini" style="background-color: #ff0000; color: #FFFFFF" @click="toPay(item.orderId)">去支付</button>
</view>
<!-- <view class="card-actions-item" v-if="item.payStatus == 1 && item.isInvoice == 0" @click="onInvoice(item.orderId)">-->
<!-- <button class="mini-btn" size="mini">申请开票</button>-->
<!-- </view>-->
</view>
</uni-card>
</block>
</block>
<block v-if="orderList.length == 0 && loadMore != 'no-more'">
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="3" avatar :loading="hideTools" :title="false"></uv-skeleton>
<uv-gap height="16"></uv-gap>
</uni-card>
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="3" avatar :loading="hideTools" :title="false"></uv-skeleton>
<uv-gap height="16"></uv-gap>
</uni-card>
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="3" avatar :loading="hideTools" :title="false"></uv-skeleton>
<uv-gap height="16"></uv-gap>
</uni-card>
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="3" avatar :loading="hideTools" :title="false"></uv-skeleton>
<uv-gap height="16"></uv-gap>
</uni-card>
</block>
<uni-load-more v-if="orderList.length > 0" :status="loadMore"></uni-load-more>
<!-- 登录组件 -->
<ws-login ref="login" @done="reload" />
</view>
</view>
</template>
<script>
@@ -102,308 +102,308 @@ import { pageWechatDeposit } from '@/api/shop/wechatDeposit';
import { getWeek, getKey } from '@/utils/common';
export default {
components: {},
data() {
return {
isRefresh: false,
isLogin: false,
userId: 0,
where: {
page: 1,
type: 0, // 0商城订单 1场地预定
sceneType: 'showOrderGoods' // 查询订单附加场地信息
},
canReset: false,
loadMore: 'more',
logo: '',
items: ['全部', '待付款', '待发货', '待收货', '已完成'],
orderList: [],
styles: [
{
value: 'button',
text: '按钮',
checked: true
},
{
value: 'text',
text: '文字'
}
],
colors: ['#333333', '#4cd964', '#dd524d'],
current: 0,
colorIndex: 0,
activeColor: '#108001',
styleType: 'text',
getWeek,
// 骨架屏
hideTools: true
};
},
onLoad(option) {
// 判断是否登录
this.openLogin();
// 加载数据
// this.reload()
// if(option.isRefresh){
// this.isRefresh = true
// }
},
onShow(e) {
// 判断是否登录
this.openLogin();
this.reload();
},
// 触底函数
onReachBottom() {
const app = this;
const { where } = this;
if (app.canReset) {
app.where.page = ++where.page;
app.reload();
}
},
methods: {
reload() {
const app = this;
const { where, userId } = this;
if (userId == 0) {
app.openLogin();
return;
}
where.userId = userId;
// uni.showLoading({
// title: '数据读取中.'
// })
app.loadMore = 'loading';
OrderApi.pageOrder(where)
.then((res) => {
const list = res.list.map((d) => {
return d;
});
if (app.orderList.length < res.count) {
console.log('11111: ', 11111);
app.orderList = app.orderList.concat(list);
app.canReset = true;
app.loadMore = 'no-more';
} else {
app.canReset = false;
app.loadMore = 'no-more';
console.log('22222: ', 22222);
}
uni.hideLoading();
app.isRefresh = false;
})
.catch(() => {
uni.showToast({
title: '请检查您的网络.',
icon: 'none'
});
uni.hideLoading();
app.isRefresh = false;
});
},
onClickItem(e) {
const app = this;
const { where, userId } = this;
const index = e.currentIndex;
if (this.current !== e.currentIndex) {
this.current = e.currentIndex;
}
if (userId == 0) {
app.openLogin();
return;
}
// 全部
if (index == 0) {
where.payStatus = undefined;
where.orderStatus = undefined;
}
// 未支付
if (index == 1) {
where.payStatus = 0;
where.orderStatus = undefined;
}
// 已支付
if (index == 2) {
where.payStatus = 1;
where.orderStatus = undefined;
}
// 已完成
if (index == 3) {
where.payStatus = 1;
where.orderStatus = 1;
}
// 押金
if (index == 4) {
pageWechatDeposit({
uid: uni.getStorageSync('user_id')
}).then((res) => {
app.orderList = res.list;
if (res.count == 0) {
app.loadMore = 'no-more';
}
uni.hideLoading();
});
return false;
}
this.where.page = 1;
this.orderList = [];
this.reload();
},
openUrl(url) {
uni.navigateTo({
url
});
},
toPay(orderId) {
uni.navigateTo({
url: '/package/booking/confirm?id=' + orderId
});
},
closeOrder(item) {
uni.showModal({
title: '确定取消此订单?',
success(o) {
if (o.confirm) {
OrderApi.updateOrder({
orderStatus: 2,
orderId: item.orderId
})
.then((msg) => {
uni.showToast({
title: msg,
icon: 'none'
});
item.orderStatus = 2;
})
.catch(() => {
uni.showToast({
title: '请检查您的网络.',
icon: 'none'
});
uni.hideLoading();
});
}
}
});
},
// 弹出登录提示框
async openLogin() {
this.userId = uni.getStorageSync('user_id');
if (!this.userId) {
this.$refs.login.open('bottom');
return false;
}
},
// 申请开票
onInvoice(id) {
uni.navigateTo({
url: '/package/user/invoice?id=' + id
});
}
}
components: {},
data() {
return {
isRefresh: false,
isLogin: false,
userId: 0,
where: {
page: 1,
type: 0, // 0商城订单 1场地预定
sceneType: 'showOrderGoods' // 查询订单附加场地信息
},
canReset: false,
loadMore: 'more',
logo: '',
items: ['全部', '待付款', '待发货', '待收货', '已完成'],
orderList: [],
styles: [
{
value: 'button',
text: '按钮',
checked: true
},
{
value: 'text',
text: '文字'
}
],
colors: ['#333333', '#4cd964', '#dd524d'],
current: 0,
colorIndex: 0,
activeColor: '#ff0000',
styleType: 'text',
getWeek,
// 骨架屏
hideTools: true
};
},
onLoad(option) {
// 判断是否登录
this.openLogin();
// 加载数据
// this.reload()
// if(option.isRefresh){
// this.isRefresh = true
// }
},
onShow(e) {
// 判断是否登录
this.openLogin();
this.reload();
},
// 触底函数
onReachBottom() {
const app = this;
const { where } = this;
if (app.canReset) {
app.where.page = ++where.page;
app.reload();
}
},
methods: {
reload() {
const app = this;
const { where, userId } = this;
if (userId == 0) {
app.openLogin();
return;
}
where.userId = userId;
// uni.showLoading({
// title: '数据读取中.'
// })
app.loadMore = 'loading';
OrderApi.pageOrder(where)
.then((res) => {
const list = res.list.map((d) => {
return d;
});
if (app.orderList.length < res.count) {
console.log('11111: ', 11111);
app.orderList = app.orderList.concat(list);
app.canReset = true;
app.loadMore = 'no-more';
} else {
app.canReset = false;
app.loadMore = 'no-more';
console.log('22222: ', 22222);
}
uni.hideLoading();
app.isRefresh = false;
})
.catch(() => {
uni.showToast({
title: '请检查您的网络.',
icon: 'none'
});
uni.hideLoading();
app.isRefresh = false;
});
},
onClickItem(e) {
const app = this;
const { where, userId } = this;
const index = e.currentIndex;
if (this.current !== e.currentIndex) {
this.current = e.currentIndex;
}
if (userId == 0) {
app.openLogin();
return;
}
// 全部
if (index == 0) {
where.payStatus = undefined;
where.orderStatus = undefined;
}
// 未支付
if (index == 1) {
where.payStatus = 0;
where.orderStatus = undefined;
}
// 已支付
if (index == 2) {
where.payStatus = 1;
where.orderStatus = undefined;
}
// 已完成
if (index == 3) {
where.payStatus = 1;
where.orderStatus = 1;
}
// 押金
if (index == 4) {
pageWechatDeposit({
uid: uni.getStorageSync('user_id')
}).then((res) => {
app.orderList = res.list;
if (res.count == 0) {
app.loadMore = 'no-more';
}
uni.hideLoading();
});
return false;
}
this.where.page = 1;
this.orderList = [];
this.reload();
},
openUrl(url) {
uni.navigateTo({
url
});
},
toPay(orderId) {
uni.navigateTo({
url: '/package/booking/confirm?id=' + orderId
});
},
closeOrder(item) {
uni.showModal({
title: '确定取消此订单?',
success(o) {
if (o.confirm) {
OrderApi.updateOrder({
orderStatus: 2,
orderId: item.orderId
})
.then((msg) => {
uni.showToast({
title: msg,
icon: 'none'
});
item.orderStatus = 2;
})
.catch(() => {
uni.showToast({
title: '请检查您的网络.',
icon: 'none'
});
uni.hideLoading();
});
}
}
});
},
// 弹出登录提示框
async openLogin() {
this.userId = uni.getStorageSync('user_id');
if (!this.userId) {
this.$refs.login.open('bottom');
return false;
}
},
// 申请开票
onInvoice(id) {
uni.navigateTo({
url: '/package/user/invoice?id=' + id
});
}
}
};
</script>
<style lang="scss">
.content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
height: 150px;
text-align: center;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
height: 150px;
text-align: center;
}
.segmented {
padding: 0 12rpx;
padding: 0 12rpx;
}
.content-text {
font-size: 14px;
color: #666;
font-size: 14px;
color: #666;
}
.color-tag {
width: 25px;
height: 25px;
width: 25px;
height: 25px;
}
.uni-list {
flex: 1;
flex: 1;
}
.order {
.order-title {
padding: 20rpx 0;
border-bottom: 1px #eee solid;
.order-title {
padding: 20rpx 0;
border-bottom: 1px #eee solid;
.merchant-avatar {
margin-right: 12rpx;
}
.merchant-avatar {
margin-right: 12rpx;
}
.merchant-name {
// padding-left: 12rpx;
}
.merchant-name {
// padding-left: 12rpx;
}
.btn-status {
font-size: 30rpx;
display: flex;
}
}
.btn-status {
font-size: 30rpx;
display: flex;
}
}
.order-body {
padding: 16px 0;
}
.order-body {
padding: 16px 0;
}
}
.ele-flex {
display: flex;
justify-content: space-between;
display: flex;
justify-content: space-between;
}
.card-actions {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
height: 45px;
border-top: 1px #eee solid;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
height: 45px;
border-top: 1px #eee solid;
}
.card-actions-item {
display: flex;
flex-direction: row;
align-items: center;
display: flex;
flex-direction: row;
align-items: center;
}
.card-actions-item-text {
font-size: 12px;
color: #666;
margin-left: 5px;
font-size: 12px;
color: #666;
margin-left: 5px;
}
.close {
top: 60rpx !important;
top: 60rpx !important;
}
.total-price {
display: flex;
flex-direction: column;
justify-content: flex-start;
font-size: 30rpx;
align-items: flex-start;
padding-left: 6rpx;
margin-left: 450rpx;
display: flex;
flex-direction: column;
justify-content: flex-start;
font-size: 30rpx;
align-items: flex-start;
padding-left: 6rpx;
margin-left: 450rpx;
.web-text-heading {
font-size: 30rpx !important;
}
.web-text-heading {
font-size: 30rpx !important;
}
}
.goods-price-bar{
display: flex;
flex-direction: column;
align-items: flex-end;
display: flex;
flex-direction: column;
align-items: flex-end;
}
</style>
+27 -8
View File
@@ -2,28 +2,28 @@
"pages": [
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"path": "pages/index",
"style": {
"navigationBarTitleText": "广西体育中心",
"enablePullDownRefresh": false
}
},
{
"path": "pages/shop/shop",
"path": "pages/shop",
"style": {
"navigationBarTitleText": "商城",
"enablePullDownRefresh": false
}
},
{
"path": "pages/order/order",
"path": "pages/order",
"style": {
"navigationBarTitleText": "我的订单",
"enablePullDownRefresh": false
}
},
{
"path": "pages/user/user",
"path": "pages/user",
"style": {
"navigationBarTitleText": "个人中心",
"enablePullDownRefresh": false,
@@ -188,6 +188,12 @@
"navigationBarTitleText": "商城订单"
}
},
{
"path": "goods/order-detail",
"style": {
"navigationBarTitleText": "订单详情"
}
},
{
"path": "card/index",
"style": {
@@ -200,6 +206,12 @@
"navigationBarTitleText": "订单确认"
}
},
{
"path": "cart/index",
"style": {
"navigationBarTitleText": "购物车"
}
},
{
"path": "article/index",
"style": {
@@ -322,6 +334,13 @@
"style": {
"navigationBarTitleText": "领劵中心"
}
},
{
"path": "foods/index",
"style": {
"navigationBarTitleText": "门店商品",
"enablePullDownRefresh": false
}
}
]
},
@@ -381,25 +400,25 @@
"fontSize": "14px",
"list": [
{
"pagePath": "pages/index/index",
"pagePath": "pages/index",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home-active.png",
"text": "首页"
},
{
"pagePath": "pages/shop/shop",
"pagePath": "pages/shop",
"iconPath": "static/tabbar/shop.png",
"selectedIconPath": "static/tabbar/shop-active.png",
"text": "商城"
},
{
"pagePath": "pages/order/order",
"pagePath": "pages/order",
"iconPath": "static/tabbar/order.png",
"selectedIconPath": "static/tabbar/order-active.png",
"text": "订单"
},
{
"pagePath": "pages/user/user",
"pagePath": "pages/user",
"iconPath": "static/tabbar/user.png",
"selectedIconPath": "static/tabbar/user-active.png",
"text": "我的"
-84
View File
@@ -1,84 +0,0 @@
<template>
<view>
<view class="search">
<uni-search-bar placeholder="搜索" @confirm="search" :focus="true" v-model="searchValue" @blur="blur" @focus="focus"
@input="input" @cancel="cancel" cancelButton="none" @clear="clear">
</uni-search-bar>
</view>
<ws-chat :list="list"></ws-chat>
</view>
</template>
<script>
export default {
data() {
return {
searchValue: '',
list: [{
userId: 1,
nickname: '张三',
avatar: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png',
note: '您收到一条消息',
badge: 99,
to: '/package/order/order',
createTime: '2023-12-12'
}, {
userId: 2,
nickname: '李四',
avatar: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png',
note: '您收到一条消息',
badge: 'dot',
createTime: '2023-12-12'
}, {
userId: 3,
nickname: '王五',
avatar: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png',
note: '您收到一条消息',
badge: 5,
createTime: '2023-12-12'
}]
}
},
methods: {
search(res) {
uni.showToast({
title: '搜索:' + res.value,
icon: 'none'
})
},
input(res) {
console.log('----input:', res)
},
clear(res) {
uni.showToast({
title: 'clear事件,清除值为:' + res.value,
icon: 'none'
})
},
blur(res) {
uni.showToast({
title: 'blur事件,输入值为:' + res.value,
icon: 'none'
})
},
focus(e) {
uni.showToast({
title: 'focus事件,输出值为:' + e.value,
icon: 'none'
})
},
cancel(res) {
uni.showToast({
title: '点击取消,输入值为:' + res.value,
icon: 'none'
})
}
}
}
</script>
<style lang="scss" scoped>
.search{
background-color: #ffffff;
}
</style>
+46 -39
View File
@@ -101,6 +101,16 @@
</template>
</uv-vtabs>
<!-- 购物车 -->
<view class="cart-icon">
<view class="icon" style="position: relative" @click="navTo(`/package/cart/index`)">
<uv-badge type="error" max="40" :value="cart.totalNums"
style="position: absolute; top: -1px; right: -1px; z-index: 9;"></uv-badge>
<uv-icon name="shopping-cart" size="30" color="#0c9d04"></uv-icon>
</view>
</view>
<!-- 支付密码弹窗 -->
<uni-popup ref="specForm" type="center" border-radius="10px 10px 0 0">
<uni-card :title="goods.goodsName" :border="false" :is-shadow="false" :padding="0">
@@ -135,7 +145,7 @@
<view class="flex m-20 justify-between items-center">
<view class="total-price web-text-heading">
总计
<text class="text-red-500" style="font-weight: 500; font-size: 36rpx">¥12.99</text>
<text class="text-red-500" style="font-weight: 500; font-size: 36rpx">¥{{ goods.price }}</text>
</view>
<view class="add-cart">
<uv-button type="warning" class="add-address" iconSize="16" :customStyle="{ borderRadius: '6px', padding: '5px 20px',
@@ -162,10 +172,12 @@ import {useMpStore} from "@/store/modules/mp";
import UvGap from "@/uni_modules/uv-gap/components/uv-gap/uv-gap.vue";
import * as CartApi from "@/api/shop/cart";
import {ShoppingCartOutlined} from '@ant-design/icons-vue';
const mpStore = useMpStore();
export default {
components: {UvGap, UvButton, UvImage, UvAvatar, Layout},
components: {UvGap, UvButton, UvImage, UvAvatar, Layout, ShoppingCartOutlined},
data() {
return {
shopInfo: {},
@@ -185,9 +197,7 @@ export default {
// 支付密码是否正确
isPayPasswordCorrect: false,
disabledPayPayPassword: false,
payPassword: '',
totalPrice: 0,
cartNum: 0
payPassword: ''
}
},
computed: {
@@ -239,14 +249,15 @@ export default {
CartApi.listCart({type: 0, isNew: false}).then(data => {
if (data) {
this.cart = data
uni.setTabBarBadge({
index: 2,
text: `${data.totalNums}`
})
// uni.setTabBarBadge({
// index: 1,
// text: `${data.totalNums}`
// })
}
})
},
navTo(url) {
console.log('>>>>>url')
uni.navigateTo({url})
},
change(index) {
@@ -314,6 +325,11 @@ export default {
},
onSlide() {
},
search(){
uni.navigateTo({
url: '/package/goods/index?keywords=' + this.goods.goodsId
})
},
save() {
// 跳转页面
@@ -366,36 +382,6 @@ export default {
}
}
.checkout-car {
width: 700rpx;
left: 25rpx;
z-index: 9999;
position: fixed;
bottom: 30rpx;
display: flex;
justify-content: space-between;
background-color: #000000;
border-radius: 100px;
align-items: center;
.car-selected {
color: #ccc;
display: flex;
align-items: center;
padding: 0 20rpx;
}
.car-total {
display: flex;
color: #ebcf00;
align-items: center;
padding-left: 40rpx;
.save-btn {
}
}
}
.gap {
padding: 0 30rpx;
}
@@ -468,4 +454,25 @@ export default {
justify-content: center;
align-items: center;
}
.cart-icon {
position: fixed;
bottom: 200rpx;
right: 20rpx;
width: 75rpx;
height: 75rpx;
font-size: 33rpx;
color: #0c9d04;
display: flex;
align-items: center;
justify-content: center;
border-radius: 100rpx;
cursor: pointer;
background-color: #FFFFFF;
box-shadow: 0 0px 6px 0 rgba(0, 0, 0, 0.2);
.icon {
display: block;
}
}
</style>
+75 -47
View File
@@ -16,54 +16,71 @@
<!-- 收藏|关注|足迹|作品 -->
<!-- <ws-user-collect></ws-user-collect> -->
<!-- 我的资产 -->
<ws-my-asset :data="users" :is-login="isLogin" @done="openLogin"></ws-my-asset>
<ws-my-asset :data="userInfo" :users="users" :config="config" :is-login="isLogin" @done="openLogin"></ws-my-asset>
<!-- 我的订单 -->
<!-- <ws-user-order :order="order" :is-login="isLogin" @done="openLogin"></ws-user-order> -->
<!-- 其他功能 -->
<uni-card :border="false" :padding="0">
<!-- 场馆管理可见-->
<block v-if="hasMerchantRole || hasMerchantClerkRole">
<view class="server" style="min-height: 200px">
<uni-list :border="false">
<block v-for="(item, index) in mpMenus" :key="index">
<block v-if="index === '1981'" v-for="(v,i) in item">
<uni-list-item :thumb="v.avatar" link @click="navTo(item)">
<template v-slot:body>
<view class="slot-box">
<text class="slot-text" :style="{ color: v.color ? v.color : '#333333' }">{{
v.title
}}
</text>
</view>
</template>
</uni-list-item>
</block>
<!-- <uni-card :border="false" :padding="0">-->
<!-- &lt;!&ndash; 场馆管理可见&ndash;&gt;-->
<!-- <block v-if="hasMerchantRole || hasMerchantClerkRole">-->
<!-- <view class="server" style="min-height: 200px">-->
<!-- <uni-list :border="false">-->
<!-- <block v-for="(item, index) in mpMenus" :key="index">-->
<!-- <block v-if="index === '1981'" v-for="(v,i) in item">-->
<!-- <uni-list-item :thumb="v.avatar" link @click="navTo(v)">-->
<!-- <template v-slot:body>-->
<!-- <view class="slot-box">-->
<!-- <text class="slot-text" :style="{ color: v.color ? v.color : '#333333' }">{{-->
<!-- v.title-->
<!-- }}-->
<!-- </text>-->
<!-- </view>-->
<!-- </template>-->
<!-- </uni-list-item>-->
<!-- </block>-->
<!-- </block>-->
<!-- </uni-list>-->
<!-- </view>-->
<!-- </block>-->
<!-- <block v-else>-->
<!-- &lt;!&ndash; 普通会员菜单 &ndash;&gt;-->
<!-- <view class="server" style="min-height: 200px">-->
<!-- <uni-list :border="false">-->
<!-- <block v-for="(item, index) in mpMenus" :key="index">-->
<!-- <block v-if="index === '1981'" v-for="(v,i) in item">-->
<!-- <uni-list-item :thumb="v.avatar" link @click="navTo(v)">-->
<!-- <template v-slot:body>-->
<!-- <view class="slot-box">-->
<!-- <text class="slot-text" :style="{ color: v.color ? v.color : '#333333' }">{{-->
<!-- v.title-->
<!-- }}-->
<!-- </text>-->
<!-- </view>-->
<!-- </template>-->
<!-- </uni-list-item>-->
<!-- </block>-->
<!-- </block>-->
<!-- </uni-list>-->
<!-- </view>-->
<!-- </block>-->
<!-- </uni-card>-->
<block v-for="(item, index) in mpMenus" :key="index">
<uni-card :title="item[0].groupName" :border="false" :padding="0">
<uv-skeleton rows="1" rowsHeight="30" rowsWidth="100%" :loading="mpMenus.length === 0" :title="false">
<div class="flex space-around py-6 flex-wrap">
<block v-for="(item,index) in item" :key="index">
<div class="service-item flex flex-col justify-center items-center web-cell-content web-text-center px-20"
@click="navTo(item)">
<image :src="item.avatar" style="width: 30px; height: 30px;" mode="widthFix"></image>
<text>{{ item.title }}</text>
</div>
</block>
</uni-list>
</view>
</block>
<block v-else>
<!-- 普通会员菜单 -->
<view class="server" style="min-height: 200px">
<uni-list :border="false">
<block v-for="(item, index) in mpMenus" :key="index">
<block v-if="index === '1981'" v-for="(v,i) in item">
<uni-list-item :thumb="item.avatar" link @click="navTo(item)">
<template v-slot:body>
<view class="slot-box">
<text class="slot-text" :style="{ color: item.color ? item.color : '#333333' }">{{
v.title
}}
</text>
</view>
</template>
</uni-list-item>
</block>
</block>
</uni-list>
</view>
</block>
</uni-card>
</div>
<w-gap height="5"></w-gap>
</uv-skeleton>
</uni-card>
</block>
<!-- <ws-personal :form="users" ref="personal" @done="reload" />-->
<!-- 登录组件 -->
@@ -77,17 +94,18 @@
<script>
import {useUserStore} from '@/store/modules/user';
import * as UserApi from '@/api/booking/users';
import * as MpMenuApi from '@/api/cms/mp-menu/index';
import * as MpMenuApi from '@/api/cms/mp-menu';
import * as UserCardApi from '@/api/booking/userCard';
import {updateUsers} from '@/api/shop/users';
import {openUrl} from '@/utils/common';
import {useMpStore} from "@/store/modules/mp";
import {getWxOpenId} from '@/api/passport/login';
import Layout from "@/components/layout.vue";
import {useTenantStore} from '@/store/modules/tenant';
const tenantStore = useTenantStore();
const mpStore = useMpStore();
const userStore = useUserStore();
export default {
@@ -99,6 +117,7 @@ export default {
userInfo: {},
fields: {},
logo: '',
config: {},
bookingUser: {},
merchantList: [],
server: [],
@@ -129,6 +148,10 @@ export default {
}
}
});
// 当前小程序信息
const info = await mpStore.fetchMpInfo();
// 配置信息
app.config = info.config
// 当前租户信息
const tenantInfo = await tenantStore.fetchTenantInfo();
app.logo = tenantInfo.websiteLogo;
@@ -252,4 +275,9 @@ page {
overflow-x: hidden;
}
</style>
<style lang="scss"></style>
<style lang="scss">
.service-item{
width: 130rpx !important;
margin-bottom: 30rpx;
}
</style>
+866
View File
@@ -0,0 +1,866 @@
$bg: #F8F8F8;
$orange: #fd7600;
$orange-deep: #FF4B00;
$orange-light: #FFC5AD;
$green: #54B06E;
$green-light: #96b0a3;
$blue: #518AFA;
$blue-light: #6EC8F2;
$purple: #c770f6;
$purple-light: #E0AFFB;
$red: #ef1717;
$red-light: #F7B2B2;
$gray-weight: #aaa;
$gray: #bbb;
$gray-light: #F7F7F7;
$gold: #B68320;
$gold-light: #FFF0D3;
$fdca00: #FDCA00;
$u-primary: $orange;
//p, span {
// font-size: 30rpx;
// margin: 0;
//}
h6 {
font-weight: bolder !important;
font-size: 20rpx;
}
.pos-r {
position: relative;
}
.pos-a {
position: absolute;
}
.bg {
background-color: $bg;
}
.bg-gray-light {
background-color: $gray-light;
}
.bg-white {
background-color: white;
}
.bg-main {
background-color: $u-primary;
}
.bg-orange {
background-color: #FFCB7E;
}
.bg-blue {
background-color: $blue;
}
.bg-main-light {
background-color: $gold-light;
}
.bg-fff0 {
background-color: #F0F0F0FF;
}
.shadow {
box-shadow: 1px 1px 10px #ccc;
}
.shadow-top {
box-shadow: 0px -2px 10px #ccc;
}
.shadow-light {
box-shadow: 0rpx 4rpx 12rpx 0rpx rgba(206, 206, 206, 80);
}
.shadow-50 {
box-shadow: -2rpx 4rpx 14rpx 4rpx rgba(206, 206, 206, 50);
}
.font-bold {
font-weight: bold;
}
.font-bolder {
font-weight: bolder;
}
.text-center {
text-align: center;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
.tips {
font-size: 20rpx;
color: $gray;
}
.text-main {
color: $u-primary;
}
.text-orange {
color: #fd7600;
}
.text-blue {
color: $blue;
}
.text-green {
color: $green;
}
.text-red {
color: $red;
}
.text-gray {
color: $gray;
}
.text-gray-weight {
color: $gray-weight;
}
.text-black {
color: #333;
}
.color-6C {
color: #6C6C6C;
}
.text-white {
color: white;
}
.color-9A {
color: #9A9A9A;
}
.color-333 {
color: #333333;
}
.flex {
display: flex;
}
.flex-wrap {
flex-wrap: wrap;
}
.justify-center {
justify-content: center;
}
.justify-start {
justify-content: flex-start;
}
.justify-end {
justify-content: flex-end;
}
.justify-between {
justify-content: space-between;
}
.justify-around {
justify-content: space-around;
}
.items-center {
align-items: center;
}
.items-start {
align-items: flex-start;
}
.items-end {
align-items: flex-end;
}
.item-self {
align-self: flex-end;
}
.flex-col {
flex-direction: column;
}
.flex-rev {
flex-direction: row-reverse;
}
.flex-1 {
flex: 1;
}
.flex-2 {
flex: 2;
}
.flex-3 {
flex: 3;
}
.flex-shrink {
flex-shrink: 0;
}
.flex-none {
flex: none;
}
.flex-grow {
flex-grow: 1
}
.flex-grow-0 {
flex-grow: 0
}
.h-100 {
height: 100vh;
}
.h-100p {
height: 100%;
}
.h-90p {
height: 90%;
}
.h-50p {
height: 50%;
}
.h-10p {
height: 10%;
}
.w-100 {
width: 100vw;
}
.w-100p {
width: 100%;
}
.w-5p {
width: 5%;
}
.w-10p {
width: 10%;
}
.w-15p {
width: 15%;
}
.w-20p {
width: 20%;
}
.w-25p {
width: 25%;
}
.w-30p {
width: 30%;
}
.w-33p {
width: 33%;
}
.w-40p {
width: 40%;
}
.w-45p {
width: 45%;
}
.w-50p {
width: 50%;
}
.w-60p {
width: 60%;
}
.w-67p {
width: 67%;
}
.w-75p {
width: 75%;
}
.w-80p {
width: 80%;
}
.w-85p {
width: 85%;
}
.w-90p {
width: 90%;
}
.p-10 {
padding: 10rpx;
}
.p-15 {
padding: 15rpx;
}
.pb-15 {
padding-bottom: 15rpx;
}
.pb-20 {
padding-bottom: 20rpx;
}
.pb-30 {
padding-bottom: 30rpx;
}
.p-20 {
padding: 20rpx;
}
.p-25 {
padding: 25rpx;
}
.p-30 {
padding: 30rpx;
}
.p-35 {
padding: 35rpx;
}
.p-40 {
padding: 40rpx;
}
.px-40 {
padding: 0 40rpx;
}
.p-50 {
padding: 50rpx;
}
.py-10 {
padding: 10rpx 0;
}
.py-15 {
padding: 15rpx 0;
}
.py-20 {
padding: 20rpx 0;
}
.py-25 {
padding: 25rpx 0;
}
.py-30 {
padding: 30rpx 0;
}
.px-15 {
padding: 0 15rpx;
}
.px-20 {
padding: 0 15rpx;
}
.px-30 {
padding: 0 30rpx;
}
.pl-15 {
padding-left: 15rpx;
}
.pl-20 {
padding-left: 20rpx;
}
.pl-40 {
padding-left: 40rpx;
}
.pr-15 {
padding-right: 15rpx;
}
.pr-20 {
padding-right: 20rpx;
}
.pr-30 {
padding-right: 30rpx;
}
.pt-10 {
padding-top: 10rpx;
}
.pt-20 {
padding-top: 20rpx;
}
.pr-25 {
padding-right: 25rpx;
}
.m-a {
margin: auto;
}
.m-10 {
margin: 10rpx;
}
.m-15 {
margin: 15rpx;
}
.m-20 {
margin: 20rpx;
}
.m-25 {
margin: 25rpx;
}
.m-30 {
margin: 30rpx;
}
.ml-5{
margin-left: 5rpx;
}
.ml-8 {
margin-left: 8rpx;
}
.ml-10 {
margin-left: 10rpx;
}
.ml-15 {
margin-left: 15rpx;
}
.ml-25 {
margin-left: 25rpx;
}
.ml-35 {
margin-left: 35rpx;
}
.ml-40 {
margin-left: 40rpx;
}
.mt-5 {
margin-top: 5rpx;
}
.mt-6 {
margin-top: 6rpx;
}
.mt-8 {
margin-top: 8rpx;
}
.mt-10 {
margin-top: 10rpx;
}
.mt-15 {
margin-top: 15rpx;
}
.mt-20 {
margin-top: 20rpx;
}
.mt-25 {
margin-top: 25rpx;
}
.mt-30 {
margin-top: 30rpx;
}
.mt-40 {
margin-top: 40rpx;
}
.mt-50 {
margin-top: 50rpx;
}
.mb-25 {
margin-bottom: 25rpx;
}
.mb-30 {
margin-bottom: 30rpx;
}
.mb-40 {
margin-bottom: 40rpx;
}
.my-10 {
margin-top: 10rpx;
margin-bottom: 10rpx;
}
.my-15 {
margin-top: 15rpx;
margin-bottom: 15rpx;
}
.my-20 {
margin-top: 20rpx;
margin-bottom: 20rpx;
}
.my-25 {
margin-top: 25rpx;
margin-bottom: 25rpx;
}
.mx-10 {
margin-left: 10rpx;
margin-right: 10rpx;
}
.mx-15 {
margin-left: 15rpx;
margin-right: 15rpx;
}
.mx-20 {
margin-left: 20rpx;
margin-right: 20rpx;
}
.mx-25 {
margin-left: 25rpx;
margin-right: 25rpx;
}
.mx-40 {
margin-left: 40rpx;
margin-right: 40rpx;
}
.mb-15 {
margin-bottom: 15rpx;
}
.mb-20 {
margin-bottom: 20rpx;
}
.mr-10 {
margin-right: 10rpx;
}
.mr-15 {
margin-right: 15rpx;
}
.ml-20 {
margin-left: 20rpx;
}
.mr-20 {
margin-right: 20rpx;
}
.mr-25 {
margin-right: 25rpx;
}
.mr-35 {
margin-right: 35rpx;
}
.text-15 {
font-size: 15rpx;
}
.text-18 {
font-size: 18rpx;
}
.text-20 {
font-size: 20rpx;
line-height: 20rpx;
}
.text-22 {
font-size: 22rpx;
line-height: 22rpx;
}
.text-24 {
font-size: 24rpx;
line-height: 24rpx;
}
.text-25 {
font-size: 25rpx;
line-height: 25rpx;
}
.text-26 {
font-size: 26rpx;
line-height: 26rpx;
}
.text-28 {
font-size: 28rpx;
line-height: 28rpx;
}
.text-30 {
font-size: 30rpx;
line-height: 30rpx;
}
.text-35 {
font-size: 35rpx;
line-height: 35rpx;
}
.text-40 {
font-size: 40rpx;
line-height: 40rpx;
}
.text-50 {
font-size: 50rpx;
line-height: 50rpx;
}
.text-60 {
font-size: 60rpx;
line-height: 60rpx;
}
.rounded {
border-radius: 10px;
}
.rounded-16 {
border-radius: 16rpx;
}
.rounded-bottom {
border-radius: 0 0 10px 10px;
}
.rounded-top {
border-radius: 10px 10px 0 0;
}
.border-top {
border-top: 1px solid $gray-light;
}
.border-bottom {
border-bottom: 1px solid $gray-light;
}
.border-bottom-weight {
border-bottom: 1px solid $gray-weight;
}
.border-right {
border-right: 1px solid $gray-light;
}
.border {
border: 1px solid $gray;
}
.canvas-hide {
//position: fixed;
//right: 100vw;
//bottom: 100vh;
//z-index: -9999;
//opacity: 0;
}
.card {
@extend .rounded;
@extend .bg-white;
@extend .p-20;
}
.footer {
position: fixed;
left: 0;
bottom: 0;
@extend .w-100p;
z-index: 10;
}
.public-sub-btn {
background: $fdca00;
font-weight: bold;
color: #000;
border-radius: 50rpx;
text-align: center;
padding: 24rpx 0;
}
.b-20 {
bottom: 20rpx;
}
.p-button {
background: linear-gradient(#E5CB98, #FBEDBC);
color: #B68320;
}
@font-face {
font-family: "iconfont";
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAeYAAsAAAAADlAAAAdLAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEAgqOYItrATYCJAMkCxQABCAFhG0HcBv/CzOjdoNyEiD7nwnxpstuRCLrGmPTaffv/hnWZJHUNtWZeOD/3t03mks73vmC/3jA8SRom0aatimgfv7d9M8lBEJCIHRBKua0E7EEOqedMBEJm8N7js0MWpgq9PlMkGcTsS8NgH3X/AEbFaFGZNFvH+xR2uYofWlu9NO9ypmTgvNlW8CitMbdT7rHpgAXaKxBOfzWBdQCFgyrMV3kKtMLUFGd7GEC0JSkACq79OKAIMbDAW2W48z1QESSiQsUARGRZFyYAZ0AR8Q1ogsAjs7vhy+UBQIgwhPwR83HdB4F7R6gR25M+CrAUEwAobtM6LuBBBRA1qlLZvYO80KFg8isxmImAH1xHwzc0UPpQ/ph9cNLD+8+cn/9mnAgGQwUGkVj0B1kUhL4EP94IgQIVeCoDc62pg7uyLCRwUMCauARlsQ0ElWAq5EoAV9CogB8FzYieLq7qQM0rM5DYAriAik/Li6hNpHBj2knBBuokIJWymUizhppEknSNKNTIHnPfnR5WRIjFnmB0MgyTh9CFr9W5WgCNNfq00hdfi0KEVVL7I0kQvMYjy8OUbDAQIFwzDiGGzMKX+/PVu1sih2FbLk8PneQ0e84zT9a9GckbXu06x/h1C0hw45Twmlb0BLgUtCw7qqMfsqCGhV6bZl8tzTOhwXIwI1ZQCJLIIvccUoHE88h4XC2eGu4M/1XNB3fedRypMHlpyhbEwA5zn0qQ+4JIFxpmvQRIqHR6kOYxT8yRF6DufwjDl1JEG+8Wqk8ej0Z33StarLSdvb0fhAL+06dIRXWc4EDCLccDJ7nRTRGNUgi5S3sUk8hG4BAIuuqdJzCcXaWtWpZK0O7I0Mqs9SeBk6HJs+pMZ3cqWSo18Up8nh2vcql1drvYnRZfFaWawwlbAjnNuUeD0fz47f2GNsa/fF7o5EiX96JqiMhfWMOZ3c32aoWarUuu1GgZb3ZijxTszPBoebYYVU51WtjNSTXad3ekZzB2YUmmynf7Frv87CjOrjBApsDIHqPD//DhUKGSMSAEKRwBgqH+XDUGI0YIlaOKiYk2EnSqUEWF7XAageI3OVCf/PhsDEaNSKnhrSzKBTiQlVdDbJsPEl0ONSUS4ssTnLO4dOJ8O/y7lwLIsG9w6MxwIZTFYojgSR8c7B6ksJqZ8UOB6W0ubb0SifPuQb42mUpNFyJuQI0OLvELTPRSN5ODs3CBUKIBoDa1xrz1K/SNy3fVPVDMKK2XqdM6a9QLFycnZWRVUJ89QUvJOjZoAOfr7zKhGDrb79CEfP5M8/DTEvPngRh8AWBr9OZ66+89rX3tVtZ8tVf0r2fhur6+fMn0ALooJU7KIuS79+fpFNWX018UNVONCAU6vv7QGWHX5rbxpdvCW5JI9sFt9aUVW1pjXfr1K+5X6dOeOsts8vm/p1Iq+glCpUiObh4EVm2JbClPL5V603DrqjoTQomnlFsolUURBISwDpcroJ7b0oA02NQonc6VOv1iZVzBiYiduCcysTgHXF6OAN6GftRd0b3kZV9q0+AxEQ+IRESEvhEqIl262o2d+ZSUQfnmQcNY2dMXbp06rKxDTkJDJeW6vN3QmnfdO+etSJLmp0tSazIHjphQaZo7r6Dq2MZ3eom36nkLlp5St+X1jcrBkv4xK/79qbGfer3tXOWL0+NzJUNjuev1m2r8TwarGszs8uaVXMJRufavYvjGRWXNvLMw4a6hqnTp+OWddN3rFg+ixl4/IR5XXolag7ZzhxpDtvDmd17wTeo3HzocG+79mhzQ6GYS6SY3AUFNu1aUC5jsE6YcVIdLZk+YIqhI161tOWSVwtt2jUJey9Kv5VI+tWYJCCe8U3j1Nhp6t/ry8zF48oidd2GdLkxpPOAeiG9UXgmkpyh9YWSltIkJvUm3/2XckNk/emn1TPGhuRv5ddp5qpQ5XLRDWCzQqyzQ4tWrMxPsIRfxsInjYr7g9evq5O7w5KQAvAPYk1YW0p4kkSoGpozaS3WThNOfixfE8B+wzrpbqcdWAzzu1akq+jGw+IgeIpNPUYoW30gqPdHzI3c6qeif0AMzVuoE4HK3keDt+KE/PXzUOM3K4anQW5D40VTGYGmWAAeCflDN7ulJpW9TyBKHUAklQgJIYOROQVQQamAKkJbaMrX9fKWFqYDBmUZgJkVDBDGXhBRCAKGcdEJJzg3AKfxAiSYgAHJgFrckJIVVqPJSTBWzCD5AKVcG5mmE7ftHW1TxhL2O+o/lEBlsJjO43U3rFG6OCU87VLVgBGu4Moeh2XJ4IVzTHXqVP1xNjNZp05TrlqTVkfBWC3zDJKPPaVcm611kvj5O9qmjKVgyI/9H0qg7cNiOq/AuKG60pBT6RyedqmUacDoLVzBlTKxFNUMPnu/HFOdugaV/jijqUxVNB2eqs41gtM3LCcta4sQhsQIRxIkRQSSIRLEim8daOMprvsqcXCDRdX2cFgMy8TbcsJh6vBNMY++jmv7bXgQHHmqWy0A') format('woff2');
}
.iconfont {
flex: 1;
text-align: center;
font-family: "iconfont" !important;
font-size: 22px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-undo:before {
content: "\e607";
}
.icon-redo:before {
content: "\e606";
}
.icon-img:before {
content: "\e6e2";
}
.icon-video:before {
content: "\e798";
}
.icon-link:before {
content: "\e60d";
}
.icon-text:before {
content: "\e6ce";
}
.icon-clear:before {
content: "\e637";
}
.icon-save:before {
content: "\e501";
}
.required {
@extend .pos-a;
left: -9px;
color: #f56c6c;
line-height: 20px;
font-size: 20px;
top: 15px;
}
.overflow-y {
overflow-y: auto;
}
.overflow-x {
overflow-x: auto;
}
.album-item {
width: 190rpx;
height: 190rpx;
@extend .m-10;
@extend .flex;
@extend .justify-center;
@extend .items-center;
}
.del-wrap {
@extend .pos-a;
right: 0;
top: 0;
border-radius: 0 10px 0 10px;
padding: 10rpx;
background-color: $red;
z-index: 1000;
}
.min-height {
min-height: 100vh;
}
.share-btn {
border: none;
background: none;
margin: 0;
padding: 0;
&::after {
border: none;
}
}
.popup-close {
bottom: -80rpx;
left: calc(50% - 20rpx);
}
+388
View File
@@ -0,0 +1,388 @@
//栏目
.navbox {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
padding: 30rpx 0;
.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin: 0rpx 26rpx;
width: 168rpx;
height: 144rpx;
border-radius: 24rpx;
background: #ffffff;
.icon {
width: 68rpx;
height: 68rpx;
border-radius: 50%;
image{
width: 100%;
height: 100%;
}
}
.text {
margin-top: 10rpx;
font-size: 28rpx;
font-weight: 500;
line-height: 40rpx;
color: #333333;
text-align: center;
}
}
.item:nth-child(1) {
background: #dcf8f9;
}
.item:nth-child(2) {
background: #e6fff1;
}
.item:nth-child(3) {
background: #f7e6ff;
}
}
//置顶公共css
.top-list-box {
padding: 30rpx 0rpx;
.item {
padding: 20rpx 30rpx;
border-bottom: 1px solid #efefef;
.user {
display: flex;
justify-content: flex-start;
align-items: center;
.hd {
width: 80rpx;
height: 80rpx;
border-radius: 8rpx;
overflow: hidden;
background: red;
}
.info {
flex: 1;
flex-wrap: nowrap;
padding-left: 20rpx;
}
}
.left,.right {
display: flex;
justify-content: flex-start;
align-items: center;
}
.one {
display: flex;
justify-content: space-between;
align-items: center;
.name {
font-size: 32rpx;
line-height: 44rpx;
color: #53667f;
}
.dage {
display: flex;
justify-content: flex-start;
align-items: center;
margin-left: 10rpx;
padding: 0 20rpx;
height: 40rpx;
border-radius: 20rpx;
background: #ff5299;
.sex {
width: 32rpx;
height: 32rpx;
background: red;
}
.age {
margin-left: 6rpx;
font-size: 24rpx;
color: #ffffff;
}
}
.real {
width: 96rpx;
height: 40rpx;
}
}
.two {
margin-top: 10rpx;
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 28rpx;
line-height: 32rpx;
.xu {
display: inline-block;
padding: 0 8rpx;
font-size: 24rpx;
line-height: 36rpx;
border-radius: 10rpx;
background: #fdca00;
}
.price {
padding: 0 20rpx;
font-weight: 500;
color: #db0c17;
}
.dep {
color: #666666;
}
.deposit {
margin-left: 20rpx;
color: #c79655;
}
}
.content {
margin-top: 10rpx;
padding-left: 100rpx;
.title {
font-size: 32rpx;
line-height: 44rpx;
color: #333333;
}
.desc {
font-size: 24rpx;
line-height: 32rpx;
color: #999999;
}
.imgbox {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
padding: 20rpx 0;
.i {
margin-top: 10rpx;
margin-right: 10rpx;
width: 180rpx;
height: 180rpx;
overflow: hidden;
}
}
.other {
display: flex;
justify-content: flex-start;
align-items: center;
.icon {
width: 30rpx;
height: 30rpx;
background: red;
}
.text {
padding: 0 20rpx 0 10rpx;
font-size: 24rpx;
line-height: 32rpx;
color: #999999;
}
.read {
font-size: 24rpx;
line-height: 32rpx;
color: greenyellow;
}
}
}
}
}
//闲置物品
.idle-list-box {
margin: 20rpx 0 10rpx;
.item {
overflow: hidden;
.img {
position: relative;
.credit{
padding: 6rpx;
color: #F19947;
position: absolute;
top: 16rpx;
left: 0;
}
.edit-btn{
color: #F19947;
position: absolute;
top: 16rpx;
right: 16rpx;
}
.goods-level{
color: #F19947;
position: absolute;
bottom: 16rpx;
right: 16rpx;
}
}
.msg-box{
padding: 20rpx;
background-color: #fff;
}
.desc{
.title{
font-weight: bold;
}
.info{
font-size: 23rpx;
margin: 10rpx 0;
color: #666;
}
}
.price-box{
background-color: #F0F4FDFF;
padding: 20rpx 10rpx;
border-radius: 10rpx;
.mode-type{
.icon{
background-color: red;
width: 10rpx;
height: 10rpx;
margin-right: 5rpx;
}
font-size: 20rpx;
}
.price{
}
}
.item-bottom{
font-size: 20rpx;
display: flex;
.type{
font-size: 24rpx;
color: #F41F1B;
border: 1px solid #F41F1B;
border-radius: 8rpx;
margin-right: 5rpx;
padding: 4rpx;
}
}
}
}
//收藏夹服务人员
.favorite-service-list {
.item {
padding: 30rpx;
margin-bottom: 40rpx;
.hd {
position: relative;
//overflow: hidden;
.real {
position: absolute;
left: -38rpx;
top: -22rpx;
transform: rotate(-28deg);
z-index: 9;
}
}
.service {
.img {
}
.text {
.name {
.n {
}
.a {
}
.s {
color: #FF72AD;
width: 30rpx;
height: 30rpx;
}
}
.dage {
.i {
margin-bottom: 14rpx;
margin-right: 18rpx;
overflow: hidden;
font-size: 24rpx;
text-align: center;
border: 4rpx solid #fdc700;
border-radius: 8rpx;
padding: 4rpx 6rpx;
&:nth-child(3n) {
margin-right: 0;
}
}
}
}
}
.desc {
}
.online {
.on {
padding: 4rpx;
color: #ffffff;
border-radius: 8rpx;
background: #fdca00;
}
.location {
}
}
.number {
padding-bottom: 16rpx;
border-bottom: 1px dashed #d5d5d5;
.rate {
}
.price {
}
}
}
.item:nth-child(1) {
margin-top: 0;
}
.item:nth-child(3n) {
margin-right: 0;
}
}
//收藏夹需求信息
.demand-list{
.item{
padding: 36rpx;
}
}
.status{
color: #fff;
height: 40rpx;
width: 80rpx;
padding: 4rpx;
border-radius: 8rpx;
}
.publish{
background: #A2EF4D;;
}
.finish{
background: #CECECE;
}
//服务
.service-side {
position: absolute;
left: 0;
top: 0;
z-index: 9;
width: 160rpx;
height: 100%;
background: #f6f6f6;
.side {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100rpx;
font-size: 26rpx;
line-height: 32rpx;
}
.active {
font-weight: bold;
color: #333333;
background: #ffffff;
}
}
@@ -6,8 +6,8 @@
<view class="flex uni-tab__cart-sub-left">
<view v-for="(item,index) in options" :key="index" class="flex uni-tab__cart-button-left uni-tab__shop-cart" @click="onClick(index,item)">
<view class="uni-tab__icon">
<uni-icons :type="item.icon" size="20" color="#646566"></uni-icons>
<!-- <image class="image" :src="item.icon" mode="widthFix" /> -->
<uv-icon :name="item.icon" :size="20"></uv-icon>
<!-- <uni-icons :type="item.icon" size="20" color="#646566"></uni-icons>-->
</view>
<text class="uni-tab__text">{{ item.text }}</text>
<view class="flex uni-tab__dot-box">
@@ -4,7 +4,7 @@
@click="searchClick">
<view class="uni-searchbar__box-icon-search">
<slot name="searchIcon">
<uni-icons color="#c0c4cc" size="18" type="search" />
<uv-icon name="search" color="#c0c4cc" size="20"></uv-icon>
</slot>
</view>
<input v-if="show || searchVal" :focus="showSync" :disabled="readonly" :placeholder="placeholderText" :maxlength="maxlength"
@@ -14,7 +14,7 @@
<view v-if="show && (clearButton==='always'||clearButton==='auto'&&searchVal!=='') &&!readonly"
class="uni-searchbar__box-icon-clear" @click="clear">
<slot name="clearIcon">
<uni-icons color="#c0c4cc" size="20" type="clear" />
<uv-icon name="close" color="#c0c4cc" size="20"></uv-icon>
</slot>
</view>
</view>
@@ -92,7 +92,6 @@
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
$uv-badge-primary: $uv-primary !default;
$uv-badge-error: $uv-error !default;
$uv-badge-blank: #ffffff !default;
$uv-badge-success: $uv-success !default;
$uv-badge-info: $uv-info !default;
$uv-badge-warning: $uv-warning !default;
@@ -142,15 +141,6 @@
color: $uv-badge-primary;
}
&--blank {
background-color: $uv-badge-blank;
border: 1px solid #808080;
}
&--blank--inverted {
color: $uv-badge-blank;
}
&--error {
background-color: $uv-badge-error;
}
@@ -0,0 +1,40 @@
export default {
props: {
// item标签的名称,作为与uv-tabbar的value参数匹配的标识符
name: {
type: [String, Number, null],
default: null
},
// uv-ui内置图标或者绝对路径的图片
icon: {
icon: String,
default: ''
},
// 图标大小,默认uv-tabbar的iconSize=20
iconSize: {
type: [String, Number],
default: ''
},
// 右上角的角标提示信息
badge: {
type: [String, Number, null],
default: null
},
// 是否显示圆点,将会覆盖badge参数
dot: {
type: Boolean,
default: false
},
// 描述文本
text: {
type: String,
default: ''
},
// 控制徽标的位置,对象或者字符串形式,可以设置top和right属性
badgeStyle: {
type: [Object, String],
default: 'top: 6px;right:2px;'
},
...uni.$uv?.props?.tabbarItem
}
}
@@ -0,0 +1,141 @@
<template>
<view class="uv-tabbar-item" :style="[$uv.addStyle(customStyle)]" @tap="clickHandler">
<view class="uv-tabbar-item__icon">
<component v-if="icon" :is="icon" :style="{
color: isActive ? parentData.activeColor : parentData.inactiveColor
}"/>
<template v-else>
<slot v-if="isActive" name="active-icon"/>
<slot v-else name="inactive-icon"/>
</template>
<uv-badge
absolute
:offset="[0, dot ? '34rpx' : badge > 9 ? '14rpx' : '20rpx']"
:customStyle="badgeStyle"
:isDot="dot"
:value="badge || (dot ? 1 : null)"
:show="dot || badge > 0"
></uv-badge>
</view>
<slot name="text">
<text
class="uv-tabbar-item__text"
:style="{
color: isActive ? parentData.activeColor : parentData.inactiveColor
}"
>
{{ text }}
</text>
</slot>
</view>
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
import props from './props.js';
import * as MenuIcons from '@/api/menu-icons.ts';
import {CheckCircleOutlined} from '@ant-design/icons-vue';
/**
* TabbarItem 底部导航栏子组件
* @description 此组件提供了自定义tabbar的能力。
* @tutorial https://www.uvui.cn/components/tabbar.html
* @property {String | Number} name item标签的名称,作为与uv-tabbar的value参数匹配的标识符
* @property {String} icon uvui内置图标或者绝对路径的图片
* @property {String | Number} badge 右上角的角标提示信息
* @property {Boolean} dot 是否显示圆点,将会覆盖badge参数(默认 false )
* @property {String} text 描述文本
* @property {Object | String} badgeStyle 控制徽标的位置,对象或者字符串形式,可以设置top和right属性(默认 'top: 6px;right:2px;' )
* @property {Object} customStyle 定义需要用到的外部样式
*
* @example <uv-tabbar :value="value2" :placeholder="false" @change="name => value2 = name" :fixed="false" :safeAreaInsetBottom="false"><uv-tabbar-item text="首页" icon="home" dot ></uv-tabbar-item></uv-tabbar>
*/
export default {
name: 'uv-tabbar-item',
components: MenuIcons,
mixins: [mpMixin, mixin, props],
emits: ['click', 'change'],
data() {
return {
isActive: false, // 是否处于激活状态
parentData: {
value: null,
activeColor: '',
inactiveColor: '',
iconSize: 20
}
};
},
created() {
this.init();
},
methods: {
init() {
// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
this.updateParentData();
if (!this.parent) {
this.$uv.error('uv-tabbar-item必须搭配uv-tabbar组件使用');
}
// 本子组件在uv-tabbar的children数组中的索引
const index = this.parent.children.indexOf(this);
// 判断本组件的name(如果没有定义name,就用index索引)是否等于父组件的value参数
this.isActive = (this.name || index) === this.parentData.value;
},
updateParentData() {
// 此方法在mixin中
this.getParentData('uv-tabbar');
},
// 此方法将会被父组件uv-tabbar调用
updateFromParent() {
// 重新初始化
this.init();
},
clickHandler() {
this.$nextTick(() => {
const index = this.parent.children.indexOf(this);
const name = this.name || index;
// 点击的item为非激活的item才发出change事件
if (name !== this.parent.value) {
this.parent.$emit('change', name);
}
this.$emit('click', name);
});
}
}
};
</script>
<style lang="scss" scoped>
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
.uv-tabbar-item {
@include flex(column);
align-items: center;
justify-content: center;
flex: 1;
&__icon {
@include flex;
position: relative;
width: 150rpx;
justify-content: center;
}
&__text {
margin-top: 2px;
font-size: 12px;
color: $uv-content-color;
}
}
/* #ifdef MP */
// 由于小程序都使用shadow DOM形式实现,需要给影子宿主设置flex: 1才能让其撑开
:host {
flex: 1;
}
/* #endif */
</style>
@@ -0,0 +1,50 @@
export default {
props: {
// 当前匹配项的name
value: {
type: [String, Number, null],
default: null
},
// 是否为iPhoneX留出底部安全距离
safeAreaInsetBottom: {
type: Boolean,
default: true
},
// 是否显示上方边框
border: {
type: Boolean,
default: true
},
// 元素层级z-index
zIndex: {
type: [String, Number],
default: 9
},
// 选中标签的颜色
activeColor: {
type: String,
default: '#1989fa'
},
// 未选中标签的颜色
inactiveColor: {
type: String,
default: '#7d7e80'
},
// 是否固定在底部
fixed: {
type: Boolean,
default: true
},
// fixed定位固定在底部时,是否生成一个等高元素防止塌陷
placeholder: {
type: Boolean,
default: true
},
// 图标大小
iconSize: {
type: [String, Number],
default: 20
},
...uni.$uv?.props?.tabbar
}
}
@@ -0,0 +1,146 @@
<template>
<view class="uv-tabbar">
<view
class="uv-tabbar__content"
ref="uv-tabbar__content"
@touchmove.stop.prevent="noop"
:class="[border && 'uv-border-top', fixed && 'uv-tabbar--fixed']"
:style="[tabbarStyle]"
>
<view class="uv-tabbar__content__item-wrapper">
<slot />
</view>
<uv-safe-bottom v-if="safeAreaInsetBottom"></uv-safe-bottom>
</view>
<view
class="uv-tabbar__placeholder"
v-if="placeholder"
:style="{
height: placeholderHeight + 'px',
}"
></view>
</view>
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import props from './props.js';
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom')
// #endif
/**
* Tabbar 底部导航栏
* @description 此组件提供了自定义tabbar的能力。
* @tutorial https://www.uvui.cn/components/tabbar.html
* @property {String | Number} value 当前匹配项的name
* @property {Boolean} safeAreaInsetBottom 是否为iPhoneX留出底部安全距离(默认 true )
* @property {Boolean} border 是否显示上方边框(默认 true )
* @property {String | Number} zIndex 元素层级z-index(默认 1 )
* @property {String} activeColor 选中标签的颜色(默认 '#1989fa' )
* @property {String} inactiveColor 未选中标签的颜色(默认 '#7d7e80' )
* @property {Boolean} fixed 是否固定在底部(默认 true )
* @property {Boolean} placeholder fixed定位固定在底部时,是否生成一个等高元素防止塌陷(默认 true )
* @property {Object} customStyle 定义需要用到的外部样式
*
* @example <uv-tabbar :value="value2" :placeholder="false" @change="name => value2 = name" :fixed="false" :safeAreaInsetBottom="false"><uv-tabbar-item text="首页" icon="home" dot ></uv-tabbar-item></uv-tabbar>
*/
export default {
name: 'uv-tabbar',
mixins: [mpMixin, mixin, props],
data() {
return {
placeholderHeight: 0
}
},
computed: {
tabbarStyle() {
const style = {
zIndex: this.zIndex
}
// 合并来自父组件的customStyle样式
return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
},
// 监听多个参数的变化,通过在computed执行对应的操作
updateChild() {
return [this.value, this.activeColor, this.inactiveColor]
},
updatePlaceholder() {
return [this.fixed, this.placeholder]
}
},
watch: {
updateChild() {
// 如果updateChildren中的元素发生了变化,则执行子元素初始化操作
this.updateChildren()
},
updatePlaceholder() {
// 如果fixed,placeholder等参数发生变化,重新计算占位元素的高度
this.setPlaceholderHeight()
}
},
created() {
this.children = []
},
mounted() {
this.setPlaceholderHeight()
},
methods: {
updateChildren() {
// 如果存在子元素,则执行子元素的updateFromParent进行更新数据
this.children.length && this.children.map(child => child.updateFromParent())
},
// 设置用于防止塌陷元素的高度
async setPlaceholderHeight() {
if (!this.fixed || !this.placeholder) return
// 延时一定时间
await this.$uv.sleep(20)
// #ifndef APP-NVUE
this.$uvGetRect('.uv-tabbar__content').then(({height = 50}) => {
// 修复IOS safearea bottom 未填充高度
this.placeholderHeight = height
})
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['uv-tabbar__content'], (res) => {
const {
size
} = res
this.placeholderHeight = size.height
})
// #endif
}
}
}
</script>
<style lang="scss" scoped>
$show-border: 1;
$show-border-top: 1;
@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
.uv-tabbar {
@include flex(column);
flex: 1;
justify-content: center;
&__content {
@include flex(column);
background-color: #fff;
&__item-wrapper {
height: 50px;
@include flex(row);
}
}
&--fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
}
</style>
+90
View File
@@ -0,0 +1,90 @@
{
"id": "uv-tabbar",
"displayName": "uv-tabbar 底部导航栏 全面兼容vue3+2、app、h5、小程序等多端",
"version": "1.0.5",
"description": "底部导航栏组件提供了自定义tabbar的能力,可以满足某些需要鉴权跳转等场景。",
"keywords": [
"uv-tabbar",
"uvui",
"uv-ui",
"tabbar",
"底部导航栏"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [
"uv-ui-tools",
"uv-icon",
"uv-badge",
"uv-safe-bottom"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
View File
+20
View File
@@ -0,0 +1,20 @@
## 1.0.8(2023-12-20)
1. 优化
## 1.0.7(2023-12-20)
1. 优化
## 1.0.6(2023-12-12)
1. 修复设置current,快速点击菜单,导致死循环的BUG
## 1.0.5(2023-06-27)
修复:非联动,内容过多的情况,滚动一段距离,再切换未滚动到顶部的BUG
## 1.0.4(2023-06-13)
1. 增加scrolltolower回调函数
2. 优化
## 1.0.3(2023-06-13)
1. 优化
## 1.0.2(2023-06-13)
1. 增加hdHeight参数,避免顶部有内容计算联动不准确的BUG
2. 优化滑动触发频率,避免跳动
## 1.0.1(2023-06-04)
1. 文档说明
## 1.0.0(2023-06-04)
1. 新增垂直选项卡组件
@@ -0,0 +1,68 @@
<template>
<view
class="uv-vtabs-item"
:id="`content_${index}`"
ref="uv-vtabs-item"
>
<slot />
</view>
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom');
// #endif
export default {
name: 'uv-vtabs-item',
mixins: [mpMixin, mixin],
props: {
index: {
type: [Number,String],
default: 0
}
},
data(){
return {
// 记录item的离顶部的距离
top: 0,
// 记录item的高度
height: 0
// 是否为联动
}
},
mounted() {
this.init();
},
methods: {
async init(){
this.getParentData('uv-vtabs');
if (!this.parent) {
return this.$uv.error('uv-vtabs必须要搭配uv-vtabs-item组件使用')
}
if(!this.parent.chain) return;
await this.$uv.sleep();
this.getItemRect().then(size=>{
// 由于对象的引用特性,此处会同时生效到父组件的children数组的本实例的top属性中,供父组件判断读取
this.top = size.top;
this.height = size.height;
});
},
getItemRect(){
return new Promise(resolve => {
// #ifndef APP-NVUE
this.$uvGetRect('.uv-vtabs-item').then(size => {
resolve(size)
})
// #endif
// #ifdef APP-NVUE
const ref = this.$refs['uv-vtabs-item']
dom.getComponentRect(ref, res => {
resolve(res.size)
})
// #endif
})
}
}
}
</script>
@@ -0,0 +1,79 @@
export default {
props: {
// 列表数据
list: {
type: Array,
default: ()=>[]
},
// 从list元素对象中读取的键名,默认name
keyName: {
type: String,
default: 'name'
},
// 当前选中项
current: {
type: [Number, String],
default: 0
},
// 头部内容的高度
hdHeight: {
type: [Number, String],
default: 0
},
// 是否联动,默认开启联动
chain: {
type: Boolean,
default: true
},
// 整个列表的高度,默认auto屏幕高度
height: {
type: [Number, String],
default: 'auto'
},
// 左边列表的宽度,默认200rpx
barWidth: {
type: [Number, String],
default: '180rpx'
},
// 左边列表是否允许滚动
barScrollable: {
type: Boolean,
default: true
},
// 背景颜色 默认主题颜色 $bg-color
barBgColor: {
type: String,
default: ''
},
// 左边列表的自定义样式
barStyle: {
type: [Object, String],
default: ''
},
// 左边列表项的自定义样式
barItemStyle: {
type: [Object, String],
default: ''
},
// 左边选择项激活时的自定义样式
barItemActiveStyle: {
type: [Object, String],
default: ''
},
// 左边选择项激活时的左边线条自定义样式
barItemActiveLineStyle: {
type: [Object, String],
default: ''
},
// 菜单项中的徽标自定义样式,比如定位位置
barItemBadgeStyle: {
type: [Object, String],
default: ''
},
// 右边区域自定义样式
contentStyle: {
type: [Object, String],
default: ''
}
}
}
@@ -0,0 +1,438 @@
<template>
<view
class="uv-vtabs"
:style="[vtabsStyle]"
>
<scroll-view
class="uv-vtabs__bar"
ref="uv-vtabs__bar"
:style="[getBarStyle]"
:scroll-y="barScrollable"
:scroll-x="scrollX"
:show-scrollbar="false"
:scroll-with-animation="true"
:scroll-top="barScrollTop"
:scroll-into-view="barScrollToView"
>
<view
:class="[
'uv-vtabs__bar-item',
`uv-vtabs__bar-item--${index}`,
index == activeIndex && 'uv-vtabs__bar-item-active'
]"
:ref="`uv-vtabs__bar-item--${index}`"
v-for="(item,index) in list"
:key="index"
:id="`bar_${index}`"
:style="[itemStyle(index)]"
@tap.stop="clickHandler(index)"
>
<view
class="uv-vtabs__bar-item--line"
v-if="index == activeIndex"
:style="[$uv.addStyle(barItemActiveLineStyle)]"
></view>
<text
:class="[
'uv-vtabs__bar-item--value',
index == activeIndex && 'uv-vtabs__bar-item-active--value'
]"
:style="[itemStyle(index),textStyle(index)]"
>{{item[keyName]}}</text>
<view
class="uv-vtabs__bar-item--badge"
:style="[$uv.addStyle(barItemBadgeStyle)]"
v-if="!!(item.badge && (item.badge.show || item.badge.isDot || item.badge.value))"
>
<uv-badge
:show="!!(item.badge && (item.badge.show || item.badge.isDot || item.badge.value))"
:isDot="item.badge && item.badge.isDot || propsBadge.isDot"
:value="item.badge && item.badge.value || propsBadge.value"
:max="item.badge && item.badge.max || propsBadge.max"
:type="item.badge && item.badge.type || propsBadge.type"
:showZero="item.badge && item.badge.showZero || propsBadge.showZero"
:bgColor="item.badge && item.badge.bgColor || propsBadge.bgColor"
:color="item.badge && item.badge.color || propsBadge.color"
:shape="item.badge && item.badge.shape || propsBadge.shape"
:numberType="item.badge && item.badge.numberType || propsBadge.numberType"
:inverted="item.badge && item.badge.inverted || propsBadge.inverted"
></uv-badge>
</view>
</view>
</scroll-view>
<scroll-view
class="uv-vtabs__content"
:style="[getContentStyle,$uv.addStyle(contentStyle)]"
:scroll-y="true"
:scroll-x="scrollX"
:show-scrollbar="false"
:scroll-top="contentScrollTop"
:scroll-into-view="contentScrollTo"
:scroll-with-animation="true"
@scroll="scrollHandler"
@scrolltolower="scrolltolower"
v-if="chain"
>
<slot />
</scroll-view>
<scroll-view
v-else
class="uv-vtabs__content"
:style="[getContentStyle,$uv.addStyle(contentStyle)]"
:scroll-y="true"
:scroll-x="scrollX"
:show-scrollbar="false"
:scroll-top="contentScrollTop2"
@scrolltolower="scrolltolower"
>
<slot />
</scroll-view>
</view>
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import debounce from '@/uni_modules/uv-ui-tools/libs/function/debounce.js'
import throttle from '@/uni_modules/uv-ui-tools/libs/function/throttle.js'
import uvBadgeProps from '@/uni_modules/uv-badge/components/uv-badge/props.js'
import props from './props.js';
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom')
// #endif
/**
* 垂直选项卡
* @description 该组件兼容所有端,提供了分类展示和联动等功能
* @tutorial https://www.uvui.cn/components/vtabs.html
* @property {Array} list 选项数组,元素为对象,如[{name:'uv-ui'}](默认 [] )
* @property {String} keyName 从list元素对象中读取的键名(默认 name )
* @property {Number} current 当前选中项,从0开始(默认 0 )
* @property {Number | String} hdHeight 头部内容的高度,头部有内容必传,否则会有联动误差(默认 0 )
* @property {Boolean} chain 是否开启联动,开启后右边区域可以滑动查看内容(默认 true )
* @property {Number|String} height 整个列表的高度,默认auto或空则为屏幕高度(默认 auto屏幕高度 )
* @property {Number|String} barWidth 左边选项区域的宽度(默认 180rpx )
* @property {Boolean} barScrollable 左边选项区域是否允许滚动 (默认 true )
* @property {String} barBgColor 左边选项区域的背景颜色(默认$uv-bg-color)
* @property {Object} barStyle 左边选项区域的自定义样式 (默认{})
* @property {Object} barItemStyle 左边选项区域每个选项的自定义样式 (默认{})
* @property {Object} barItemActiveStyle 左边选项区域选中选项的自定义样式 (默认{})
* @property {Object} barItemActiveLineStyle 左边选项区域选中选项竖线条的自定义样式 (默认{})
* @property {Object} barItemBadgeStyle 左边选项区域选中选项徽标的自定义样式,主要用于设置位置 (默认{})
* @property {Object} contentStyle 右边区域自定义样式 (默认{})
* @example <uv-vtabs :list="list"><uv-vtabs-item>...</uv-vtabs-item></uv-vtabs>
*/
export default {
name: 'uv-vtabs',
mixins: [mpMixin, mixin, props],
created() {
this.children = []
},
mounted() {
this.$nextTick(()=>{
this.init(this.current);
})
},
data() {
return {
activeIndex: 0,
// 微信小程序下,scroll-view的scroll-into-view属性无法对slot中的内容的id生效,只能通过设置scrollTop的形式去移动滚动条
contentScrollTop: 0,
contentScrollTop2: 0,//针对非联动
contentScrollTo: '',
scrolling: false,
barScrolling: false,
touching: false,
hasHeight: 0,
scrollViewHeight: 0,
barScrollTop: 0,
barScrollToView: '',
timer2: 0
}
},
computed: {
scrollX(){
// #ifdef APP-NVUE
return true;
// #endif
return false;
},
vtabsStyle() {
const style = {};
style.height = this.getHeight();
return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
},
getBarStyle() {
const style = {};
style.width = this.$uv.getPx(this.barWidth, true);
style.background = this.barBgColor;
style.height = this.getHeight();
return this.$uv.deepMerge(style, this.$uv.addStyle(this.barStyle));
},
itemStyle(){
return index =>{
const style = {};
let barItemInitStyle = this.barItemStyle;
// 避免在nvue模式下,切换时候上一个选中颜色不变
if(this.barItemStyle && !this.barItemStyle?.background) {
barItemInitStyle.background = 'transparent';
}
// 是否激活的样式
const customeStyle = index === this.activeIndex ? this.$uv.addStyle(this.barItemActiveStyle) : this.$uv.addStyle(barItemInitStyle);
if (this.list[index].disabled) {
style.color = '#c8c9cc'
}
return this.$uv.deepMerge(style, customeStyle);
}
},
// nvue设置字体样式必须要text标签上进行
textStyle(){
return index=>{
const style = {};
style.width = this.$uv.getPx(this.barWidth, true);
return style;
}
},
getContentStyle() {
const style = {};
style.height = this.getHeight();
return style;
},
propsBadge() {
return uvBadgeProps
}
},
watch: {
current(newVal){
if(!this.touching)
this.$nextTick(()=>{
this.init(newVal?newVal:0);
})
},
list(newVal) {
if (newVal.length) {
this.$uv.sleep(30).then(res => {
this.resize();
})
}
},
activeIndex(newVal){
if(!this.chain) {// 解决:非联动,内容过多的情况,滚动一段距离,再切换未滚动到顶部的BUG
this.contentScrollTop2 = 0 - Math.random() * 4 - 4;
}
this.$emit('change',newVal);
}
},
methods: {
init(index){
let num = 0;
clearInterval(this.timer2);
this.timer2 = setInterval(async ()=>{
num++;
if(num>50) clearInterval(this.timer2);
if(this.children.length) {
clearInterval(this.timer2);
await this.$uv.sleep(300);
this.clickHandler(index);
}
},100)
},
// 内容滚动到底部触发
scrolltolower(){
this.$emit('scrolltolower',this.activeIndex);
},
async resize() {
// 如果list数组长度为0就不处理 || 选中目标未变则不处理
if (this.list.length == 0 || !this.barScrollable) return;
// 避免滑太快,修复位置
Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => {
this.tabsRect = tabsRect;
this.scrollViewHeight = 0
itemRect.map((item, index) => {
this.scrollViewHeight += item.height;
this.list[index].rect = item;
})
this.setBarScrollTop();
})
},
// 设置左边菜单滚动条的位置,目标:将当前的选项移到中间位置
setBarScrollTop() {
const tabRect = this.list[this.activeIndex];
const offsetTop = this.list
.slice(0, this.activeIndex)
.reduce((total, item) => {
return total + item.rect.height;
}, 0);
const scrollViewHeight = this.$uv.getPx(this.getHeight());
let barScrollTop = tabRect.rect.height / 2 + offsetTop - scrollViewHeight / 2;
// 先给一点随机值,避免出现不能滚动的BUG
barScrollTop = Math.min(barScrollTop, this.scrollViewHeight - this.tabsRect.height);
this.barScrollTop = Math.max(0, barScrollTop);
// 已经不能滚动的时候,就使用scroll-into-view的方式进行定位,避免失效
if(barScrollTop>=(this.scrollViewHeight - this.tabsRect.height)) {
this.timer && clearTimeout(this.timer);
this.timer = setTimeout(()=>{
this.barScrollToView = `bar_${this.activeIndex}`;
},400)
}
},
// 左边菜单点击
async clickHandler(currentIndex) {
if (currentIndex == this.activeIndex) return;
this.touching = true;
this.activeIndex = currentIndex;
if(this.chain) {
// 给一点随机值,避免出现不能滚动的BUG。微信端必须用此方法
this.contentScrollTop = this.children[currentIndex].top - this.$uv.getPx(this.hdHeight) - Math.random() * 4 - 4;
// #ifndef MP-WEIXIN
this.contentScrollTo = `content_${currentIndex}`;
// #endif
}
this.timer && clearTimeout(this.timer);
throttle(()=>{
this.resize();
},300,false)
debounce(() => {
this.touching = false;
}, 900)
},
// 内容滚动
scrollHandler(e) {
if (this.touching || this.scrolling) return;
// 每过一定时间取样一次,减少资源损耗以及可能带来的卡顿
this.scrolling = true;
this.$uv.sleep(80).then(() => {
this.scrolling = false;
})
const scrollTop = e.detail.scrollTop;
let children = this.children;
const len = children.length;
let top = 0;
let activeIndex = 0;
children = this.children.map((item, index) => {
if (item.height > 0) this.hasHeight = item.height;
item.height = item.height > 0 ? item.height : this.hasHeight;
const child = {
height: item.height,
top
}
// 进行累加,给下一个item提供计算依据
top += item.height;
return child;
})
for (let i = 0; i < len; i++) {
const item = children[i];
const nextItem = children[i + 1];
// 如果滚动条高度小于第一个item的top值,此时无需设置任意字母为高亮
if (scrollTop <= children[0].top) {
activeIndex = 0;
break
} else if (!nextItem) {
// 当不存在下一个item时,意味着历遍到了最后一个
activeIndex = len - 1;
break
} else if (scrollTop > item.top && scrollTop < nextItem.top) {
activeIndex = i;
break
}
}
this.activeIndex = activeIndex;
// 当前选中项索引必然来源于前后两个索引,满足才执行,避免闪烁的bug
this.timer4 && clearTimeout(this.timer4);
this.timer4 = setTimeout(()=>{
this.resize();
},100)
},
// 设置高度
getHeight() {
let height = 0;
const isEmpty = this.$uv.test.empty(this.height);
if (isEmpty || this.height=='auto') height = this.$uv.addUnit(this.$uv.sys().windowHeight);
else height = this.$uv.getPx(this.height, true);
return height;
},
// 获取导航菜单的尺寸
getTabsRect() {
return new Promise(resolve => {
this.queryRect('uv-vtabs__bar').then(size => resolve(size))
})
},
// 获取所有标签的尺寸
getAllItemRect() {
return new Promise(resolve => {
const promiseAllArr = this.list.map((item, index) => this.queryRect(
`uv-vtabs__bar-item--${index}`, true))
Promise.all(promiseAllArr).then(sizes => resolve(sizes))
})
},
// 获取各个标签的尺寸
queryRect(el, item) {
// #ifndef APP-NVUE
// $uvGetRect为uv-ui自带的节点查询简化方法,详见文档介绍:https://www.uvui.cn/js/getRect.html
// 组件内部一般用this.$uvGetRect,对外的为getRect,二者功能一致,名称不同
return new Promise(resolve => {
this.$uvGetRect(`.${el}`).then(size => {
resolve(size)
})
})
// #endif
// #ifdef APP-NVUE
// nvue下,使用dom模块查询元素高度
// 返回一个promise,让调用此方法的主体能使用then回调
return new Promise(resolve => {
dom.getComponentRect(item ? this.$refs[el][0] : this.$refs[el], res => {
resolve(res.size)
})
})
// #endif
}
}
}
</script>
<style scoped lang="scss">
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
.uv-vtabs {
@include flex;
&__bar {
background: $uv-bg-color;
&-item {
position: relative;
@include flex;
align-items: center;
justify-content: center;
padding: 35rpx 12rpx 35rpx 20rpx;
&--value {
/* #ifdef APP-NVUE */
padding: 0 12rpx;
/* #endif */
font-size: 14px;
color: $uv-content-color;
}
&-active {
background: #fff;
&--value {
color: $uv-primary;
}
}
&--line {
position: absolute;
width: 2px;
left: 0;
top: 0;
bottom: 0;
z-index: 1;
background-color: $uv-primary;
}
&--badge {
position: absolute;
top: 4px;
right: 10px;
z-index: 1;
}
}
}
&__content {
flex: 1;
background: #fff;
}
}
</style>
+87
View File
@@ -0,0 +1,87 @@
{
"id": "uv-vtabs",
"displayName": "uv-vtabs 垂直选项卡 全面兼容vue3+2、app、h5、小程序等多端",
"version": "1.0.8",
"description": "uv-vtabs 垂直分类组件主要用于分类选择,简单配置即可使用,左右自动进行联动,不用自己再去做复杂的计算,组件内部已经完成相关计算。支持联动和不联动,商品分类,灵活配置,多端兼容开箱即用。",
"keywords": [
"uv-vtabs",
"uvui",
"uv-ui",
"垂直分类",
"垂直选项卡"
],
"repository": "",
"engines": {
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [
"uv-ui-tools",
"uv-badge"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
+19
View File
@@ -0,0 +1,19 @@
## Vtabs 垂直选项卡
> **组件名:uv-vtabs**
该组件主要用于分类选择,开箱即用,简单配置参数即可使用,左右自动进行联动,不用自己再去做复杂的计算,组件内部已经完成相关计算。联动和不联动两种可选方式,联动-左右均可滚动,不联动-右边区域只会在选中时显示。
# <a href="https://www.uvui.cn/components/vtabs.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
@@ -0,0 +1,2 @@
## 1.0.0(2024-08-02)
修复bug
+6 -6
View File
@@ -24,9 +24,9 @@
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
@@ -35,9 +35,9 @@
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u",
"alipay": "u"
"tcb": "y",
"aliyun": "y",
"alipay": "y"
},
"client": {
"Vue": {
+2
View File
@@ -1,2 +1,4 @@
## 1.0.1(2024-08-02)
修复bug
## 1.0.0(2023-11-28)
新增组件
+3 -2
View File
@@ -1,7 +1,7 @@
{
"id": "ws-chat",
"displayName": "ws-chat",
"version": "1.0.0",
"version": "1.0.1",
"description": "ws-chat",
"keywords": [
"ws-chat"
@@ -36,7 +36,8 @@
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
"aliyun": "y",
"alipay": "n"
},
"client": {
"Vue": {
+2
View File
@@ -1,3 +1,5 @@
## 1.0.2(2024-08-02)
修复bug
## 1.0.1(2024-07-03)
更新最新版本
## 1.0.0(2023-11-28)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "ws-common",
"displayName": "ws-common",
"version": "1.0.1",
"version": "1.0.2",
"description": "ws-common",
"keywords": [
"ws-common"
@@ -0,0 +1,559 @@
<template>
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{label + ':'}}</span>
<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
<view class="uni-select" :class="{'uni-select--disabled':disabled}" style="min-width: 50px">
<view class="uni-select__input-box" @click="toggleSelector">
<view v-if="current" class="uni-select__input-text">{{textShow}}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder" style="font-size: 15px; margin-right: 4px;">{{typePlaceholder}}</view>
<view v-if="current && clear && !disabled" @click.stop="clearVal">
<uni-icons type="clear" color="#c0c4cc" size="24" />
</view>
<view v-else>
<uv-icon name="arrow-down" size="14"></uv-icon>
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
</view>
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" :style="getOffsetByPlacement" v-if="showSelector">
<view :class="placement=='bottom'?'uni-popper__arrow_bottom':'uni-popper__arrow_top'"></view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
<text>{{emptyTips}}</text>
</view>
<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index"
@click="change(item)">
<text :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染的下拉框组件
* @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
* @property {String} value 默认值
* @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
* @property {Boolean} clear 是否可以清空已选项
* @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
* @property {String} label 左侧标题
* @property {String} placeholder 输入框的提示文字
* @property {Boolean} disabled 是否禁用
* @property {String} placement 弹出位置
* @value top 顶部弹出
* @value bottom 底部弹出(default)
* @event {Function} change 选中发生变化触发
*/
export default {
name: "uni-data-select",
mixins: [uniCloud.mixinDatacom || {}],
props: {
localdata: {
type: Array,
default () {
return []
}
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
emptyTips: {
type: String,
default: '无选项'
},
clear: {
type: Boolean,
default: true
},
defItem: {
type: Number,
default: 0
},
disabled: {
type: Boolean,
default: false
},
// 格式化输出 用法 field="_id as value, version as text, uni_platform as label" format="{label} - {text}"
format: {
type: String,
default: ''
},
placement: {
type: String,
default: 'bottom'
}
},
data() {
return {
showSelector: false,
current: '',
mixinDatacomResData: [],
apps: [],
channels: [],
cacheKey: "uni-data-select-lastSelectedValue",
};
},
created() {
this.debounceGet = this.debounce(() => {
this.query();
}, 300);
if (this.collection && !this.localdata.length) {
this.debounceGet();
}
},
computed: {
typePlaceholder() {
const text = {
'opendb-stat-app-versions': '版本',
'opendb-app-channels': '渠道',
'opendb-app-list': '应用'
}
const common = this.placeholder
const placeholder = text[this.collection]
return placeholder ?
common + placeholder :
common
},
valueCom() {
// #ifdef VUE3
return this.modelValue;
// #endif
// #ifndef VUE3
return this.value;
// #endif
},
textShow() {
// 长文本显示
let text = this.current;
if (text.length > 10) {
return text.slice(0, 25) + '...';
}
return text;
},
getOffsetByPlacement() {
switch (this.placement) {
case 'top':
return "bottom:calc(100% + 12px);";
case 'bottom':
return "top:calc(100% + 12px);";
}
}
},
watch: {
localdata: {
immediate: true,
handler(val, old) {
if (Array.isArray(val) && old !== val) {
this.mixinDatacomResData = val
}
}
},
valueCom(val, old) {
this.initDefVal()
},
mixinDatacomResData: {
immediate: true,
handler(val) {
if (val.length) {
this.initDefVal()
}
}
},
},
methods: {
debounce(fn, time = 100) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, time)
}
},
// 执行数据库查询
query() {
this.mixinDatacomEasyGet();
},
// 监听查询条件变更事件
onMixinDatacomPropsChange() {
if (this.collection) {
this.debounceGet();
}
},
initDefVal() {
let defValue = ''
if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
defValue = this.valueCom
} else {
let strogeValue
if (this.collection) {
strogeValue = this.getCache()
}
if (strogeValue || strogeValue === 0) {
defValue = strogeValue
} else {
let defItem = ''
if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
defItem = this.mixinDatacomResData[this.defItem - 1].value
}
defValue = defItem
}
if (defValue || defValue === 0) {
this.emit(defValue)
}
}
const def = this.mixinDatacomResData.find(item => item.value === defValue)
this.current = def ? this.formatItemName(def) : ''
},
/**
* @param {[String, Number]} value
* 判断用户给的 value 是否同时为禁用状态
*/
isDisabled(value) {
let isDisabled = false;
this.mixinDatacomResData.forEach(item => {
if (item.value === value) {
isDisabled = item.disable
}
})
return isDisabled;
},
clearVal() {
this.emit('')
if (this.collection) {
this.removeCache()
}
},
change(item) {
if (!item.disable) {
this.showSelector = false
this.current = this.formatItemName(item)
this.emit(item.value)
}
},
emit(val) {
this.$emit('input', val)
this.$emit('update:modelValue', val)
this.$emit('change', val)
if (this.collection) {
this.setCache(val);
}
},
toggleSelector() {
if (this.disabled) {
return
}
this.showSelector = !this.showSelector
},
formatItemName(item) {
let {
text,
value,
channel_code
} = item
channel_code = channel_code ? `(${channel_code})` : ''
if (this.format) {
// 格式化输出
let str = "";
str = this.format;
for (let key in item) {
str = str.replace(new RegExp(`{${key}}`, "g"), item[key]);
}
return str;
} else {
return this.collection.indexOf('app-list') > 0 ?
`${text}(${value})` :
(
text ?
text :
`未命名${channel_code}`
)
}
},
// 获取当前加载的数据
getLoadData() {
return this.mixinDatacomResData;
},
// 获取当前缓存key
getCurrentCacheKey() {
return this.collection;
},
// 获取缓存
getCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
return cacheData[name];
},
// 设置缓存
setCache(value, name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
cacheData[name] = value;
uni.setStorageSync(this.cacheKey, cacheData);
},
// 删除缓存
removeCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
delete cacheData[name];
uni.setStorageSync(this.cacheKey, cacheData);
},
}
}
</script>
<style lang="scss">
$uni-base-color: #6a6a6a !default;
$uni-main-color: #333 !default;
$uni-secondary-color: #909399 !default;
$uni-border-3: #e5e5e5;
/* #ifndef APP-NVUE */
@media screen and (max-width: 500px) {
.hide-on-phone {
display: none;
}
}
/* #endif */
.uni-stat__select {
display: flex;
align-items: center;
// padding: 15px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
width: 100%;
flex: 1;
box-sizing: border-box;
}
.uni-stat-box {
width: 100%;
flex: 1;
}
.uni-stat__actived {
width: 100%;
flex: 1;
// outline: 1px solid #2979ff;
}
.uni-label-text {
font-size: 14px;
font-weight: bold;
color: $uni-base-color;
margin: auto 0;
margin-right: 5px;
}
.uni-select {
font-size: 14px;
box-sizing: border-box;
border-radius: 4px;
padding: 0 5px;
padding-left: 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
user-select: none;
/* #endif */
flex-direction: row;
align-items: center;
width: 100%;
flex: 1;
height: 35px;
&--disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.uni-select__label {
font-size: 16px;
// line-height: 22px;
height: 35px;
padding-right: 10px;
color: $uni-secondary-color;
}
.uni-select__input-box {
height: 35px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-select__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-select__input-plac {
font-size: 14px;
color: $uni-secondary-color;
}
.uni-select__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3;
padding: 4px 0;
}
.uni-select__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
/* #ifdef H5 */
@media (min-width: 768px) {
.uni-select__selector-scroll {
max-height: 600px;
}
}
/* #endif */
.uni-select__selector-empty,
.uni-select__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 35px;
font-size: 14px;
text-align: center;
/* border-bottom: solid 1px $uni-border-3; */
padding: 0px 10px;
}
.uni-select__selector-item:hover {
background-color: #f9f9f9;
}
.uni-select__selector-empty:last-child,
.uni-select__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.uni-select__selector__disabled {
opacity: 0.4;
cursor: default;
}
/* picker 弹出层通用的指示小三角 */
.uni-popper__arrow_bottom,
.uni-popper__arrow_bottom::after,
.uni-popper__arrow_top,
.uni-popper__arrow_top::after,
{
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow_bottom {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
}
.uni-popper__arrow_bottom::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-popper__arrow_top {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
bottom: -6px;
left: 10%;
margin-right: 3px;
border-bottom-width: 0;
}
.uni-popper__arrow_top::after {
content: " ";
bottom: 1px;
margin-left: -6px;
border-bottom-width: 0;
border-top-color: #fff;
}
.uni-select__input-text {
// width: 280px;
width: 100%;
color: $uni-main-color;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
.uni-select__input-placeholder {
color: $uni-base-color;
font-size: 12px;
}
.uni-select--mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 2;
}
</style>
@@ -0,0 +1,83 @@
{
"id": "ws-data-select",
"displayName": "ws-data-select",
"version": "1.0.0",
"description": "ws-data-select",
"keywords": [
"ws-data-select"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u",
"alipay": "u"
},
"client": {
"Vue": {
"vue2": "u",
"vue3": "u"
},
"App": {
"app-vue": "u",
"app-nvue": "u",
"app-uvue": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
+1
View File
@@ -0,0 +1 @@
# ws-data-select
+2
View File
@@ -0,0 +1,2 @@
## 1.0.0(2024-08-02)
外卖菜品列表
+6 -6
View File
@@ -24,9 +24,9 @@
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
@@ -35,9 +35,9 @@
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u",
"alipay": "u"
"tcb": "y",
"aliyun": "y",
"alipay": "y"
},
"client": {
"Vue": {
+2
View File
@@ -0,0 +1,2 @@
## 1.0.1(2024-08-02)
商品列表组件
+7 -7
View File
@@ -1,7 +1,7 @@
{
"id": "ws-goods",
"displayName": "ws-goods",
"version": "1.0.0",
"version": "1.0.1",
"description": "ws-goods",
"keywords": [
"ws-goods"
@@ -24,9 +24,9 @@
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
@@ -35,9 +35,9 @@
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u",
"alipay": "u"
"tcb": "y",
"aliyun": "y",
"alipay": "y"
},
"client": {
"Vue": {
+2
View File
@@ -1,3 +1,5 @@
## 1.0.3(2024-08-02)
修复bug
## 1.0.2(2024-07-02)
更新
## 1.0.1(2023-11-28)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "ws-login",
"displayName": "ws-login",
"version": "1.0.2",
"version": "1.0.3",
"description": "基于vue3开发微信小程序快捷登录组件",
"keywords": [
"小程序手机号码登录",
+2
View File
@@ -1,3 +1,5 @@
## 1.0.4(2024-08-02)
修复bug
## 1.0.3(2023-11-29)
去除边框颜色
## 1.0.2(2023-11-28)
@@ -1,48 +1,60 @@
<template>
<view class="logout" @click="onLogout">
<view size="20" class="btn">退出登录</view>
</view>
<view class="logout" @click="onLogout">
<view size="20" class="btn">退出登录</view>
</view>
</template>
<script>
export default {
name: "w-logout",
emits:['done'],
methods: {
onLogout(){
const app = this
uni.showModal({
title: '确定退出登录?',
success(o) {
if (o.confirm) {
uni.removeStorageSync('access_token')
uni.removeStorageSync('user_id')
uni.clearStorageSync()
uni.showToast({
title: '退出成功',
icon: 'success'
})
app.$emit('done','logout')
}
}
});
}
}
}
import {useCartStore} from "@/store/modules/cart";
import {
storeToRefs
} from 'pinia';
const cartStore = useCartStore();
const {
isLogin
} = storeToRefs(cartStore)
export default {
name: "w-logout",
emits: ['done'],
methods: {
onLogout() {
const app = this
uni.showModal({
title: '确定退出登录?',
success(o) {
if (o.confirm) {
uni.removeStorageSync('access_token')
uni.removeStorageSync('user_id')
uni.clearStorageSync()
uni.showToast({
title: '退出成功',
icon: 'success'
})
cartStore.isLogin = false
app.$emit('done', 'logout')
}
}
});
}
}
}
</script>
<style lang="scss" scoped>
.logout{
width: 300rpx;
margin: 0 auto;
padding: 10rpx 0 20rpx 0;
.btn {
display: flex;
justify-content: center;
background-color: #fff;
border-radius: 30rpx;
padding: 12rpx 0;
color: $uni-text-color-placeholder;
}
}
</style>
.logout {
width: 300rpx;
margin: 0 auto;
padding: 10rpx 0 20rpx 0;
.btn {
display: flex;
justify-content: center;
background-color: #fff;
border-radius: 30rpx;
padding: 12rpx 0;
color: $uni-text-color-placeholder;
}
}
</style>
+3 -2
View File
@@ -1,7 +1,7 @@
{
"id": "ws-logout",
"displayName": "ws-logout",
"version": "1.0.3",
"version": "1.0.4",
"description": "退出登录状态并清除缓存",
"keywords": [
"ws-logout",
@@ -37,7 +37,8 @@
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
"aliyun": "y",
"alipay": "n"
},
"client": {
"Vue": {
+2
View File
@@ -1,2 +1,4 @@
## 1.0.1(2024-08-02)
修复bug
## 1.0.0(2024-07-03)
1.0.0
@@ -1,25 +1,34 @@
<template>
<uni-card :border="false" :padding="0">
<div class="user-asset web-cell">
<div class="web-cell-content web-text-center" @click="navTo(`/package/user/balance-log`)">
<text class="web-text-heading">{{ money }}</text>
<text class="web-text-secondary">余额</text>
</div>
<div class="web-cell-content web-text-center" @click="navTo(`/package/user/integral`)">
<text class="web-text-heading">{{ integral }}</text>
<text class="web-text-secondary">积分</text>
</div>
<div class="web-cell-content web-text-center" @click="navTo(`/package/user/card`)">
<text class="web-text-heading">{{ cards }}</text>
<text class="web-text-secondary">会员卡</text>
</div>
<div class="web-cell-content web-text-center" @click="navTo(`/package/user/coupon`)">
<text class="web-text-heading">{{ coupon }}</text>
<text class="web-text-secondary">优惠券</text>
</div>
</div>
<w-gap height="5"></w-gap>
</uni-card>
<view class="my-asset" :style="`background: url(${config.myAssets})`">
<view class="title">
我的余额
</view>
<view class="money">
<uv-count-to :startVal="0" decimals="2" duration="100" color="#ebcf00" fontSize="20"
:endVal="data.balance"></uv-count-to>
<uv-icon name="arrow-right"></uv-icon>
<!-- <uni-icons style="color: #FFFFFF" type="right" size="20"></uni-icons>-->
</view>
<!-- <div class="user-asset web-cell">-->
<!-- <div class="web-cell-content web-text-center" @click="navTo(`/package/user/balance-log`)">-->
<!-- <text class="web-text-heading">{{ money }}</text>-->
<!-- <text class="web-text-secondary">余额</text>-->
<!-- </div>-->
<!-- <div class="web-cell-content web-text-center" @click="navTo(`/package/user/integral`)">-->
<!-- <text class="web-text-heading">{{ integral }}</text>-->
<!-- <text class="web-text-secondary">积分</text>-->
<!-- </div>-->
<!-- <div class="web-cell-content web-text-center" @click="navTo(`/package/user/card`)">-->
<!-- <text class="web-text-heading">{{ cards }}</text>-->
<!-- <text class="web-text-secondary">会员卡</text>-->
<!-- </div>-->
<!-- <div class="web-cell-content web-text-center" @click="navTo(`/package/user/coupon`)">-->
<!-- <text class="web-text-heading">{{ coupon }}</text>-->
<!-- <text class="web-text-secondary">优惠券</text>-->
<!-- </div>-->
<!-- </div>-->
<!-- <w-gap height="5"></w-gap>-->
</view>
</template>
<script>
@@ -30,6 +39,10 @@ export default {
name: 'ws-user-order',
emits: ['done'],
props: {
config: {
type: Object,
default: {}
},
isLogin: {
type: Boolean,
default: false
@@ -37,7 +50,11 @@ export default {
data: {
type: Object,
default: {}
}
},
users: {
type: Object,
default: {}
}
},
data() {
return {
@@ -62,12 +79,12 @@ export default {
},
methods: {
async reload(){
await Api.pageUserCard({sceneType: 'myCardAll'}).then(res => {
this.cards = res.count;
})
await CouponApi.data().then(res => {
this.coupon = res.toBeUsed;
})
// await Api.pageUserCard({sceneType: 'myCardAll'}).then(res => {
// this.cards = res.count;
// })
// await CouponApi.data().then(res => {
// this.coupon = res.toBeUsed;
// })
},
navTo(item) {
const app = this;
@@ -84,8 +101,27 @@ export default {
};
</script>
<style lang="scss">
.my-asset{
width: 700rpx;
height: 92rpx;
margin: 20rpx auto;
background-size: 100% !important;
background-repeat: no-repeat !important;
background-position: center !important;
color: #FFFFFF;
display: flex;
justify-content: space-between;
align-items: center;
.title{
padding-left: 30rpx;
}
.money{
display: flex;
align-items: center;
padding-right: 20rpx;
}
}
.user-asset {
padding: 16px 0;
.web-text-heading{
font-size: 40rpx;
font-weight: 400;
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "ws-my-asset",
"displayName": "ws-my-asset",
"version": "1.0.0",
"version": "1.0.1",
"description": "ws-my-asset",
"keywords": [
"ws-my-asset"
+2
View File
@@ -0,0 +1,2 @@
## 1.0.0(2024-08-02)
自定义nav-bar
@@ -0,0 +1,448 @@
<template>
<view class="uni-navbar" :class="{'uni-dark':dark, 'uni-nvue-fixed': fixed}">
<view class="uni-navbar__content"
:class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }"
:style="{ 'background-color': themeBgColor, 'border-bottom-color':themeColor }">
<status-bar v-if="statusBar"/>
<view :style="{ color: themeColor,backgroundColor: themeBgColor ,height:navbarHeight}"
class="uni-navbar__header">
<view class="uni-navbar__header-btns uni-navbar__header-btns-left"
:style="{width:leftIconWidth}">
<slot name="left">
<view class="uni-navbar__content_view">
<image :src="config.siteLogoDark" mode="widthFix" style="width: 78px"/>
</view>
<view class="site-info" v-if="!takeaway">
<view class="site-info-text">合力打造/中国品牌</view>
<view class="site-info-text">品牌连锁/服务世界</view>
</view>
<view class="uni-navbar-btn-text" @tap="onClickLeft">
<view class="tool-btn flex">
<view class="btn-list">
<text class="btn" :class="!takeaway ? 'active' : ''">首页</text>
<text class="btn" :class="takeaway ? 'active' : ''">外卖</text>
</view>
<view class="btn-bg"></view>
</view>
</view>
<view class="location" v-if="takeaway">
<uni-icons style="color: #FFFFFF" type="location" color="#ffffff" size="20"></uni-icons>
<text>五象航洋城</text>
</view>
</slot>
</view>
<view class="uni-navbar__header-container " @tap="onClickTitle">
<slot>
<view class="uni-navbar__header-container-inner" v-if="title.length>0">
<text class="uni-nav-bar-text uni-ellipsis-1"
:style="{color: themeColor }">{{ title }}
</text>
</view>
</slot>
</view>
<view @click="onClickRight" class="uni-navbar__header-btns uni-navbar__header-btns-right"
:style="{width:rightIconWidth}">
<slot name="right">
<view v-if="rightIcon.length">
<uni-icons :color="themeColor" :type="rightIcon" size="22"/>
</view>
<view class="uni-navbar-btn-text" v-if="rightText.length && !rightIcon.length">
<text class="uni-nav-bar-right-text" :style="{ color: themeColor}">{{ rightText }}</text>
</view>
</slot>
</view>
</view>
</view>
<!-- #ifndef APP-NVUE -->
<view class="uni-navbar__placeholder" v-if="fixed">
<status-bar v-if="statusBar"/>
<view class="uni-navbar__placeholder-view" :style="{ height:navbarHeight}"/>
</view>
<!-- #endif -->
</view>
</template>
<script>
import statusBar from "./ws-status-bar.vue";
const getVal = (val) => typeof val === 'number' ? val + 'px' : val;
/**
*
*
* NavBar 自定义导航栏
* @description 导航栏组件,主要用于头部导航
* @tutorial https://ext.dcloud.net.cn/plugin?id=52
* @property {Boolean} dark 开启黑暗模式
* @property {String} title 标题文字
* @property {String} leftText 左侧按钮文本
* @property {String} rightText 右侧按钮文本
* @property {String} leftIcon 左侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性)
* @property {String} rightIcon 右侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性)
* @property {String} color 图标和文字颜色
* @property {String} backgroundColor 导航栏背景颜色
* @property {Boolean} fixed = [true|false] 是否固定顶部
* @property {Boolean} statusBar = [true|false] 是否包含状态栏
* @property {Boolean} shadow = [true|false] 导航栏下是否有阴影
* @property {Boolean} stat 是否开启统计标题上报
* @event {Function} clickLeft 左侧按钮点击时触发
* @event {Function} clickRight 右侧按钮点击时触发
* @event {Function} clickTitle 中间标题点击时触发
*/
export default {
name: "UniNavBar",
components: {
statusBar
},
emits: ['clickLeft', 'clickRight', 'clickTitle'],
props: {
config: {
type: Object,
default: {}
},
takeaway: {
type: Boolean,
default: false
},
dark: {
type: Boolean,
default: false
},
title: {
type: String,
default: ""
},
leftText: {
type: String,
default: ""
},
rightText: {
type: String,
default: ""
},
leftIcon: {
type: String,
default: ""
},
rightIcon: {
type: String,
default: ""
},
fixed: {
type: [Boolean, String],
default: false
},
color: {
type: String,
default: ""
},
backgroundColor: {
type: String,
default: ""
},
statusBar: {
type: [Boolean, String],
default: false
},
shadow: {
type: [Boolean, String],
default: false
},
border: {
type: [Boolean, String],
default: true
},
height: {
type: [Number, String],
default: 44
},
leftWidth: {
type: [Number, String],
default: 350
},
rightWidth: {
type: [Number, String],
default: 60
},
stat: {
type: [Boolean, String],
default: ''
}
},
computed: {
themeBgColor() {
if (this.dark) {
// 默认值
if (this.backgroundColor) {
return this.backgroundColor
} else {
return this.dark ? '#333' : '#FFF'
}
}
return this.backgroundColor || '#FFF'
},
themeColor() {
if (this.dark) {
// 默认值
if (this.color) {
return this.color
} else {
return this.dark ? '#fff' : '#333'
}
}
return this.color || '#333'
},
navbarHeight() {
return getVal(this.height)
},
leftIconWidth() {
return getVal(this.leftWidth)
},
rightIconWidth() {
return getVal(this.rightWidth)
}
},
mounted() {
if (uni.report && this.stat && this.title !== '') {
uni.report('title', this.title)
}
},
methods: {
onClickLeft() {
this.$emit("clickLeft");
},
onClickRight() {
this.$emit("clickRight");
},
onClickTitle() {
this.$emit("clickTitle");
}
}
};
</script>
<style lang="scss" scoped>
$nav-height: 44px;
.uni-nvue-fixed {
/* #ifdef APP-NVUE */
position: sticky;
/* #endif */
}
.uni-navbar {
// box-sizing: border-box;
}
.uni-nav-bar-text {
/* #ifdef APP-PLUS */
font-size: 34rpx;
/* #endif */
/* #ifndef APP-PLUS */
font-size: 16px;
/* #endif */
}
.uni-nav-bar-right-text {
font-size: 12px;
}
.uni-navbar__content {
position: relative;
// background-color: #fff;
// box-sizing: border-box;
background-color: transparent;
}
.uni-navbar__content_view {
// box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
}
.uni-navbar-btn-text {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: flex-start;
align-items: center;
line-height: 12px;
}
.uni-navbar__header {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 0 10px;
flex-direction: row;
height: $nav-height;
font-size: 12px;
}
.uni-navbar__header-btns {
/* #ifndef APP-NVUE */
overflow: hidden;
display: flex;
/* #endif */
flex-wrap: nowrap;
flex-direction: row;
// padding: 0 6px;
justify-content: center;
align-items: center;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-navbar__header-btns-left {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
width: 120rpx;
justify-content: flex-start;
align-items: center;
}
.uni-navbar__header-btns-right {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
// width: 150rpx;
// padding-right: 30rpx;
justify-content: flex-end;
align-items: center;
}
.uni-navbar__header-container {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
padding: 0 10px;
overflow: hidden;
}
.uni-navbar__header-container-inner {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 12px;
overflow: hidden;
// box-sizing: border-box;
}
.uni-navbar__placeholder-view {
height: $nav-height;
}
.uni-navbar--fixed {
position: fixed;
z-index: 998;
/* #ifdef H5 */
left: var(--window-left);
right: var(--window-right);
/* #endif */
/* #ifndef H5 */
left: 0;
right: 0;
/* #endif */
}
.uni-navbar--shadow {
box-shadow: 0 1px 6px #ccc;
}
//.uni-navbar--border {
// border-bottom-width: 1rpx;
// border-bottom-style: solid;
// border-bottom-color: #eee;
//}
.uni-ellipsis-1 {
overflow: hidden;
/* #ifndef APP-NVUE */
white-space: nowrap;
text-overflow: ellipsis;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
text-overflow: ellipsis;
/* #endif */
}
// 暗主题配置
.uni-dark {
}
.site-info{
display: flex;
flex-direction: column;
.site-info-text{
font-size: 16rpx;
line-height: .7rem;
color: #f3f3f3;
}
}
.tool-btn {
margin-left: 10rpx;
height: 50rpx !important;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
.btn-list {
width: 185rpx;
display: flex;
justify-content: start;
.btn {
line-height: 1.2rem;
color: #000000;
font-weight: 500;
border-radius: 50rpx;
display: block;
background: none;
padding: 4rpx 18rpx;
margin: 4rpx;
font-size: 24rpx;
}
.active {
color: #000000 !important;
background-color: #f3f3f3 !important;
}
}
.btn-bg {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 185rpx;
height: 50rpx;
overflow: hidden;
border-radius: 50rpx;
background-color: #FFFFFF;
opacity: .4;
}
}
.location{
margin-left: 10rpx;
color: #FFFFFF;
display: flex;
align-items: center;
}
</style>
@@ -0,0 +1,24 @@
<template>
<view :style="{ height: statusBarHeight }" class="uni-status-bar">
<slot />
</view>
</template>
<script>
export default {
name: 'UniStatusBar',
data() {
return {
statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px'
}
}
}
</script>
<style lang="scss" >
.uni-status-bar {
// width: 750rpx;
height: 20px;
// height: var(--status-bar-height);
}
</style>
+83
View File
@@ -0,0 +1,83 @@
{
"id": "ws-nav-bar",
"displayName": "ws-nav-bar",
"version": "1.0.0",
"description": "ws-nav-bar",
"keywords": [
"ws-nav-bar"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "y"
},
"client": {
"Vue": {
"vue2": "u",
"vue3": "u"
},
"App": {
"app-vue": "u",
"app-nvue": "u",
"app-uvue": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
+1
View File
@@ -0,0 +1 @@
# ws-nav-bar
+2
View File
@@ -0,0 +1,2 @@
## 1.0.0(2024-08-02)
修复bug
@@ -7,7 +7,7 @@
</button>
<!-- 其他功能 -->
<uni-card :border="false" :is-shadow="false" :padding="0">
<view class="order-body web-cell-align-top">
<uv-form labelPosition="left" :model="form" :rules="rules" ref="form">
<uv-form-item prop="form.phone" borderBottom>
@@ -50,7 +50,7 @@
text="保存" @click="save"></uv-button>
</view>
<!-- 登录组件 -->
<ws-login ref="login" :logo="logo" @done="reload" />
<ws-login ref="login" @done="reload" />
</view>
</template>
+6 -6
View File
@@ -24,9 +24,9 @@
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
@@ -35,9 +35,9 @@
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u",
"alipay": "u"
"tcb": "y",
"aliyun": "y",
"alipay": "y"
},
"client": {
"Vue": {
@@ -3,18 +3,16 @@
<view class="userinfo" v-if="form">
<view class="avatar">
<image v-if="isLogin" :src="form.avatarUrl" mode="aspectFill"></image>
<!-- <uni-icons v-else type="contact-filled" color="#f3f3f3" size="100"></uni-icons> -->
</view>
<view class="nickname-box" v-if="isLogin">
<view class="nickname">
<text class="nickname-text">{{ form.username }}</text>
<block v-for="(item, index) in data.roles" :key="index">
<uni-tag v-if="item.roleName != '注册用户'" :text="item.roleName" type="warning"/>
<uni-tag :text="item.roleName" type="warning"/>
</block>
</view>
<view class="userid">
<view class="text">{{ data.mobile }}</view>
<!-- <uni-icons custom-prefix="iconfont" color="#333333" type="icon-erweima" size="20"></uni-icons> -->
</view>
</view>
<view class="nickname-box" v-else>
@@ -22,7 +20,6 @@
</view>
</view>
<view class="tool-btn" v-if="isLogin">
<!-- <uni-icons type="gear" color="#333333" :size="28"></uni-icons> -->
</view>
</view>
<uni-popup ref="personal" type="center">
@@ -146,13 +143,13 @@ export default {
const app = this
const {form} = this
if (!uni.$uv.test.idCard(form.idCard)) {
uni.showToast({
title: '请填写真实身份证号',
icon: 'none'
})
return false
}
// if (!uni.$uv.test.idCard(form.idCard)) {
// uni.showToast({
// title: '请填写真实身份证号',
// icon: 'none'
// })
// return false
// }
UserApi.updateUsers({
phone: form.phone,
username: form.username,
@@ -232,6 +229,7 @@ export default {
.nickname-text {
margin-right: 26rpx;
color: #FFFFFF;
}
.role-name {
@@ -245,7 +243,7 @@ export default {
.text {
font-size: 24rpx;
color: #797979;
color: #808080;
margin-right: 30rpx;
}
}
@@ -1,5 +1,5 @@
<template>
<uni-card :border="false" :padding="0">
<uni-card title="我的订单" :border="false" :padding="0">
<uv-skeleton rows="1" rowsHeight="30" rowsWidth="100%" :loading="order.length == 0" :title="false">
<div class="user-oreder web-cell">
<block v-for="(item,index) in order" :key="index">
@@ -16,10 +16,10 @@
<script>
const tabBarLinks = [
'/pages/index/index',
'/pages/shop/shop',
'/pages/order/order',
'/pages/user/user'
'/pages/index',
'/pages/shop',
'/pages/order',
'/pages/user'
]
import {
openUrl
@@ -118,4 +118,4 @@
// margin-top: (@padding-xs / 2);
}
}
</style>
</style>
+4 -1
View File
@@ -3,6 +3,9 @@ page {
background-color: #f0f2f5;
}
.none {
display: none;
}
/* 单元格 */
.web-cell {
@@ -54,7 +57,7 @@ page {
}
.web-text-success {
color: #3C8618;
color: #49af10;
}
.web-text-warning {}
+4 -3
View File
@@ -1,7 +1,8 @@
/**
* 显示成功提示框
*/
export const showSuccess = (msg, callback) => {
export const showSuccess = (msg:string, callback: any) => {
uni.showToast({
title: msg,
icon: 'success',
@@ -22,7 +23,7 @@ export function createCode(): string {
/**
* 显示失败提示框
*/
export const showError = (msg, callback) => {
export const showError = (msg:string, callback:any) => {
uni.showModal({
title: '友情提示',
content: msg,
@@ -31,4 +32,4 @@ export const showError = (msg, callback) => {
callback && callback()
}
})
}
}
+1 -16
View File
@@ -1,6 +1,5 @@
import { listDictionaryData } from '@/api/system/dictionary-data';
import { ref } from 'vue';
// import { pageProject } from '@/api/oa/project';
// import { getJson } from '@/api/json';
import { APP_SECRET, FILE_SERVER } from '@/config/setting';
import { useUserStore } from '@/store/modules/user';
@@ -92,6 +91,7 @@ export const navTo = (url : string, query = {}, modo = 'navigateTo') => {
* 打开链接
*/
export const openUrl = (item : any) => {
console.log(item.path)
if (item.target == 'uni.navigateTo') {
return uni.navigateTo({
url: item.path
@@ -169,21 +169,6 @@ export const copyText = (text : string) => {
// return <any>dictOptions;
// };
// 下拉选择项目
// export const selectProject = (text : any) => {
// const data = ref<any>([]);
// pageProject({ projectName: text }).then((result) => {
// data.value = result?.list.map((d) => {
// return {
// value: d.projectId,
// label: d.projectName,
// text: d.projectName
// };
// });
// });
// return data;
// };
// 判断是否为图片
/*
* @param: fileName - 文件名称