feat 同步前端

This commit is contained in:
damonyuan
2024-10-10 14:10:49 +08:00
parent dff6804bca
commit 2864e8448f
110 changed files with 14463 additions and 10446 deletions

View File

@@ -2,18 +2,51 @@
import { onLaunch } from '@dcloudio/uni-app'
import { useAppStore } from './stores/app'
import { useUserStore } from './stores/user'
import { useThemeStore } from './stores/theme'
import { useRoute, useRouter } from 'uniapp-router-next'
const appStore = useAppStore()
const { getUser } = useUserStore()
const { getTheme } = useThemeStore()
const router = useRouter()
const route = useRoute()
//#ifdef H5
const setH5WebIcon = () => {
const config = appStore.getWebsiteConfig
let favicon: HTMLLinkElement = document.querySelector('link[rel="icon"]')!
if (favicon) {
favicon.href = config.h5_favicon
return
}
favicon = document.createElement('link')
favicon.rel = 'icon'
favicon.href = config.h5_favicon
document.head.appendChild(favicon)
}
//#endif
const getConfig = async () => {
await appStore.getConfig()
//#ifdef H5
setH5WebIcon()
//#endif
const { status, page_status, page_url } = appStore.getH5Config
if (route.meta.webview) return
//处理关闭h5渠道
//#ifdef H5
if (status == 0) {
if (page_status == 1) return (location.href = page_url)
router.reLaunch('/pages/empty/empty')
}
//#endif
}
onLaunch(async () => {
await appStore.getConfig()
// #ifdef H5
const { status, close, url } = appStore.getH5Config
if (status == 0) {
if (close == 1) return (location.href = url)
uni.reLaunch({ url: '/pages/empty/empty' })
}
// #endif
getTheme()
getConfig()
//#ifdef H5
setH5WebIcon()
//#endif
await getUser()
})
</script>

View File

@@ -1,37 +1,40 @@
import { client } from '@/utils/client'
import request from '@/utils/request'
// 登录
export function mobileLogin(data: Record<string, any>) {
return request.post({ url: '/login/mobileLogin', data })
}
// 登录
export function accountLogin(data: Record<string, any>) {
return request.post({ url: '/login/accountLogin', data })
export function login(data: Record<string, any>) {
return request.post({ url: '/login/account', data: { ...data, terminal: client } })
}
//注册
export function register(data: Record<string, any>) {
return request.post({ url: '/login/register', data })
}
//忘记密码
export function forgotPassword(data: Record<string, any>) {
return request.post({ url: '/login/forgotPassword', data })
return request.post({ url: '/login/register', data: { ...data, channel: client } })
}
//向微信请求code的链接
export function getWxCodeUrl() {
return request.get({ url: '/login/oaCodeUrl', data: { url: location.href } })
export function getWxCodeUrl(data: Record<string, any>) {
return request.get({ url: '/login/codeUrl', data })
}
// 微信小程序登录
export function OALogin(data: Record<string, any>) {
return request.post({ url: '/login/oaLogin', data })
}
export function mnpLogin(data: Record<string, any>) {
return request.post({ url: '/login/mnpLogin', data })
}
// 公众号登录
export function OALogin(data: Record<string, any>) {
return request.post({ url: '/login/oaLogin', data })
//更新微信小程序头像昵称
export function updateUser(data: Record<string, any>, header: any) {
return request.post({ url: '/login/updateUser', data, header })
}
//小程序绑定微信
export function mnpAuthBind(data: Record<string, any>) {
return request.post({ url: '/login/mnpAuthBind', data })
}
//公众号绑定微信
export function oaAuthBind(data: Record<string, any>) {
return request.post({ url: '/login/oaAuthBind', data })
}

View File

@@ -1,9 +1,8 @@
import wechatOa from '@/utils/wechat'
import request from '@/utils/request'
//发送短信
export function smsSend(data: any) {
return request.post({ url: '/index/sendSms', data: data })
return request.post({ url: '/sms/sendCode', data: data })
}
export function getConfig() {

View File

@@ -5,7 +5,7 @@ import request from '@/utils/request'
* @return { Promise }
*/
export function getArticleCate() {
return request.get({ url: '/article/category' })
return request.get({ url: '/article/cate' })
}
/**
@@ -13,7 +13,7 @@ export function getArticleCate() {
* @return { Promise }
*/
export function getArticleList(data: Record<string, any>) {
return request.get({ url: '/article/list', data: data })
return request.get({ url: '/article/lists', data: data })
}
/**
@@ -27,11 +27,11 @@ export function getArticleDetail(data: { id: number }) {
/**
* @description 加入收藏
* @param { number } articleId
* @param { number } id
* @return { Promise }
*/
export function addCollect(data: { articleId: number }) {
return request.post({ url: '/article/collectAdd', data: data }, { isAuth: true })
export function addCollect(data: { id: number }) {
return request.post({ url: '/article/addCollect', data: data }, { isAuth: true })
}
/**
@@ -39,8 +39,8 @@ export function addCollect(data: { articleId: number }) {
* @param { number } id
* @return { Promise }
*/
export function cancelCollect(data: { articleId: number }) {
return request.post({ url: '/article/collectCancel', data: data }, { isAuth: true })
export function cancelCollect(data: { id: number }) {
return request.post({ url: '/article/cancelCollect', data: data }, { isAuth: true })
}
/**
@@ -48,5 +48,5 @@ export function cancelCollect(data: { articleId: number }) {
* @return { Promise }
*/
export function getCollect() {
return request.get({ url: '/article/collectList' })
return request.get({ url: '/article/collect' })
}

View File

@@ -2,12 +2,12 @@ import request from '@/utils/request'
//充值
export function recharge(data: any) {
return request.post({ url: '/recharge/placeOrder', data }, { isAuth: true })
return request.post({ url: '/recharge/recharge', data }, { isAuth: true })
}
//充值记录
export function rechargeRecord(data: any) {
return request.get({ url: '/recharge/record', data }, { isAuth: true })
return request.get({ url: '/recharge/lists', data }, { isAuth: true })
}
// 充值配置

View File

@@ -7,7 +7,7 @@ export function getIndex() {
// 装修页面
export function getDecorate(data: any) {
return request.get({ url: '/index/decorate', data })
return request.get({ url: '/index/decorate', data }, { ignoreCancel: true })
}
/**
@@ -15,5 +15,5 @@ export function getDecorate(data: any) {
* @return { Promise }
*/
export function getHotSearch() {
return request.get({ url: '/index/hotSearch' })
return request.get({ url: '/search/hotLists' })
}

View File

@@ -1,7 +1,7 @@
import request from '@/utils/request'
export function getUserCenter(header?: any) {
return request.get({ url: '/user/center', header })
return request.get({ url: '/user/center', header }, { ignoreCancel: true })
}
// 个人信息
@@ -11,7 +11,7 @@ export function getUserInfo() {
// 个人编辑
export function userEdit(data: any) {
return request.post({ url: '/user/edit', data }, { isAuth: true })
return request.post({ url: '/user/setInfo', data }, { isAuth: true })
}
// 绑定手机
@@ -21,28 +21,21 @@ export function userBindMobile(data: any, header?: any) {
// 微信电话
export function userMnpMobile(data: any) {
return request.post({ url: '/user/mnpMobile', data }, { isAuth: true })
return request.post({ url: '/user/getMobileByMnp', data }, { isAuth: true })
}
// 更改手机号
export function userChangePwd(data: any) {
return request.post({ url: '/user/changePwd', data }, { isAuth: true })
return request.post({ url: '/user/changePassword', data }, { isAuth: true })
}
// 绑定小程序
export function mnpAuthBind(data: any) {
return request.post({ url: '/user/bindMnp', data })
}
// 绑定公众号
export function oaAuthBind(data: any) {
return request.post({ url: '/user/bindOa', data })
}
//更新微信小程序头像昵称
export function updateUser(data: Record<string, any>, header: any) {
return request.post({ url: '/user/updateUser', data, header })
//忘记密码
export function forgotPassword(data: Record<string, any>) {
return request.post({ url: '/user/resetPassword', data })
}
//余额明细
export function accountLog(data: any) {
return request.get({ url: '/logs/userMoney', data })
return request.get({ url: '/account_log/lists', data })
}

View File

@@ -32,7 +32,7 @@ const props = defineProps({
},
fileKey: {
type: String,
default: 'path'
default: 'uri'
},
size: {
type: [String, Number],
@@ -81,6 +81,7 @@ const uploadImageIng = async (file: string) => {
try {
const res: any = await uploadImage(file, userStore.temToken!)
uni.hideLoading()
console.log(res)
emit('update:modelValue', res[props.fileKey])
} catch (error) {
uni.hideLoading()

View File

@@ -0,0 +1,97 @@
<template>
<u-swiper
v-if="lists.length"
:list="lists"
:mode="mode"
:height="height"
:effect3d="effect3d"
:indicator-pos="indicatorPos"
:autoplay="autoplay"
:interval="interval"
:duration="duration"
:circular="circular"
:borderRadius="borderRadius"
:current="current"
:name="name"
:bg-color="bgColor"
@click="handleClick"
@change="handleChange"
>
</u-swiper>
</template>
<script setup lang="ts">
import {useAppStore} from "@/stores/app";
import {navigateTo, navigateToMiniProgram, LinkTypeEnum} from "@/utils/util";
import {watchEffect, computed} from "vue";
import {useRouter} from "uniapp-router-next";
const emit = defineEmits(["change"]);
const props = withDefaults(
defineProps<{
content?: any; // 轮播图数据
mode?: string; // 指示器模式 rect / dot / number / none
height?: string; // 轮播图组件高度
indicatorPos?: string; // 指示器的位置 topLeft / topCenter / topRight / bottomLeft / bottomRight
effect3d?: boolean; // 是否开启3D效果
autoplay?: boolean; // 是否自动播放
interval?: number | string; // 自动轮播时间间隔单位ms
duration?: number | string; // 切换一张轮播图所需的时间单位ms
circular?: boolean; // 是否衔接播放
current?: number; // 默认显示第几项
name?: string; // 显示的属性
borderRadius?: string; //轮播图圆角值单位rpx
bgColor?: string; // 背景颜色
}>(),
{
content: {
data: [],
},
mode: "round",
indicatorPos: "bottomCenter",
height: "340",
effect3d: false,
autoplay: true,
interval: "2500",
duration: 300,
circular: true,
current: 0,
name: "image",
borderRadius: "0",
bgColor: "#f3f4f6",
}
);
const {getImageUrl} = useAppStore();
watchEffect(() => {
try {
const content = props?.content;
const len = content?.data?.length;
if (!len) return;
for (let i = 0; i < len; i++) {
const item = content.data[i];
item.image = getImageUrl(item.image);
}
emit("change", 0);
} catch (error) {
//TODO handle the exception
console.log("轮播图数据错误", error);
}
});
const lists = computed(() => props.content.data || []);
const router = useRouter();
const handleClick = (index: number) => {
const link = props.content.data[index]?.link;
if (!link) return
navigateTo(link);
};
const handleChange = (index: number) => {
emit("change", index);
};
</script>
<style></style>

View File

@@ -79,10 +79,10 @@ const avatar = ref()
const handleSubmit = (e: any) => {
const { nickname } = e.detail.value
if (!avatar.value)
return uni.$u.toast('请添加头像')
if (!nickname)
return uni.$u.toast('请输入昵称')
if (!avatar.value)
return uni.$u.toast('请添加头像')
if (!nickname)
return uni.$u.toast('请输入昵称')
emit('update', {
avatar: avatar.value,
nickname

View File

@@ -5,19 +5,19 @@
<u-image :src="item.image" width="240" height="180"></u-image>
</view>
<view class="news-card-content flex flex-col justify-between flex-1">
<view class="news-card-content-title text-lg font-medium">{{ item.title }}</view>
<view class="news-card-content-intro text-gray-400 text-sm mt-[16rpx]">{{
item.intro
}}</view>
<view class="news-card-content-title text-base">{{ item.title }}</view>
<view class="news-card-content-intro text-gray-400 text-sm mt-[16rpx]">
{{ item.desc }}
</view>
<view class="text-muted text-xs w-full flex justify-between mt-[12rpx]">
<view>{{ item.createTime }}</view>
<view>{{ item.create_time }}</view>
<view class="flex items-center">
<image
src="/static/images/icon/icon_visit.png"
class="w-[30rpx] h-[30rpx]"
></image>
<view class="ml-[10rpx]">{{ item.visit }}</view>
<view class="ml-[10rpx]">{{ item.click }}</view>
</view>
</view>
</view>

View File

@@ -17,7 +17,7 @@
<view class="payment h-full w-full flex flex-col">
<view class="header py-[50rpx] flex flex-col items-center">
<price
:content="payData.orderAmount"
:content="payData.order_amount"
mainSize="44rpx"
minorSize="40rpx"
fontWeight="500"
@@ -30,9 +30,9 @@
<u-radio-group v-model="payWay" class="w-full">
<view
class="p-[20rpx] flex items-center w-full payway-item"
v-for="(item, index) in payData.list"
v-for="(item, index) in payData.lists"
:key="index"
@click="selectPayWay(item.id)"
@click="selectPayWay(item.pay_way)"
>
<u-icon
class="flex-none"
@@ -48,7 +48,8 @@
}}</view>
</view>
<u-radio class="mr-[-20rpx]" :name="item.id"> </u-radio>
<u-radio activeColor="var(--color-primary)" class="mr-[-20rpx]" :name="item.pay_way">
</u-radio>
</view>
</u-radio-group>
</view>
@@ -84,8 +85,8 @@
<view class="pt-[30rpx] pb-[40rpx]">
<view> 请在微信内完成支付如果您已支付成功请点击`已完成支付`按钮 </view>
</view>
<view class="flex justify-between">
<view class="w-[48%]">
<view class="flex">
<view class="flex-1 mr-[20rpx]">
<u-button
shape="circle"
type="primary"
@@ -98,7 +99,7 @@
重新支付
</u-button>
</view>
<view class="w-[48%]">
<view class="flex-1">
<u-button
shape="circle"
type="primary"
@@ -124,7 +125,6 @@ import { series } from '@/utils/util'
import { ClientEnum, PageStatusEnum, PayStatusEnum } from '@/enums/appEnums'
import { useUserStore } from '@/stores/user'
import { client } from '@/utils/client'
import { onShow } from '@dcloudio/uni-app'
/*
页面参数 orderId订单idfrom订单来源
*/
@@ -158,11 +158,10 @@ const emit = defineEmits(['update:showCheck', 'update:show', 'close', 'success',
const payWay = ref()
const popupStatus = ref(PageStatusEnum.LOADING)
const payData = ref<any>({
orderAmount: '',
list: []
order_amount: '',
lists: []
})
const payStatus = ref()
const showCheckPay = computed({
get() {
return props.showCheck
@@ -189,13 +188,13 @@ const getPayData = async () => {
popupStatus.value = PageStatusEnum.LOADING
try {
payData.value = await getPayWay({
orderId: props.orderId,
order_id: props.orderId,
from: props.from
})
popupStatus.value = PageStatusEnum.NORMAL
const checkPay =
payData.value.list.find((item: any) => item.isDefault) || payData.value.list[0]
payWay.value = checkPay?.id
payData.value.lists.find((item: any) => item.is_default) || payData.value.lists[0]
payWay.value = checkPay?.pay_way
} catch (error) {
popupStatus.value = PageStatusEnum.ERROR
}
@@ -209,7 +208,7 @@ const payment = (() => {
// 查询是否绑定微信
const checkIsBindWx = async () => {
if (
userStore.userInfo.isBindWechat == 0 &&
userStore.userInfo.is_auth == 0 &&
[ClientEnum.OA_WEIXIN, ClientEnum.MP_WEIXIN].includes(client) &&
payWay.value == PayWayEnum.WECHAT
) {
@@ -233,10 +232,10 @@ const payment = (() => {
title: '正在支付中'
})
const data = await prepay({
orderId: props.orderId,
scene: props.from,
payWay: payWay.value,
redirectUrl: props.redirect
order_id: props.orderId,
from: props.from,
pay_way: payWay.value,
redirect: props.redirect
})
return data
@@ -245,7 +244,7 @@ const payment = (() => {
//拉起支付
const payTask = async (data: any) => {
try {
const res = await pay.payment(payWay.value, data)
const res = await pay.payment(data.pay_way, data.config)
return res
} catch (error) {
return Promise.reject(error)
@@ -265,7 +264,6 @@ const { isLock, lockFn: handlePay } = useLockFn(async () => {
})
const handlePayResult = (status: PayStatusEnum) => {
payStatus.value = status
switch (status) {
case PayStatusEnum.SUCCESS:
emit('success')
@@ -278,11 +276,11 @@ const handlePayResult = (status: PayStatusEnum) => {
const queryPayResult = async (confirm = true) => {
const res = await getPayResult({
orderId: props.orderId,
order_id: props.orderId,
from: props.from
})
if (res.payStatus === 0) {
if (res.pay_status === 0) {
if (confirm == true) {
uni.$u.toast('您的订单还未支付,请重新支付')
}
@@ -312,12 +310,6 @@ watch(
immediate: true
}
)
onShow(() => {
if (payStatus.value == PayStatusEnum.PENDING) {
showPay.value = false
showCheckPay.value = true
}
})
</script>
<style lang="scss">

View File

@@ -5,7 +5,7 @@
v-bind="tabbarStyle"
:list="tabbarList"
@change="handleChange"
:hide-tab-bar="false"
:hide-tab-bar="true"
></u-tabbar>
</template>
@@ -16,18 +16,18 @@ import { computed, ref } from 'vue'
const current = ref()
const appStore = useAppStore()
const tabbarList = computed(() => {
return appStore.getTabbarConfig.map((item: any) => {
const link = JSON.parse(item.link)
return {
iconPath: item.unselected,
selectedIconPath: item.selected,
text: item.name,
link,
pagePath: link.path
}
})
return appStore.getTabbarConfig
?.filter((item: any) => item.is_show == 1)
.map((item: any) => {
return {
iconPath: item.unselected,
selectedIconPath: item.selected,
text: item.name,
link: item.link,
pagePath: item.link.path
}
})
})
const showTabbar = computed(() => {
const currentPages = getCurrentPages()
const currentPage = currentPages[currentPages.length - 1]
@@ -36,12 +36,20 @@ const showTabbar = computed(() => {
})
return current >= 0
})
const tabbarStyle = computed(() => ({
activeColor: appStore.getStyleConfig.selectedColor,
inactiveColor: appStore.getStyleConfig.defaultColor
activeColor: appStore.getStyleConfig.selected_color,
inactiveColor: appStore.getStyleConfig.default_color
}))
const nativeTabbar = [
'/pages/index/index',
'/pages/news/news',
'/pages/user/user'
]
const handleChange = (index: number) => {
const selectTab = tabbarList.value[index]
navigateTo(selectTab.link, 'reLaunch')
const navigateType = nativeTabbar.includes(selectTab.link.path) ? 'switchTab' : 'reLaunch'
navigateTo(selectTab.link, navigateType)
}
</script>

View File

@@ -8,7 +8,7 @@ export function useTouch() {
// 最小移动距离
const MIN_DISTANCE = 10
const touch = reactive({
const touch = reactive<any>({
direction: '',
deltaX: 0,
deltaY: 0,

View File

@@ -16,9 +16,9 @@
>
<view class="scroll-box" :class="{ 'tabs-scorll-flex': !isScroll }">
<view
v-for="(item, index) in list"
class="tab-item line1"
:id="'tab-item-' + index"
v-for="(item, index) in list"
:key="index"
@tap="clickTab(index)"
:style="[tabItemStyle(index)]"
@@ -63,7 +63,7 @@ import {
onMounted,
getCurrentInstance
} from 'vue'
import { useTouch } from '@/hooks/useTouch'
import { useTouch } from './hooks/useTouch'
// Touch 钩子
const { touch, resetTouchStatus, touchStart, touchMove } = useTouch()
@@ -97,7 +97,7 @@ const props = withDefaults(
top?: number | string // 吸顶顶部距离
stickyBgColor?: string // 吸顶颜色
swipeable: boolean // 是否允许滑动切换
swipeable?: boolean // 是否允许滑动切换
// animated: boolean // 切换动画
}>(),
{
@@ -106,7 +106,7 @@ const props = withDefaults(
height: 80,
fontSize: 28,
duration: 0.3,
activeColor: '#2073F4',
activeColor: 'var(--color-primary)',
inactiveColor: '#333',
barWidth: 40,
barHeight: 4,

View File

@@ -1,34 +1,27 @@
<template>
<view
class="banner h-[340rpx] bg-white translate-y-0"
class="banner translate-y-0"
:class="{ 'px-[20rpx]': !isLargeScreen }"
v-if="content.data.length && content.enabled"
>
<swiper
class="swiper h-full"
:indicator-dots="content.data.length > 1"
indicator-active-color="#4173ff"
:autoplay="true"
>
<swiper-item
v-for="(item, index) in content.data"
:key="index"
@click="handleClick(item.link)"
>
<u-image
mode="aspectFit"
width="100%"
height="100%"
:src="getImageUrl(item.image)"
/>
</swiper-item>
</swiper>
<LSwiper
:content="content"
:height="isLargeScreen ? '1100' : '321'"
:circular="true"
:effect3d="false"
:border-radius="isLargeScreen ? '0' : '14'"
interval="7000"
bgColor="transparent"
@change="handleChange"
></LSwiper>
</view>
</template>
<script setup lang="ts">
import { useAppStore } from '@/stores/app'
import { navigateTo } from '@/utils/util'
import LSwiper from '@/components/l-swiper/l-swiper.vue'
import {useAppStore} from "@/stores/app";
const emit = defineEmits(['change'])
const props = defineProps({
content: {
type: Object,
@@ -37,12 +30,14 @@ const props = defineProps({
styles: {
type: Object,
default: () => ({})
},
isLargeScreen: {
type: Boolean
}
})
const { getImageUrl } = useAppStore()
const handleClick = (link: any) => {
navigateTo(link)
const {getImageUrl} = useAppStore();
const handleChange = (index: number) => {
emit('change', getImageUrl(props['content'].data[index].bg))
}
</script>
<style></style>

View File

@@ -1,37 +1,41 @@
<template>
<view class="bg-white p-[30rpx] flex text-[#101010] font-medium text-lg">
联系我们
</view>
<view
class="customer-service bg-white flex flex-col justify-center items-center mx-[36rpx] mt-[20rpx] rounded-lg px-[110rpx] pt-[100rpx] pb-[160rpx]"
class="customer-service bg-white flex flex-col justify-center items-center mx-[36rpx] mt-[30rpx] rounded-[20rpx] px-[20rpx] pb-[100rpx]"
>
<u-image width="280" height="280" :src="getImageUrl(content.qrcode)" />
<view v-if="content.title" class="text-lg mt-[14rpx] font-medium">{{ content.title }}</view>
<view v-if="content.time" class="text-content mt-[40rpx]"
>服务时间{{ content.time }}</view
>
<view v-if="content.mobile" class="text-content mt-[14rpx] flex flex-wrap">
客服电话{{ content.mobile }}
<view
class="w-full border-solid border-0 border-b border-[#f5f5f5] p-[30rpx] text-center text-[#101010] text-base font-medium">
{{ content.title }}
</view>
<view class="mt-[60rpx]">
<!-- 这样渲染是为了能在小程序中长按识别二维码 -->
<u-parse :html="richTxt"></u-parse>
<!-- <u-image width="200" height="200" border-radius="10rpx" :src="getImageUrl(content.qrcode)"/>-->
</view>
<view v-if="content.remark" class="text-sm mt-[40rpx] font-medium">{{ content.remark }}</view>
<view v-if="content.mobile" class="text-sm mt-[24rpx] flex flex-wrap">
<!-- #ifdef H5 -->
<a class="ml-[10rpx] phone text-muted underline" :href="'tel:' + content.mobile">
拨打
<a class="ml-[10rpx] phone text-primary underline" :href="'tel:' + content.mobile">
{{ content.mobile }}
</a>
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="ml-[10rpx] phone text-muted underline" @click="handleCall">拨打</view>
<view class="ml-[10rpx] phone text-primary underline" @click="handleCall">
{{ content.mobile }}
</view>
<!-- #endif -->
</view>
<view class="mt-[100rpx] w-full">
<u-button
type="primary"
shape="circle"
@click="saveImageToPhotosAlbum(getImageUrl(content.qrcode))"
>
保存二维码图片
</u-button>
<view v-if="content.time" class="text-muted text-sm mt-[30rpx]">
服务时间{{ content.time }}
</view>
</view>
</template>
<script lang="ts" setup>
import { useAppStore } from '@/stores/app'
import { saveImageToPhotosAlbum } from '@/utils/file'
import {useAppStore} from '@/stores/app'
import { computed } from 'vue'
const props = defineProps({
content: {
@@ -44,7 +48,12 @@ const props = defineProps({
}
})
const { getImageUrl } = useAppStore()
const {getImageUrl} = useAppStore()
const richTxt = computed(() => {
const src = getImageUrl(props.content.qrcode)
return `<img src="${src}" style="width: 100px;height: 100px; border-radius: 8px" />`
})
const handleCall = () => {
uni.makePhoneCall({

View File

@@ -0,0 +1,54 @@
<template>
<view
class="banner h-[200rpx] mx-[20rpx] mt-[20rpx] translate-y-0"
v-if="showList.length && content.enabled"
>
<swiper
class="swiper h-full"
:indicator-dots="showList.length > 1"
indicator-active-color="#4173ff"
:autoplay="true"
>
<swiper-item
v-for="(item, index) in showList"
:key="index"
@click="handleClick(item.link)"
>
<u-image
mode="widthFix"
width="100%"
height="100%"
:src="getImageUrl(item.image)"
:border-radius="14"
/>
</swiper-item>
</swiper>
</view>
</template>
<script setup lang="ts">
import { useAppStore } from '@/stores/app'
import { navigateTo } from '@/utils/util'
import { computed } from 'vue'
const props = defineProps({
content: {
type: Object,
default: () => ({})
},
styles: {
type: Object,
default: () => ({})
}
})
const handleClick = (link: any) => {
navigateTo(link)
}
const { getImageUrl } = useAppStore()
const showList = computed(() => {
return props.content.data?.filter((item: any) => item.is_show == '1') || []
})
</script>
<style></style>

View File

@@ -1,31 +1,31 @@
<template>
<div class="my-service bg-white mx-[20rpx] mt-[20rpx] rounded-lg">
<div class="my-service bg-white mx-[20rpx] mt-[20rpx] rounded-lg p-[30rpx]">
<div
v-if="content.title"
class="title px-[30rpx] py-[20rpx] font-medium text-xl border-light border-solid border-0 border-b"
class="title font-medium text-lg"
>
<div>{{ content.title }}</div>
</div>
<div v-if="content.style == 1" class="flex flex-wrap pt-[40rpx] pb-[20rpx]">
<div v-if="content.style == 1" class="grid grid-cols-4 gap-x-9 gap-y-7">
<div
v-for="(item, index) in content.data"
v-for="(item, index) in showList"
:key="index"
class="flex flex-col items-center w-1/4 mb-[15px]"
class="flex flex-col items-center pt-[40rpx]"
@click="handleClick(item.link)"
>
<u-image width="52" height="52" :src="getImageUrl(item.image)" alt="" />
<div class="mt-[7px]">{{ item.name }}</div>
<div class="mt-[22rpx] text-sm">{{ item.name }}</div>
</div>
</div>
<div v-if="content.style == 2">
<div
v-for="(item, index) in content.data"
v-for="(item, index) in showList"
:key="index"
class="flex items-center border-light border-solid border-0 border-b h-[100rpx] px-[24rpx]"
@click="handleClick(item.link)"
>
<u-image width="48" height="48" :src="getImageUrl(item.image)" alt="" />
<div class="ml-[20rpx] flex-1">{{ item.name }}</div>
<div class="ml-[20rpx] flex-1 text-sm">{{ item.name }}</div>
<div class="text-muted">
<u-icon name="arrow-right" />
</div>
@@ -36,6 +36,7 @@
<script lang="ts" setup>
import { useAppStore } from '@/stores/app'
import { navigateTo } from '@/utils/util'
import { computed } from 'vue'
const props = defineProps({
content: {
@@ -51,6 +52,10 @@ const { getImageUrl } = useAppStore()
const handleClick = (link: any) => {
navigateTo(link)
}
const showList = computed(() => {
return props.content.data?.filter((item: any) => item.is_show == '1') || []
})
</script>
<style lang="scss"></style>

View File

@@ -1,22 +1,40 @@
<template>
<view class="nav pt-[30rpx] pb-[16rpx] bg-white" v-if="content.data.length && content.enabled">
<view class="nav-item flex flex-wrap">
<view
v-for="(item, index) in content.data"
:key="index"
class="flex flex-col items-center w-1/5 mb-[30rpx]"
@click="handleClick(item.link)"
>
<u-image width="41px" height="41px" :src="getImageUrl(item.image)" alt="" />
<view class="mt-[14rpx]">{{ item.name }}</view>
</view>
</view>
</view>
<div class="relative mx-[20rpx] mt-[20rpx]">
<swiper
class="py-[20rpx] bg-white rounded-lg"
:style="{
height: navList[0].length > content.per_line ? '288rpx' : '132rpx'
}"
:autoplay="false"
:indicator-dots="false"
@change="swiperChange"
>
<swiper-item v-for="(sItem, sIndex) in navList" :key="sIndex">
<view class="nav" v-if="navList.length && content.enabled">
<view
class="grid grid-rows-auto gap-y-3 w-full"
:style="{ 'grid-template-columns': `repeat(${content.per_line}, 1fr)` }"
>
<view
v-for="(item, index) in sItem"
:key="index"
class="flex flex-col items-center"
@click="handleClick(item.link)"
>
<u-image width="82" height="82" :src="getImageUrl(item.image)" alt=""/>
<view class="mt-[14rpx] text-xs">{{ item.name }}</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</div>
</template>
<script setup lang="ts">
import { useAppStore } from '@/stores/app'
import { navigateTo } from '@/utils/util'
import {ref, watch, computed} from 'vue'
import {useAppStore} from '@/stores/app'
import {navigateTo, sliceArray} from '@/utils/util'
const props = defineProps({
content: {
@@ -29,10 +47,29 @@ const props = defineProps({
}
})
const {getImageUrl} = useAppStore()
const swiperCurrent = ref<number>(0)
const navList = ref<Record<string, any>>([])
const pagesNum = computed<number>(() => {
return props.content.per_line * props.content.show_line
})
watch(
() => props.content.data,
(val) => {
const num = props.content.style === 1 ? val.length : pagesNum.value
navList.value = sliceArray(val, num)
console.log(navList.value)
},
{deep: true, immediate: true}
)
const handleClick = (link: any) => {
navigateTo(link)
}
const { getImageUrl } = useAppStore()
</script>
<style></style>
const swiperChange = (e: any) => {
swiperCurrent.value = e.detail.current
}
</script>

View File

@@ -1,13 +1,93 @@
<template>
<!-- #ifndef H5 -->
<u-sticky h5-nav-height="0" bg-color="transparent">
<u-navbar
:class="{ 'fixed top-0 z-10': isLargeScreen }"
:is-back="false"
:is-fixed="true"
:title="metaData.title"
:custom-title="metaData.title_type == 2"
:border-bottom="false"
:title-bold="true"
:background="{ background: 'rgba(256,256, 256, 0)' }"
:title-color="percent > 0.5 ? '#000' : metaData.text_color == 1 ? '#fff' : '#000'"
>
<template #default>
<navigator
url="/pages/search/search"
class="mini-search"
hover-class="none"
:style="{ opacity: isLargeScreen ? 1 : percent }"
>
<u-icon name="search"></u-icon>
</navigator>
</template>
<template #title>
<image
class="!h-[54rpx]"
:src="metaData.title_img"
mode="widthFix"
></image>
</template>
</u-navbar>
</u-sticky>
<!-- #endif -->
<navigator
v-if="!isLargeScreen"
url="/pages/search/search"
class="search px-[24rpx] py-[14rpx] bg-white"
class="px-[24rpx] mt-[24rpx] mb-[30rpx]"
:style="{ opacity: 1 - percent }"
hover-class="none"
>
<u-search placeholder="请输入关键词搜索" disabled :show-action="false"></u-search>
<u-search
placeholder="请输入关键词搜索"
:height="72"
:disabled="true"
:show-action="false"
bgColor="#ffffff"
></u-search>
</navigator>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import {computed} from "vue";
<style></style>
const props = defineProps({
pageMeta: {
type: Object,
default: () => []
},
content: {
type: Object,
default: () => ({})
},
styles: {
type: Object,
default: () => ({})
},
isLargeScreen: {
type: Boolean
},
percent: {
type: Number
}
})
const metaData: any = computed(() => {
return props.pageMeta[0].content
})
</script>
<style scoped>
.mini-search {
display: flex;
align-items: center;
justify-content: center;
width: 60rpx;
height: 60rpx;
margin-left: 20rpx;
background-color: #ffffff;
border-radius: 50%;
box-shadow: 0 0 6px rgba(0, 0, 0, 0.2);
}
</style>

View File

@@ -1,21 +1,21 @@
<template>
<view
class="banner h-[200rpx] mx-[20rpx] mt-[20rpx] translate-y-0"
v-if="content.data.length && content.enabled"
v-if="showList.length && content.enabled"
>
<swiper
class="swiper h-full"
:indicator-dots="content.data.length > 1"
:indicator-dots="showList.length > 1"
indicator-active-color="#4173ff"
:autoplay="true"
>
<swiper-item
v-for="(item, index) in content.data"
v-for="(item, index) in showList"
:key="index"
@click="handleClick(item.limk)"
@click="handleClick(item.link)"
>
<u-image
mode="aspectFit"
mode="widthFix"
width="100%"
height="100%"
:src="getImageUrl(item.image)"
@@ -29,6 +29,7 @@
<script setup lang="ts">
import { useAppStore } from '@/stores/app'
import { navigateTo } from '@/utils/util'
import { computed } from 'vue'
const props = defineProps({
content: {
@@ -44,6 +45,10 @@ const handleClick = (link: any) => {
navigateTo(link)
}
const { getImageUrl } = useAppStore()
const showList = computed(() => {
return props.content.data?.filter((item: any) => item.is_show == '1') || []
})
</script>
<style></style>

View File

@@ -1,31 +1,63 @@
<template>
<view class="user-info flex px-[50rpx] justify-between py-[50rpx]">
<view
v-if="isLogin"
class="flex items-center"
@click="navigateTo('/pages/user_data/user_data')"
<view class="user-info mb-[0rpx]">
<!-- #ifndef H5 -->
<u-sticky
h5-nav-height="0"
bg-color="transparent"
>
<u-avatar :src="user.avatar" :size="120"></u-avatar>
<view class="text-white ml-[20rpx]">
<view class="text-2xl">{{ user.nickname }}</view>
<view class="text-xs mt-[18rpx]" @click.stop="copy(user.username)">
账号{{ user.username }}
<u-navbar
:is-back="false"
:is-fixed="false"
:title="metaData.title"
:custom-title="metaData.title_type == 2"
:border-bottom="false"
:title-bold="true"
:background="{ background: 'rgba(256,256, 256, 0)' }"
:title-color="$theme.navColor"
>
<template #title>
<image
class="!h-[54rpx]"
:src="metaData.title_img"
mode="widthFix"
></image>
</template>
</u-navbar>
</u-sticky>
<!-- #endif -->
<view class="flex items-center justify-between px-[50rpx] pb-[50rpx] pt-[40rpx]">
<view
v-if="isLogin"
class="flex items-center"
@click="navigateTo('/pages/user_data/user_data')"
>
<u-avatar :src="user.avatar" :size="120"></u-avatar>
<view class="text-white ml-[20rpx]">
<view class="text-2xl">{{ user.nickname }}</view>
<view class="text-xs mt-[18rpx]" @click.stop="copy(user.account)">
账号{{ user.account }}
</view>
</view>
</view>
<navigator v-else class="flex items-center" hover-class="none" url="/pages/login/login">
<u-avatar src="/static/images/user/default_avatar.png" :size="120"></u-avatar>
<view class="text-white text-3xl ml-[20rpx]">未登录</view>
</navigator>
<navigator v-if="isLogin" hover-class="none" url="/pages/user_set/user_set">
<u-icon name="setting" color="#fff" :size="48"></u-icon>
</navigator>
</view>
<navigator v-else class="flex items-center" hover-class="none" url="/pages/login/login">
<u-avatar src="/static/images/user/default_avatar.png" :size="120"></u-avatar>
<view class="text-white text-3xl ml-[20rpx]">未登录</view>
</navigator>
<navigator v-if="isLogin" hover-class="none" url="/pages/user_set/user_set">
<u-icon name="setting" color="#fff" :size="48"></u-icon>
</navigator>
</view>
</template>
<script lang="ts" setup>
import { useCopy } from '@/hooks/useCopy'
import {computed} from "vue";
const props = defineProps({
pageMeta: {
type: Object,
default: () => []
},
content: {
type: Object,
default: () => ({})
@@ -43,6 +75,11 @@ const props = defineProps({
}
})
const { copy } = useCopy()
const metaData: any = computed(() => {
return props.pageMeta[0].content
})
const navigateTo = (url: string) => {
uni.navigateTo({
url
@@ -52,9 +89,10 @@ const navigateTo = (url: string) => {
<style lang="scss" scoped>
.user-info {
background: url('../../../static/images/user/my_topbg.png');
height: 115px;
background: url(../../../static/images/user/my_topbg.png),
linear-gradient(90deg, $u-type-primary, $u-minor-color);
background-repeat: no-repeat;
background-position: bottom;
background-size: 100% auto;
background-size: 100%;
}
</style>

View File

@@ -0,0 +1,23 @@
import { isDevMode } from "@/utils/env";
const envBaseUrl = import.meta.env.VITE_APP_BASE_URL || "";
let baseUrl = `${envBaseUrl}/`;
/*
* 微信小程序在`VITE_APP_BASE_URL`存在或`dev`模式下
* 使用`VITE_APP_BASE_URL`的值
* 其他情况使用`[baseUrl]`,方便服务端替换
*/
//#ifdef MP-WEIXIN
baseUrl = isDevMode() || envBaseUrl ? baseUrl : "[baseUrl]";
//#endif
const config = {
version: "1.9.0", //版本号
baseUrl, //请求接口域名
urlPrefix: "api", //请求默认前缀
timeout: 60 * 1000, //请求超时时长
};
export default config;

View File

@@ -14,10 +14,10 @@ export enum ClientEnum {
}
export enum SMSEnum {
LOGIN = 101,
BIND_MOBILE = 102,
CHANGE_MOBILE = 103,
FIND_PASSWORD = 104
LOGIN = 'YZMDL',
BIND_MOBILE = 'BDSJHM',
CHANGE_MOBILE = 'BGSJHM',
FIND_PASSWORD = 'ZHDLMM'
}
export enum SearchTypeEnum {
@@ -28,7 +28,7 @@ export enum SearchTypeEnum {
export enum FieldType {
NONE = '',
AVATAR = 'avatar',
USERNAME = 'username',
USERNAME = 'account',
NICKNAME = 'nickname',
SEX = 'sex'
}
@@ -46,4 +46,4 @@ export enum PageStatusEnum {
NORMAL = 'normal', // 正常
ERROR = 'error', // 异常
EMPTY = 'empty' // 为空
}
}

View File

@@ -7,3 +7,5 @@ export const TOKEN_KEY = 'token'
export const HISTORY = 'history'
export const BACK_URL = 'back_url'
export const PAY_STATUS_EVENT = 'event:payStatus'

View File

@@ -11,20 +11,9 @@ export enum RequestMethodsEnum {
}
export enum RequestCodeEnum {
SUCCESS = 200, //成功
FAILED = 300, // 失败
PARAMS_VALID_ERROR = 310, //参数校验错误
PARAMS_TYPE_ERROR = 311, //参数类型错误
REQUEST_METHOD_ERROR = 312, //请求方法错误
ASSERT_ARGUMENT_ERROR = 313, //断言参数错误
ASSERT_MYBATIS_ERROR = 314, //断言mybatis错误
LOGIN_ACCOUNT_ERROR = 330, //登陆账号或密码错误
LOGIN_DISABLE_ERROR = 331, //登陆账号已被禁用
TOKEN_EMPTY = 332, // TOKEN参数为空
TOKEN_INVALID = 333, // TOKEN参数无效
NO_PERMISSTION = 403, //无相关权限
REQUEST_404_ERROR = 404, //请求接口不存在
SYSTEM_ERROR = 500 //系统错误
SUCCESS = 1, //成功
FAILED = 0, // 失败
TOKEN_INVALID = -1 // TOKEN参数无效
}
export enum RequestErrMsgEnum {

View File

@@ -1,15 +1,14 @@
import { createSSRApp } from 'vue'
import App from './App.vue'
import plugins from './plugins'
import { setupRouter } from './router'
import router from './router'
import './styles/index.scss'
import { setupMixin } from './mixins'
export function createApp() {
const app = createSSRApp(App)
Promise.resolve().then(() => {
setupRouter()
})
setupMixin(app)
app.use(plugins)
app.use(router)
return {
app
}

View File

@@ -52,8 +52,11 @@
"mp-weixin" : {
"appid" : "wx386a75e518b38935",
"setting" : {
"urlCheck" : false
"urlCheck" : false,
"es6" : true,
"minified" : true
},
"__usePrivacyCheck__": true,
"usingComponents" : true
},
"mp-alipay" : {
@@ -74,9 +77,6 @@
"mode" : "history",
"base" : "/mobile/"
},
"title" : "加载中",
"devServer" : {
"https" : false
}
"title" : "加载中"
}
}

View File

@@ -0,0 +1,5 @@
import { App } from 'vue'
import theme from './theme'
export function setupMixin(app: App) {
app.mixin(theme)
}

View File

@@ -0,0 +1,18 @@
import { useThemeStore } from '@/stores/theme'
import { useAppStore } from '@/stores/app'
export default {
computed: {
$theme() {
const themeStore = useThemeStore()
const appStore = useAppStore()
return {
primaryColor: themeStore.primaryColor,
pageStyle: themeStore.vars,
navColor: themeStore.navColor,
navBgColor: themeStore.navBgColor,
title: appStore.getWebsiteConfig.shop_name
}
}
}
}

View File

@@ -0,0 +1,24 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="h-screen flex flex-col justify-center items-center">
<view>
<u-empty text="对不起,您访问的页面不存在" mode="data"></u-empty>
</view>
<view class="w-full px-[100rpx] mt-[40rpx]">
<router-navigate
class="bg-primary rounded-full text-btn-text leading-[80rpx] text-center"
to="/"
nav-type="reLaunch"
>
返回首页
</router-navigate>
</view>
</view>
</template>

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="recharge p-[20rpx]">
<view class="bg-white rounded-[14rpx] p-[40rpx]">
<view class="text-content">充值金额</view>
@@ -7,12 +15,12 @@
v-model="money"
class="text-[60rpx] h-[60rpx] py-[24rpx]"
placeholder="0.00"
type="text"
type="digit"
/>
</view>
<view class="mt-[20rpx] text-xs text-muted">
当前可用余额
<text class="text-primary"> {{ wallet.userMoney }}</text>
<text class="text-primary"> {{ wallet.user_money }}</text>
</view>
</view>
<view class="mt-[40rpx]">
@@ -45,43 +53,42 @@ const money = ref('')
const payState = reactive({
orderId: '',
from: 'recharge',
from: '',
showPay: false,
showCheck: false,
redirect: '/packages/pages/recharge/recharge'
})
const wallet = reactive({
userMoney: '',
minRechargeMoney: 0
user_money: '',
min_amount: 0
})
const { isLock, lockFn: rechargeLock } = useLockFn(async () => {
const minNum = wallet.minRechargeMoney
const minNum = wallet.min_amount
if (!money.value) return uni.$u.toast('请输入充值金额')
if (minNum == 0 && Number(money.value) == minNum) {
return uni.$u.toast(`充值金额必须大于0`)
}
if (Number(money.value) < minNum) return uni.$u.toast(`最低充值金额${minNum}`)
const data = await recharge({
orderAmount: money.value,
payWay: 2
money: money.value
})
payState.orderId = data.orderId
payState.orderId = data.order_id
payState.from = data.from
payState.showPay = true
})
const handlePaySuccess = async () => {
payState.showPay = false
payState.showCheck = false
uni.navigateTo({
url: `/pages/payment_result/payment_result?id=${payState.orderId}&from=${payState.from}`
})
}
// const handlePayFail = async () => {
// uni.$u.toast('支付失败')
// }
const handlePayFail = async () => {
uni.$u.toast('支付失败')
}
const getWallet = async () => {
const data = await rechargeConfig()
@@ -90,11 +97,11 @@ const getWallet = async () => {
onLoad((options: any) => {
// h5支付用于弹起手动确认支付弹窗
// if (options?.checkPay) {
// payState.orderId = options.orderId
// payState.from = options.scene
// payState.showCheck = true
// }
if (options?.checkPay) {
payState.orderId = options.id
payState.from = options.from
payState.showCheck = true
}
})
onShow(() => {
getWallet()

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<z-paging
ref="paging"
v-model="dataList"
@@ -13,9 +21,9 @@
>
<view class="flex justify-between">
<view class="mr-2">{{ item.tips }}</view>
<view class="text-lg text-primary"> +{{ item.orderAmount }} </view>
<view class="text-lg text-primary"> +{{ item.order_amount }} </view>
</view>
<view class="text-sm text-muted mr-1">{{ item.createTime }}</view>
<view class="text-sm text-muted mr-1">{{ item.create_time }}</view>
</view>
</view>
</z-paging>

View File

@@ -1,10 +1,16 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<z-paging
ref="paging"
v-model="dataList"
@query="queryList"
:auto="false"
@onRefresh="getWallet()"
:show-loading-more-when-reload="true"
>
<view class="user-wallet">
@@ -14,10 +20,10 @@
>
<view>
<view class="text-sm">钱包余额</view>
<view class="text-[60rpx]">{{ wallet.userMoney }}</view>
<view class="text-[60rpx]">{{ wallet.user_money }}</view>
</view>
<navigator
v-if="wallet.openRecharge"
v-if="wallet.status"
url="/packages/pages/recharge/recharge"
hover-class="none"
>
@@ -31,6 +37,7 @@
:list="tabList"
:is-scroll="false"
v-model="current"
activeColor="var(--color-primary)"
@change="changeType"
></u-tabs>
@@ -41,17 +48,17 @@
class="bg-white border-solid border-b border-0 border-light px-[26rpx] py-[24rpx]"
>
<view class="flex justify-between">
<view class="mr-2">{{ item.tips }}</view>
<view class="mr-2">{{ item.type_desc }}</view>
<view
class="text-lg"
:class="{
'text-primary': item.action == 1
}"
>
{{ item.orderAmount }}
{{ item.change_amount_desc }}
</view>
</view>
<view class="text-sm text-muted mr-1">{{ item.createTime }}</view>
<view class="text-sm text-muted mr-1">{{ item.create_time }}</view>
</view>
</view>
</view>
@@ -59,14 +66,14 @@
</template>
<script lang="ts" setup>
import { nextTick, ref, shallowRef } from 'vue'
import { ref, shallowRef } from 'vue'
import { accountLog } from '@/api/user'
import { rechargeConfig } from '@/api/recharge'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { onShow } from '@dcloudio/uni-app'
const tabList = ref([
{
name: '全部',
type: 0
type: ''
},
{
name: '收入',
@@ -86,12 +93,12 @@ const changeType = (index: number) => {
paging.value.reload()
}
const queryList = async (pageNo: number, pageSize: number, from: any) => {
const queryList = async (pageNo: number, pageSize: number) => {
try {
console.log(from)
const type = tabList.value[current.value].type
const action = tabList.value[current.value].type
const data = await accountLog({
type,
action,
type: 'um',
page_no: pageNo,
page_size: pageSize
})
@@ -108,11 +115,6 @@ const getWallet = async () => {
onShow(() => {
getWallet()
})
onLoad(() => {
nextTick(() => {
paging.value?.reload()
})
})
</script>
<style lang="scss" scoped></style>

View File

@@ -3,44 +3,71 @@
{
"path": "pages/index/index",
"style": {
// #ifndef H5
"navigationStyle": "custom",
// #endif
// #ifdef H5
"navigationBarTitleText": "首页"
// #endif
}
},
{
"path": "pages/news/news",
"style": {
// #ifndef H5
"navigationStyle": "custom",
// #endif
// #ifdef H5
"navigationBarTitleText": "资讯",
// #endif
"disableScroll": true
}
},
{
"path": "pages/user/user",
"style": {
// #ifndef H5
"navigationStyle": "custom",
// #endif
// #ifdef H5
"navigationBarTitleText": "个人中心"
// #endif
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录"
},
"meta": {
"white": true
}
},
{
"path": "pages/register/register",
"style": {
"navigationBarTitleText": "注册"
},
"meta": {
"white": true
}
},
{
"path": "pages/forget_pwd/forget_pwd",
"style": {
"navigationBarTitleText": "忘记密码"
},
"meta": {
"white": true
}
},
{
"path": "pages/customer_service/customer_service",
"style": {
"navigationBarTitleText": "联系客服"
},
"meta": {
"white": true
}
},
{
@@ -54,14 +81,18 @@
"style": {
"navigationBarTitleText": "个人设置"
},
"auth": true
"meta": {
"auth": true
}
},
{
"path": "pages/collection/collection",
"style": {
"navigationBarTitleText": "我的收藏"
},
"auth": true
"meta": {
"auth": true
}
},
{
"path": "pages/as_us/as_us",
@@ -80,14 +111,18 @@
"style": {
"navigationBarTitleText": "修改密码"
},
"auth": true
"meta": {
"auth": true
}
},
{
"path": "pages/user_data/user_data",
"style": {
"navigationBarTitleText": "个人资料"
},
"auth": true
"meta": {
"auth": true
}
},
{
"path": "pages/search/search",
@@ -109,14 +144,16 @@
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/payment_result/payment_result",
"style": {
"navigationBarTitleText": "支付结果"
},
"auth": true
},
},
{
"path": "pages/payment_result/payment_result",
"style": {
"navigationBarTitleText": "支付结果"
},
"meta": {
"auth": true
}
},
{
"path": "uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper",
"style": {
@@ -124,32 +161,48 @@
"navigationBarBackgroundColor": "#000000"
}
}
],
"subPackages": [{
"root": "packages",
"pages": [
{
"path": "pages/user_wallet/user_wallet",
"style": {
"navigationBarTitleText": "我的钱包"
},
"auth": true
},
{
"path": "pages/recharge/recharge",
"style": {
"navigationBarTitleText": "充值"
},
"auth": true
},
{
"path": "pages/recharge_record/recharge_record",
"style": {
"navigationBarTitleText": "充值记录"
},
"auth": true
}
]
],
"subPackages": [{
"root": "packages",
"pages": [
{
"path": "pages/404/404",
"style": {
"navigationBarTitleText": "404"
},
"name": "404",
"meta": {
"white": true
}
},
{
"path": "pages/user_wallet/user_wallet",
"style": {
"navigationBarTitleText": "我的钱包"
},
"meta": {
"auth": true
}
},
{
"path": "pages/recharge/recharge",
"style": {
"navigationBarTitleText": "充值"
},
"meta": {
"auth": true
}
},
{
"path": "pages/recharge_record/recharge_record",
"style": {
"navigationBarTitleText": "充值记录"
},
"meta": {
"auth": true
}
}
]
}],
"globalStyle": {
"navigationBarTextStyle": "black",
@@ -160,8 +213,33 @@
"navigationStyle": "custom"
}
},
"tabBar": {
"custom": true,
"iconWidth": "20px",
"list": [
{
"iconPath": "static/images/tabbar/home.png",
"selectedIconPath": "static/images/tabbar/home_s.png",
"pagePath": "pages/index/index",
"text": "首页"
},
{
"iconPath": "static/images/tabbar/news.png",
"selectedIconPath": "static/images/tabbar/news_s.png",
"pagePath": "pages/news/news",
"text": "资讯"
},
{
"iconPath": "static/images/tabbar/user.png",
"selectedIconPath": "static/images/tabbar/user_s.png",
"pagePath": "pages/user/user",
"text": "我的"
}
]
},
"easycom": {
"custom": {
"router-navigate": "uniapp-router-next/components/router-navigate/router-navigate.vue",
"^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue",
"^w-(.*)": "@/components/widgets/$1/$1.vue"
}

View File

@@ -1,13 +1,12 @@
<template>
<view class="">
<view class="p-[30rpx]">
<u-parse :html="agreementContent"></u-parse>
</view>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { AgreementEnum } from '@/enums/agreementEnums'
import { getPolicy } from '@/api/app'
let agreementType = ref('') // 协议类型
@@ -15,12 +14,9 @@ const agreementContent = ref('') // 协议内容
const getData = async (type) => {
const res = await getPolicy({ type })
console.log(res, 'res')
agreementContent.value = res.content
uni.setNavigationBarTitle({
title: res.name
title: String(res.title)
})
}

View File

@@ -1,6 +1,14 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="as-us flex flex-1 flex-col items-center">
<image :src="appStore.config.website.logo" mode="" class="img"></image>
<image :src="appStore.getWebsiteConfig.shop_logo" mode="" class="img"></image>
<view class="text-content mt-[20rpx]">当前版本{{ appStore.config.version }}</view>
</view>
</template>

View File

@@ -1,38 +1,65 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="bg-white min-h-full flex flex-col items-center px-[40rpx] pt-[40rpx] box-border">
<view class="w-full">
<u-form borderBottom :label-width="150">
<u-form-item label="手机号" borderBottom>
<u-input
class="flex-1"
v-model="formData.mobile"
:border="false"
placeholder="请输入手机号码"
<view class="text-2xl font-medium mb-[60rpx]">绑定手机号</view>
<view
class="px-[18rpx] border border-solid border-lightc border-light rounded-[10rpx] h-[100rpx] items-center flex"
>
<u-input
class="flex-1"
v-model="formData.mobile"
:border="false"
placeholder="请输入手机号码"
/>
</view>
<view
class="px-[18rpx] border border-solid border-lightc border-light rounded-[10rpx] h-[100rpx] items-center flex mt-[40rpx]"
>
<u-input
class="flex-1"
v-model="formData.code"
placeholder="请输入验证码"
:border="false"
/>
<view
class="border-l border-solid border-0 border-light pl-3 leading-4 ml-3 w-[180rpx]"
@click="sendSms"
>
<u-verification-code
ref="uCodeRef"
:seconds="60"
@change="codeChange"
change-text="x秒"
/>
</u-form-item>
<u-form-item label="验证码" borderBottom>
<u-input
class="flex-1"
v-model="formData.code"
placeholder="请输入验证码"
:border="false"
/>
<view
class="border-l border-solid border-0 border-light pl-3 text-muted leading-4 ml-3 w-[180rpx]"
@click="sendSms"
>
<u-verification-code
ref="uCodeRef"
:seconds="60"
@change="codeChange"
change-text="x秒"
/>
<text :class="formData.mobile ? 'text-primary' : 'text-muted'">
{{ codeTips }}
</view>
</u-form-item>
</u-form>
</text>
</view>
</view>
<view class="mt-[40rpx]">
<u-button type="primary" shape="circle" @click="handleConfirm"> 确定 </u-button>
<u-button
type="primary"
hover-class="none"
:customStyle="{
height: '100rpx',
opacity:
formData.mobile && formData.code
? '1'
: '0.5'
}"
@click="handleConfirm"
>
确定
</u-button>
</view>
</view>
</view>
@@ -74,9 +101,7 @@ const handleConfirm = async () => {
await userBindMobile(formData, { token: userStore.temToken })
uni.$u.toast('绑定成功')
userStore.login(userStore.temToken!)
setTimeout(() => {
uni.navigateBack()
}, 1000)
uni.navigateBack()
}
</script>

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view
class="register bg-white min-h-full flex flex-col items-center px-[40rpx] pt-[100rpx] box-border"
>
@@ -11,7 +19,7 @@
<u-input
class="flex-1"
type="password"
v-model="formData.oldPassword"
v-model="formData.old_password"
:border="false"
placeholder="请输入原来的密码"
/>
@@ -29,7 +37,7 @@
<u-input
class="flex-1"
type="password"
v-model="formData.password2"
v-model="formData.password_confirm"
placeholder="再次输入新密码"
:border="false"
/>
@@ -50,19 +58,19 @@ import { reactive, ref } from 'vue'
const type = ref('')
const formData = reactive<any>({
password: '',
password2: ''
password_confirm: ''
})
const handleConfirm = async () => {
if (!formData.oldPassword && type.value != 'set') return uni.$u.toast('请输入原来的密码')
if (!formData.old_password && type.value != 'set') return uni.$u.toast('请输入原来的密码')
if (!formData.password) return uni.$u.toast('请输入密码')
if (!formData.password2) return uni.$u.toast('请输入确认密码')
if (formData.password != formData.password2) return uni.$u.toast('两次输入的密码不一致')
if (!formData.password_confirm) return uni.$u.toast('请输入确认密码')
if (formData.password != formData.password_confirm) return uni.$u.toast('两次输入的密码不一致')
await userChangePwd(formData)
uni.$u.toast('操作成功')
setTimeout(() => {
uni.navigateBack()
}, 1000)
uni.navigateBack()
}, 1500)
}
onLoad((options) => {

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<z-paging
ref="paging"
v-model="collectData"
@@ -16,7 +24,7 @@
:options="options"
btn-width="120"
>
<news-card :item="item" :newsId="item.articleId"></news-card>
<news-card :item="item" :newsId="item.article_id"></news-card>
</u-swipe-action>
</z-paging>
</template>
@@ -39,7 +47,7 @@ const collectData: any = ref([])
const queryList = async (pageNo, pageSize) => {
const { lists } = await getCollect()
lists.forEach((item) => {
lists.forEach((item: any) => {
item.show = false
})
collectData.value = lists
@@ -48,8 +56,8 @@ const queryList = async (pageNo, pageSize) => {
const handleCollect = async (index: number): Promise<void> => {
try {
const articleId: number = collectData.value[index].articleId
await cancelCollect({ articleId })
const article_id: number = collectData.value[index].article_id
await cancelCollect({ id: article_id })
uni.$u.toast('已取消收藏')
paging.value.reload()
} catch (err) {

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="customer-service">
<view v-for="(item, index) in state.pages" :key="index">
<template v-if="item.name == 'customer-service'">
@@ -18,7 +26,7 @@ const state = reactive<{
})
const getData = async () => {
const data = await getDecorate({ id: 3 })
state.pages = JSON.parse(data.pages)
state.pages = JSON.parse(data.data)
}
getData()
</script>

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view
class="register bg-white min-h-full flex flex-col items-center px-[40rpx] pt-[100rpx] box-border"
>
@@ -48,7 +56,7 @@
<u-input
class="flex-1"
type="password"
v-model="formData.password2"
v-model="formData.password_confirm"
placeholder="再次输入新密码"
:border="false"
/>
@@ -62,8 +70,8 @@
</template>
<script setup lang="ts">
import { forgotPassword } from '@/api/account'
import { smsSend } from '@/api/app'
import { forgotPassword } from '@/api/user'
import { SMSEnum } from '@/enums/appEnums'
import { reactive, ref, shallowRef } from 'vue'
@@ -73,7 +81,7 @@ const formData = reactive({
mobile: '',
code: '',
password: '',
password2: ''
password_confirm: ''
})
const codeChange = (text: string) => {
@@ -95,13 +103,12 @@ const sendSms = async () => {
const handleConfirm = async () => {
if (!formData.mobile) return uni.$u.toast('请输入手机号码')
if (!formData.password) return uni.$u.toast('请输入密码')
if (!formData.password2) return uni.$u.toast('请输入确认密码')
if (formData.password != formData.password2) return uni.$u.toast('两次输入的密码不一致')
if (!formData.password_confirm) return uni.$u.toast('请输入确认密码')
if (formData.password != formData.password_confirm) return uni.$u.toast('两次输入的密码不一致')
await forgotPassword(formData)
uni.$u.toast('操作成功')
setTimeout(() => {
uni.navigateBack()
}, 1000)
uni.navigateBack()
}, 1500)
}
</script>

View File

@@ -0,0 +1,158 @@
<template>
<!-- modal:隐私授权弹窗-->
<view v-if="show" class="modal-box" @tap.stop>
<view class="dialog" @tap.stop>
<view class="title">隐私政策提示</view>
<view class="content">
欢迎使用{{
appStore.getWebsiteConfig.shop_name
}}小程序请您在使用前点击
<text
class="text-[#243245]"
hover-class="hover"
@click="openContract"
>
{{ name }}
</text>
并仔细阅读如您同意全部内容请点击同意开始使用我们的服务
</view>
<view class="btn-box">
<button
class="btn disagree"
hover-class="hover"
@click="disagreePrivacy"
>
不同意
</button>
<button
class="btn bg-primary text-white"
hover-class="hover"
id="agree-btn"
open-type="agreePrivacyAuthorization"
@agreeprivacyauthorization="agreePrivacy"
>
同意
</button>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useAppStore } from '@/stores/app'
const appStore = useAppStore()
const name = ref<string>('')
const show = ref<boolean>(false)
interface PrivacyRes {
errMsg: string
privacyContractName: string
needAuthorization: boolean
}
if (wx.getPrivacySetting) {
wx.getPrivacySetting({
success(res: PrivacyRes) {
console.log(res)
name.value = res.privacyContractName
show.value = res.needAuthorization
}
})
}
const openContract = () => {
wx.openPrivacyContract({
success: () => {},
fail: () => {}
})
}
const disagreeHandle = () => {
// 用户点击拒绝后
show.value = false
}
const disagreePrivacy = () => {
uni.$u.toast('同意隐私政策后可继续使用')
// wx.exitMiniProgram()
}
const agreePrivacy = () => {
show.value = false
}
</script>
<style scoped>
.modal-box {
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 99999;
}
.modal-box .dialog {
box-sizing: border-box;
position: absolute;
bottom: 0;
width: 100%;
padding: 40rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: #ffffff;
border-radius: 20rpx 20rpx 0 0;
}
.modal-box .title {
text-align: center;
color: #333;
font-weight: bold;
font-size: 34rpx;
}
.modal-box .content {
display: block;
font-size: 28rpx;
color: #666;
margin-top: 20rpx;
text-align: justify;
line-height: 1.6;
padding: 10rpx 20rpx;
}
.modal-box .btn-box {
margin-top: 50rpx;
padding: 0 30rpx;
padding-bottom: 30rpx;
display: flex;
text-align: center;
}
.modal-box .btn::after {
border: none;
display: none;
}
.modal-box .btn-box .btn {
width: 50%;
height: 76rpx;
line-height: 76rpx;
margin: 0 10rpx;
padding: 0;
align-items: center;
justify-content: center;
border-radius: 60px;
font-size: 28rpx;
font-weight: 500;
}
.modal-box .disagree {
color: #0f0f0f;
background: #f5f5f5;
}
</style>

View File

@@ -1,19 +1,46 @@
<template>
<view class="index">
<view v-for="(item, index) in state.pages" :key="index">
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="index" :style="pageStyle">
<!-- 组件 -->
<template
v-for="(item, index) in state.pages"
:key="index"
>
<template v-if="item.name == 'search'">
<w-search :content="item.content" :styles="item.styles" />
<w-search
:pageMeta="state.meta"
:content="item.content"
:styles="item.styles"
:percent="percent"
:isLargeScreen="isLargeScreen"
/>
</template>
<template v-if="item.name == 'banner'">
<w-banner :content="item.content" :styles="item.styles" />
<w-banner
:content="item.content"
:styles="item.styles"
:isLargeScreen="isLargeScreen"
@change="handleBanner"
/>
</template>
<template v-if="item.name == 'nav'">
<w-nav :content="item.content" :styles="item.styles" />
<w-nav :content="item.content" :styles="item.styles"/>
</template>
</view>
<template v-if="item.name == 'middle-banner'">
<w-middle-banner :content="item.content" :styles="item.styles" />
</template>
</template>
<view class="article" v-if="state.article.length">
<view
class="flex items-center article-title mx-[20rpx] my-[30rpx] text-2xl font-medium"
class="flex items-center article-title mx-[20rpx] my-[30rpx] text-lg font-medium"
>
最新资讯
</view>
@@ -24,30 +51,125 @@
:item="item"
/>
</view>
<tabbar />
<!-- #ifdef H5 -->
<view class="text-center py-4 mb-12">
<router-navigate
class="mx-1 text-xs text-[#495770]"
:to="{
path: '/pages/webview/webview',
query: {
url: item.value
}
}"
v-for="item in appStore.getCopyrightConfig"
:key="item.key"
>
{{ item.key }}
</router-navigate>
</view>
<!-- #endif -->
<!-- 返回顶部按钮 -->
<u-back-top
:scroll-top="scrollTop"
:top="100"
:customStyle="{
backgroundColor: '#FFF',
color: '#000',
boxShadow: '0px 3px 6px rgba(0, 0, 0, 0.1)'
}"
>
</u-back-top>
<!-- #ifdef MP -->
<!-- 微信小程序隐私弹窗 -->
<MpPrivacyPopup></MpPrivacyPopup>
<!-- #endif -->
<tabbar/>
</view>
</template>
<script setup lang="ts">
import { getIndex } from '@/api/shop'
import { reactive } from 'vue'
import {getIndex} from '@/api/shop'
import {onLoad, onPageScroll} from "@dcloudio/uni-app";
import {computed, reactive, ref} from 'vue'
import {useAppStore} from '@/stores/app'
// #ifdef MP
import MpPrivacyPopup from './component/mp-privacy-popup.vue'
// #endif
const appStore = useAppStore()
const state = reactive<{
pages: any[]
meta: any[]
article: any[]
bannerImage: string
}>({
pages: [],
article: []
meta: [],
article: [],
bannerImage: ''
})
const getData = async () => {
const data = await getIndex()
state.pages = JSON.parse(data.pages)
state.article = data.article
const scrollTop = ref<number>(0)
const percent = ref<number>(0)
// 是否联动背景图
const isLinkage = computed(() => {
return state.pages.find((item: any) => item.name === 'banner')?.content.bg_style === 1
})
// 是否大屏banner
const isLargeScreen = computed(() => {
return state.pages.find((item: any) => item.name === 'banner')?.content.style === 2
})
// 根页面样式
const pageStyle = computed(() => {
const {bg_type, bg_color, bg_image} = state.meta[0]?.content ?? {}
if (!isLinkage.value) {
return bg_type == 1 ?
{'background-color': bg_color} :
{'background-image': `url(${bg_image})`}
}
else return {'background-image': `url(${state.bannerImage})`}
})
const handleBanner = (url: string) => {
state.bannerImage = url
}
getData()
const getData = async () => {
const data = await getIndex()
state.pages = JSON.parse(data?.page?.data)
state.meta = JSON.parse(data?.page?.meta)
state.article = data.article
uni.setNavigationBarTitle({
title: state.meta[0].content.title
})
}
onPageScroll((event: any) => {
scrollTop.value = event.scrollTop
const top = uni.upx2px(100)
percent.value = event.scrollTop / top > 1 ? 1 : event.scrollTop / top
})
onLoad(() => { getData() })
</script>
<style lang="scss">
<style lang="scss" scoped>
.index {
position: relative;
background-repeat: no-repeat;
background-size: 100% auto;
overflow: hidden;
width: 100%;
transition: all 1s;
min-height: calc(100vh - env(safe-area-inset-bottom));
}
.article-title {
&::before {
content: '';
@@ -55,7 +177,7 @@ getData()
height: 34rpx;
display: block;
margin-right: 10rpx;
background: $u-type-primary;
@apply bg-primary;
}
}
</style>

View File

@@ -1,36 +1,70 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar :front-color="$theme.navColor" :background-color="$theme.navBgColor" />
<!-- #endif -->
</page-meta>
<view
class="bg-white login min-h-full flex flex-col items-center px-[40rpx] pt-[80rpx] box-border"
class="bg-white login min-h-full flex flex-col items-center px-[40rpx] pt-[120rpx] box-border"
>
<view>
<u-image :src="appStore.config.website.logo" mode="widthFix" height="160" width="160" />
<image
:src="appStore.getWebsiteConfig.shop_logo"
mode="widthFix"
class="w-[160rpx] h-[160rpx] rounded-full"
/>
</view>
<view class="mt-4 text-xl font-medium">{{ appStore.config.website.name }}</view>
<view class="w-full mt-[60rpx] pb-[60rpx]">
<u-form borderBottom>
<view class="w-full mt-[140rpx] pb-[60rpx]">
<block v-if="!phoneLogin">
<!-- #ifdef MP-WEIXIN || H5 -->
<view v-if="isOpenOtherAuth && isWeixin && inWxAuth">
<u-button
type="primary"
@click="wxLogin"
:customStyle="{ height: '100rpx' }"
hover-class="none"
>
用户一键登录
</u-button>
</view>
<!-- #endif -->
<view class="mt-[40rpx]">
<u-button
@click="phoneLogin = !phoneLogin"
:customStyle="{ height: '100rpx' }"
hover-class="none"
>
手机号登录
</u-button>
</view>
</block>
<block v-if="phoneLogin">
<!-- 密码登录 -->
<template
v-if="loginWay == LoginWayEnum.ACCOUNT && includeLoginWay(LoginWayEnum.ACCOUNT)"
v-if="
formData.scene == LoginWayEnum.ACCOUNT &&
includeLoginWay(LoginWayEnum.ACCOUNT)
"
>
<u-form-item borderBottom>
<u-icon class="mr-2" :size="36" name="/static/images/icon/icon_user.png" />
<view
class="px-[18rpx] border border-solid border-lightc border-light rounded-[10rpx] h-[100rpx] items-center flex"
>
<u-input
class="flex-1"
v-model="formData.username"
v-model="formData.account"
:border="false"
placeholder="请输入账号/手机号码"
/>
</u-form-item>
<u-form-item borderBottom>
<u-icon
class="mr-2"
:size="36"
name="/static/images/icon/icon_password.png"
placeholder="输入账号"
/>
</view>
<view
class="px-[18rpx] py-[10rpx] border border-solid border-light rounded-[10rpx] flex h-[100rpx] items-center mt-[40rpx]"
>
<u-input
class="flex-1"
v-model="formData.password"
type="password"
placeholder="请输入密码"
placeholder="输入密码"
:border="false"
/>
<navigator url="/pages/forget_pwd/forget_pwd" hover-class="none">
@@ -40,32 +74,35 @@
忘记密码?
</view>
</navigator>
</u-form-item>
</view>
</template>
<!-- 验证码登录 -->
<template
v-if="loginWay == LoginWayEnum.MOBILE && includeLoginWay(LoginWayEnum.MOBILE)"
v-if="
formData.scene == LoginWayEnum.MOBILE &&
includeLoginWay(LoginWayEnum.MOBILE)
"
>
<u-form-item borderBottom>
<u-icon
class="mr-2"
:size="36"
name="/static/images/icon/icon_mobile.png"
/>
<view
class="px-[18rpx] border border-solid border-lightc border-light rounded-[10rpx] h-[100rpx] items-center flex"
>
<u-input
class="flex-1"
v-model="formData.mobile"
v-model="formData.account"
:border="false"
placeholder="请输入手机号码"
/>
</u-form-item>
<u-form-item borderBottom>
<u-icon class="mr-2" :size="36" name="/static/images/icon/icon_code.png" />
</view>
<view
class="px-[18rpx] border border-solid border-lightc border-light rounded-[10rpx] h-[100rpx] items-center flex mt-[40rpx]"
>
<u-input
class="flex-1"
v-model="formData.code"
placeholder="请输入验证码"
:border="false"
/>
<view
class="border-l border-solid border-0 border-light pl-3 leading-4 ml-3 w-[180rpx]"
@click="sendSms"
@@ -76,13 +113,14 @@
@change="codeChange"
change-text="x秒"
/>
<text :class="formData.mobile ? 'text-primary' : 'text-muted'">
<text :class="formData.account ? 'text-primary' : 'text-muted'">
{{ codeTips }}
</text>
</view>
</u-form-item>
</view>
</template>
</u-form>
</block>
<view class="mt-[40rpx]" v-if="isOpenAgreement">
<u-checkbox v-model="isCheckAgreement" shape="circle">
<view class="text-xs flex">
@@ -110,174 +148,178 @@
</view>
</u-checkbox>
</view>
<view class="mt-[60rpx]">
<u-button type="primary" shape="circle" @click="handleLogin(formData.scene)">
</u-button>
</view>
<view class="text-content flex justify-between mt-[40rpx]">
<view class="flex-1">
<view
v-if="
loginWay == LoginWayEnum.MOBILE && includeLoginWay(LoginWayEnum.ACCOUNT)
"
@click="changeLoginWay(LoginTypeEnum.ACCOUNT, LoginWayEnum.ACCOUNT)"
<block v-if="phoneLogin">
<view class="mt-[60rpx]">
<u-button
type="primary"
@click="handleLogin(formData.scene)"
:customStyle="{
height: '100rpx',
opacity: DisableStyle ? '1' : '0.5'
}"
hover-class="none"
>
账号密码登录
</view>
<view
v-if="
loginWay == LoginWayEnum.ACCOUNT && includeLoginWay(LoginWayEnum.MOBILE)
"
@click="changeLoginWay(LoginTypeEnum.MOBILE, LoginWayEnum.MOBILE)"
>
短信验证码登录
</view>
登录
</u-button>
</view>
<navigator url="/pages/register/register" hover-class="none">注册账号</navigator>
</view>
<!-- #ifdef MP-WEIXIN || H5 -->
<view class="mt-[80rpx]" v-if="isOpenOtherAuth && isWeixin">
<u-divider>第三方登录</u-divider>
<div class="flex justify-center mt-[40rpx]">
<div
v-if="includeAuthWay(LoginAuthEnum.WX) && isWeixin"
class="flex flex-col items-center"
@click="wxLogin"
<view class="flex justify-between mt-[40rpx]">
<view
>已有账号,使用
<span
class="text-primary"
@click="changeLoginWay(LoginWayEnum.ACCOUNT)"
v-if="
formData.scene == LoginWayEnum.MOBILE &&
includeLoginWay(LoginWayEnum.ACCOUNT)
"
>密码登录</span
>
<span
class="text-primary"
@click="changeLoginWay(LoginWayEnum.MOBILE)"
v-if="
formData.scene == LoginWayEnum.ACCOUNT &&
includeLoginWay(LoginWayEnum.MOBILE)
"
>验证码登录</span
>
</view>
<navigator url="/pages/register/register" hover-class="none"
>注册账号</navigator
>
<img src="@/static/images/icon/icon_wx.png" class="w-[80rpx] h-[80rpx]" />
<div class="text-sm mt-[10px]">微信登录</div>
</div>
</div>
</view>
<!-- #endif -->
</view>
</block>
</view>
<!-- 协议弹框 -->
<u-modal
v-model="showModel"
show-cancel-button
:show-title="false"
confirm-color="var(--color-primary)"
@confirm=";(isCheckAgreement = true), (showModel = false)"
@cancel="showModel = false"
>
<view class="text-center px-[70rpx] py-[60rpx]">
<view> 请先阅读并同意 </view>
<view class="flex justify-center">
<navigator data-theme="" url="/pages/agreement/agreement?type=service">
<view class="text-primary">《服务协议》</view>
</navigator>
<navigator url="/pages/agreement/agreement?type=privacy">
<view class="text-primary">《隐私协议》</view>
</navigator>
</view>
</view>
</u-modal>
<!-- #ifdef MP-WEIXIN -->
<mplogin-popup
v-model:show="showLoginPopup"
:logo="websiteConfig.logo"
:title="websiteConfig.name"
:logo="websiteConfig.shop_logo"
:title="websiteConfig.shop_name"
@update="handleUpdateUser"
/>
<!-- #endif -->
</view>
</template>
<script setup lang="ts">
import { mobileLogin, accountLogin, mnpLogin } from '@/api/account'
import { login, mnpLogin, updateUser, OALogin } from '@/api/account'
import { smsSend } from '@/api/app'
import { updateUser } from '@/api/user'
import { SMSEnum } from '@/enums/appEnums'
import { BACK_URL } from '@/enums/cacheEnums'
import { BACK_URL } from '@/enums/constantEnums'
import { useLockFn } from '@/hooks/useLockFn'
import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user'
import { useRouter, useRoute } from 'uniapp-router-next'
import cache from '@/utils/cache'
import { isWeixinClient } from '@/utils/client'
// #ifdef H5
import wechatOa from '@/utils/wechat'
import wechatOa, { UrlScene } from '@/utils/wechat'
// #endif
import { onLoad, onShow } from '@dcloudio/uni-app'
import { computed, reactive, ref, shallowRef, watch } from 'vue'
enum LoginTypeEnum {
MOBILE = 'mobile',
ACCOUNT = 'account'
}
enum LoginWayEnum {
ACCOUNT = 1,
MOBILE = 2
}
enum LoginAuthEnum {
WX = 1,
QQ = 2
}
const isWeixin = ref(true)
const showLoginPopup = ref(false)
// #ifdef H5
isWeixin.value = isWeixinClient()
// #endif
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const appStore = useAppStore()
const websiteConfig = computed(() => appStore.getWebsiteConfig)
const showModel = ref(false)
const uCodeRef = shallowRef()
const loginWay = ref<LoginWayEnum>()
const codeTips = ref('')
const showLoginPopup = ref(false)
const isCheckAgreement = ref(false)
const loginData = ref<any>({})
const formData = reactive({
scene: '',
username: '',
password: '',
code: '',
mobile: ''
})
const formData = reactive({
scene: 1,
account: '',
password: '',
code: ''
})
const phoneLogin = ref(false)
const loginData = ref()
const codeChange = (text: string) => {
codeTips.value = text
}
const websiteConfig = computed(() => appStore.getWebsiteConfig)
const sendSms = async () => {
if (!formData.mobile) return
if (!formData.account) return
if (uCodeRef.value?.canGetCode) {
await smsSend({
scene: SMSEnum.LOGIN,
mobile: formData.mobile
mobile: formData.account
})
uni.$u.toast('发送成功')
uCodeRef.value?.start()
}
}
const changeLoginWay = (type: LoginTypeEnum, way: LoginWayEnum) => {
formData.scene = type
loginWay.value = way
const changeLoginWay = (way: LoginWayEnum) => {
formData.scene = way
}
const includeLoginWay = (way: LoginWayEnum) => {
return appStore.getLoginConfig.loginWay.includes(way)
return appStore.getLoginConfig.login_way?.includes(String(way))
}
const includeAuthWay = (way: LoginAuthEnum) => {
return appStore.getLoginConfig.autoLoginAuth.includes(way)
}
const inWxAuth = computed(() => {
return appStore.getLoginConfig.wechat_auth
})
const isOpenAgreement = computed(() => appStore.getLoginConfig.openAgreement == 1)
const isOpenAgreement = computed(() => appStore.getLoginConfig.login_agreement == 1)
const isOpenOtherAuth = computed(() => appStore.getLoginConfig.openOtherAuth == 1)
const isForceBindMobile = computed(() => appStore.getLoginConfig.forceBindMobile == 1)
const isOpenOtherAuth = computed(() => appStore.getLoginConfig.third_auth == 1)
const isForceBindMobile = computed(() => appStore.getLoginConfig.coerce_mobile == 1)
const loginFun = async (scene: LoginTypeEnum) => {
const loginFun = async () => {
if (!isCheckAgreement.value && isOpenAgreement.value) return (showModel.value = true)
if (formData.scene == LoginWayEnum.ACCOUNT) {
if (!formData.account) return uni.$u.toast('请输入账号/手机号码')
if (!formData.password) return uni.$u.toast('请输入密码')
}
if (formData.scene == LoginWayEnum.MOBILE) {
if (!formData.account) return uni.$u.toast('请输入手机号码')
if (!formData.code) return uni.$u.toast('请输入验证码')
}
uni.showLoading({
title: '请稍后...'
})
try {
await checkAgreement()
if (scene == LoginTypeEnum.ACCOUNT) {
if (!formData.username) return uni.$u.toast('请输入账号/手机号码')
if (!formData.password) return uni.$u.toast('请输入密码')
}
if (scene == LoginTypeEnum.MOBILE) {
if (!formData.mobile) return uni.$u.toast('请输入手机号码')
if (!formData.code) return uni.$u.toast('请输入验证码')
}
uni.showLoading({
title: '请稍后...'
})
let data
switch (scene) {
case LoginTypeEnum.ACCOUNT:
data = await accountLogin(formData)
break
case LoginTypeEnum.MOBILE:
data = await mobileLogin(formData)
break
}
if (data) {
loginHandle(data)
}
const data = await login(formData)
loginHandle(data)
} catch (error: any) {
uni.hideLoading()
uni.$u.toast(error)
@@ -285,12 +327,10 @@ const loginFun = async (scene: LoginTypeEnum) => {
}
const loginHandle = async (data: any) => {
const { token, isBindMobile } = data
if (!isBindMobile && isForceBindMobile.value) {
const { token, mobile } = data
if (!mobile && isForceBindMobile.value) {
userStore.temToken = token
uni.navigateTo({
url: '/pages/bind_mobile/bind_mobile'
})
router.navigateTo('/pages/bind_mobile/bind_mobile')
uni.hideLoading()
return
}
@@ -301,62 +341,76 @@ const loginHandle = async (data: any) => {
const pages = getCurrentPages()
if (pages.length > 1) {
const prevPage = pages[pages.length - 2]
uni.navigateBack({
success: () => {
// @ts-ignore
const { onLoad, options } = prevPage
// 刷新上一个页面
onLoad && onLoad(options)
}
})
await router.navigateBack()
// @ts-ignore
const { onLoad, options } = prevPage
// 刷新上一个页面
onLoad && onLoad(options)
} else if (cache.get(BACK_URL)) {
uni.redirectTo({ url: cache.get(BACK_URL) })
try {
router.redirectTo(cache.get(BACK_URL))
} catch (error) {
router.switchTab(cache.get(BACK_URL))
}
} else {
uni.reLaunch({
url: '/pages/index/index'
})
router.reLaunch('/pages/index/index')
}
cache.remove(BACK_URL)
}
const { lockFn: handleLogin } = useLockFn(loginFun)
const checkAgreement = async () => {
if (!isCheckAgreement.value && isOpenAgreement.value)
return Promise.reject('请勾选已阅读并同意《服务协议》和《隐私协议》')
}
const { lockFn: wxLogin } = useLockFn(async () => {
try {
await checkAgreement()
// #ifdef MP-WEIXIN
uni.showLoading({
title: '请稍后...'
const oaLogin = async (options: any = { getUrl: true }) => {
const { code, getUrl } = options
if (getUrl) {
await wechatOa.getUrl(UrlScene.LOGIN)
} else {
const data = await OALogin({
code
})
return data
}
return Promise.reject()
}
const wxLogin = async () => {
if (!isCheckAgreement.value && isOpenAgreement.value) {
showModel.value = true
console.log(showModel.value)
return
}
// #ifdef MP-WEIXIN
uni.showLoading({
title: '请稍后...'
})
try {
const { code }: any = await uni.login({
provider: 'weixin'
})
const data = await mnpLogin({
code
code: code
})
loginData.value = data
if (data.isNew) {
if (data.is_new_user) {
uni.hideLoading()
userStore.temToken = data.token
showLoginPopup.value = true
return
}
loginHandle(data)
// #endif
// #ifdef H5
if (isWeixin.value) {
wechatOa.getUrl()
}
// #endif
} catch (error) {
} catch (error: any) {
uni.hideLoading()
uni.$u.toast(error)
}
})
// #endif
// #ifdef H5
if (isWeixin.value) {
oaLogin()
}
// #endif
}
const handleUpdateUser = async (value: any) => {
await updateUser(value, { token: userStore.temToken })
showLoginPopup.value = false
@@ -366,56 +420,56 @@ const handleUpdateUser = async (value: any) => {
watch(
() => appStore.getLoginConfig,
(value) => {
if (value.loginWay) {
loginWay.value = value.loginWay[0]
//@ts-ignore
formData.scene = LoginTypeEnum[LoginWayEnum[loginWay.value]]
if (value.login_way) {
formData.scene = value.login_way[0]
}
},
{
immediate: true
}
)
onShow(async () => {
try {
if (userStore.isLogin) {
uni.showLoading({
title: '请稍后...'
})
await userStore.getUser()
uni.hideLoading()
uni.navigateBack()
}
} catch (error: any) {
uni.hideLoading()
const DisableStyle = computed(() => {
if (formData.scene == 1 && formData.account && formData.password) {
return true
} else if (formData.scene == 2 && formData.account && formData.code) {
return true
} else {
return false
}
})
onLoad(async (options) => {
if (userStore.isLogin) {
// 已经登录 => 首页
uni.reLaunch({
url: '/pages/index/index'
})
return
const removeWxQuery = () => {
const options = route.query
if (options.code && options.state) {
delete options.code
delete options.state
router.redirectTo({ path: route.path, query: options })
}
// #ifdef H5
const { code } = options
if (code) {
uni.showLoading({
title: '请稍后...'
})
}
try {
const data = await wechatOa.authLogin(code)
loginHandle(data)
} catch (error: any) {
uni.hideLoading()
throw new Error(error)
onLoad(async () => {
//#ifdef H5
const options = wechatOa.getAuthData()
try {
if (options.code && options.scene === UrlScene.LOGIN) {
uni.showLoading({
title: '请稍后...'
})
const data = await oaLogin(options)
if (data) {
loginData.value = data
loginHandle(loginData.value)
}
}
} catch (error) {
removeWxQuery()
} finally {
uni.hideLoading()
//清除保存的授权数据
wechatOa.setAuthData()
}
// #endif
//#endif
})
</script>

View File

@@ -46,12 +46,12 @@ watch(
{ immediate: true }
)
const queryList = async (pageNo, pageSize) => {
const queryList = async (page_no, page_size) => {
try {
const { lists } = await getArticleList({
cid: props.cid,
pageNo,
pageSize
page_no,
page_size
})
paging.value.complete(lists)
} catch (e) {

View File

@@ -1,4 +1,29 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<!-- #ifndef H5 -->
<u-sticky
h5-nav-height="0"
bg-color="transparent"
>
<u-navbar
:is-back="false"
:is-fixed="false"
title="资讯"
:border-bottom="false"
:title-bold="true"
:title-color="$theme.navColor"
:background="{ background: $theme.navBgColor }"
>
</u-navbar>
</u-sticky>
<!-- #endif -->
<view class="news">
<!-- 搜索 -->
<navigator class="news-search px-[24rpx] py-[14rpx] bg-white" url="/pages/search/search">
@@ -39,7 +64,7 @@ const handleChange = (index: number) => {
const getData = async () => {
const data = await getArticleCate()
tabList.value = [{ name: '全部', id: 0 }].concat(data)
tabList.value = [{ name: '全部', id: '' }].concat(data)
}
onLoad((options) => {

View File

@@ -1,17 +1,25 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="news-detail bg-white">
<!-- 标题信心 -->
<view class="news-detail-header py-[20rpx] px-[30rpx]">
<view class="text-3xl font-medium">{{ newsData.title }}</view>
<view class="flex mt-[20rpx] text-xs">
<view class="mr-[40rpx]" v-if="newsData.author">作者: {{ newsData.author }}</view>
<view class="text-muted mr-[40rpx] flex-1">{{ newsData.createTime }}</view>
<view class="text-muted mr-[40rpx] flex-1">{{ newsData.create_time }}</view>
<view class="flex items-center text-muted flex-none">
<image
src="/static/images/icon/icon_visit.png"
class="w-[30rpx] h-[30rpx]"
></image>
<view class="ml-[10rpx]">{{ newsData.visit }}</view>
<view class="ml-[10rpx]">{{ newsData.click }}</view>
</view>
</view>
</view>
@@ -19,8 +27,8 @@
<!-- 咨询内容 -->
<view class="news-detail-section bg-white p-[24rpx]">
<!-- 摘要 -->
<view class="summary p-[20rpx] text-base" v-if="newsData.summary">
<text class="font-medium">摘要: </text> {{ newsData.summary }}
<view class="summary p-[20rpx] text-base" v-if="newsData.abstract">
<text class="font-medium">摘要: </text> {{ newsData.abstract }}
</view>
<!-- 内容 -->
<view class="mt-[20rpx]">
@@ -51,13 +59,13 @@ const getData = async (id) => {
newsData.value = await getArticleDetail({ id })
}
const handleAddCollect = async (articleId: number) => {
const handleAddCollect = async (id: number) => {
try {
if (newsData.value.collect) {
await cancelCollect({ articleId })
await cancelCollect({ id })
uni.$u.toast('已取消收藏')
} else {
await addCollect({ articleId })
await addCollect({ id })
uni.$u.toast('收藏成功')
}
getData(newsId)

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<!-- 页面状态 -->
<page-status :status="status">
<template #error>
@@ -18,10 +26,11 @@
/>
<!-- 支付状态文字 -->
<text class="text-2xl font-medium mt-[20rpx]">{{
paymentStatus['text']
}}</text>
paymentStatus['text']
}}
</text>
<view class="text-3xl font-medium mt-[20rpx]">
¥ {{ orderInfo.orderAmount }}
¥ {{ orderInfo.order.order_amount }}
</view>
</view>
@@ -29,16 +38,16 @@
<view class="result-info">
<view class="result-info__item">
<text>订单编号</text>
<text>{{ orderInfo.orderSn }}</text>
<text>{{ orderInfo.order.order_sn }}</text>
</view>
<view class="result-info__item">
<text>付款时间</text>
<text>{{ orderInfo.payTime || '-' }}</text>
<text>{{ orderInfo.order.pay_time }}</text>
</view>
<view class="result-info__item">
<text>支付方式</text>
<template v-if="orderInfo.payStatus">
<text>{{ orderInfo.payWay || '-' }}</text>
<template v-if="orderInfo.pay_status">
<text>{{ orderInfo.order.pay_way || '-' }}</text>
</template>
<template v-else>
<text>未支付</text>
@@ -76,10 +85,14 @@
</template>
<script lang="ts" setup>
import { getPayResult } from '@/api/pay'
import { PageStatusEnum } from '@/enums/appEnums'
import { onLoad } from '@dcloudio/uni-app'
import { computed, reactive, ref } from 'vue'
import {getPayResult} from '@/api/pay'
import {PageStatusEnum} from '@/enums/appEnums'
import {onLoad} from '@dcloudio/uni-app'
import {computed, reactive, ref} from 'vue'
import {useRouter} from "uniapp-router-next";
const router = useRouter()
const mapStatus = {
succeed: {
text: '支付成功',
@@ -99,14 +112,14 @@ const orderInfo = reactive<any>({
order: {}
})
const paymentStatus = computed(() => {
const status = !!orderInfo.payStatus
const status = !!orderInfo.pay_status
return mapStatus[status ? 'succeed' : 'waiting']
})
const initPageData = () => {
return new Promise((resolve, reject) => {
getPayResult({
orderId: pageOptions.value.id,
order_id: pageOptions.value.id,
from: pageOptions.value.from
})
.then((data) => {
@@ -120,15 +133,13 @@ const initPageData = () => {
}
const goHome = () => {
uni.reLaunch({
url: '/pages/index/index'
})
router.reLaunch('/pages/index/index')
}
const goOrder = () => {
switch (pageOptions.value.from) {
case 'recharge':
uni.navigateBack()
router.navigateBack()
break
}
}

View File

@@ -1,96 +1,142 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view
class="register bg-white min-h-full flex flex-col items-center px-[40rpx] pt-[40rpx] box-border"
>
<view class="w-full">
<u-form borderBottom :label-width="150">
<u-form-item label="创建账号" borderBottom>
<u-input
class="flex-1"
v-model="formData.username"
:border="false"
placeholder="请输入账号"
/>
</u-form-item>
<u-form-item label="设置密码" borderBottom>
<u-input
class="flex-1"
type="password"
v-model="formData.password"
placeholder="6-20位数字+字母或符号组合"
:border="false"
/>
</u-form-item>
<u-form-item label="确认密码" borderBottom>
<u-input
class="flex-1"
type="password"
v-model="formData.password2"
placeholder="请确认密码"
:border="false"
/>
</u-form-item>
</u-form>
<view class="text-2xl font-medium mb-[60rpx]">注册新账号</view>
<view
class="px-[18rpx] border border-solid border-lightc border-light rounded-[10rpx] h-[100rpx] items-center flex"
>
<u-input
class="flex-1"
v-model="formData.account"
:border="false"
placeholder="请输入账号"
/>
</view>
<view
class="px-[18rpx] border border-solid border-lightc border-light rounded-[10rpx] h-[100rpx] items-center flex mt-[40rpx]"
>
<u-input
class="flex-1"
type="password"
v-model="formData.password"
placeholder="请输入密码"
:border="false"
/>
</view>
<view
class="px-[18rpx] border border-solid border-lightc border-light rounded-[10rpx] h-[100rpx] items-center flex mt-[40rpx]"
>
<u-input
class="flex-1"
type="password"
v-model="formData.password_confirm"
placeholder="请再次输入密码"
:border="false"
/>
</view>
<view class="mt-[40rpx]" v-if="isOpenAgreement">
<u-checkbox v-model="isCheckAgreement" shape="circle">
<view class="text-xs flex">
已阅读并同意
<view @click.stop>
<navigator
<router-navigate
class="text-primary"
hover-class="none"
url="/pages/agreement/agreement?type=service"
to="/pages/agreement/agreement?type=service"
>
服务协议
</navigator>
</router-navigate>
</view>
<view @click.stop>
<navigator
<router-navigate
class="text-primary"
hover-class="none"
url="/pages/agreement/agreement?type=privacy"
to="/pages/agreement/agreement?type=privacy"
>
隐私协议
</navigator>
</router-navigate>
</view>
</view>
</u-checkbox>
</view>
<view class="mt-[60rpx]">
<u-button type="primary" shape="circle" @click="accountRegister"> 注册 </u-button>
<u-button
type="primary"
hover-class="none"
@click="accountRegister"
:customStyle="{
height: '100rpx',
opacity:
formData.account && formData.password && formData.password_confirm
? '1'
: '0.5'
}"
>
注册
</u-button>
</view>
</view>
</view>
<!-- 协议弹框 -->
<u-modal
v-model="showModel"
show-cancel-button
:show-title="false"
@confirm=";(isCheckAgreement = true), (showModel = false)"
@cancel="showModel = false"
confirm-color="var(--color-primary)"
>
<view class="text-center px-[70rpx] py-[60rpx]">
<view> 请先阅读并同意</view>
<view class="flex justify-center">
<router-navigate data-theme="" to="/pages/agreement/agreement?type=service">
<view class="text-primary">服务协议</view>
</router-navigate>
<router-navigate to="/pages/agreement/agreement?type=privacy">
<view class="text-primary">隐私协议</view>
</router-navigate>
</view>
</view>
</u-modal>
</template>
<script setup lang="ts">
import { register } from '@/api/account'
import { useAppStore } from '@/stores/app'
import { computed, reactive, ref } from 'vue'
import {register} from '@/api/account'
import {useAppStore} from '@/stores/app'
import {computed, reactive, ref} from 'vue'
const isCheckAgreement = ref(false)
const appStore = useAppStore()
const isOpenAgreement = computed(() => appStore.getLoginConfig.openAgreement == 1)
const isOpenAgreement = computed(() => appStore.getLoginConfig.login_agreement == 1)
const formData = reactive({
username: '',
account: '',
password: '',
password2: ''
password_confirm: ''
})
const showModel = ref(false)
const accountRegister = async () => {
if (!isCheckAgreement.value && isOpenAgreement.value)
return uni.$u.toast('请勾选已阅读并同意《服务协议》和《隐私协议》')
if (!formData.username) return uni.$u.toast('请输入账号')
if (!formData.account) return uni.$u.toast('请输入账号')
if (!formData.password) return uni.$u.toast('请输入密码')
if (!formData.password2) return uni.$u.toast('请输入确认密码')
if (formData.password != formData.password2) return uni.$u.toast('两次输入的密码不一致')
if (!formData.password_confirm) return uni.$u.toast('请输入确认密码')
if (!isCheckAgreement.value && isOpenAgreement.value) return (showModel.value = true)
if (formData.password != formData.password_confirm) return uni.$u.toast('两次输入的密码不一致')
await register(formData)
uni.$u.toast('注册成功')
setTimeout(() => {
uni.navigateBack()
}, 1000)
uni.navigateBack()
}
</script>

View File

@@ -1,13 +1,16 @@
<template>
<view class="suggest bg-white">
<!-- 热门搜索 -->
<view class="hot" v-if="searchData.length">
<view class="hot" v-if="hot_search.status == 1 && searchData.length">
<view class="font-medium pl-[24rpx] pt-[26rpx] pb-[6rpx] text-lg">热门搜索</view>
<view class="w-full px-[24rpx]">
<block v-for="(hotItem, index) in searchData" :key="index">
<view class="keyword truncate max-w-full" @click="handleHistoreSearch(hotItem)">
{{ hotItem }}
<view
class="keyword truncate max-w-full"
@click="handleHistoreSearch(hotItem.name)"
>
{{ hotItem.name }}
</view>
</block>
</view>
@@ -15,7 +18,7 @@
<view
class="mx-[24rpx] my-[40rpx] border-b border-solid border-0 border-light"
v-if="searchData.length && his_search.length"
v-if="hot_search.status == 1 && searchData.length && his_search.length"
></view>
<!-- 历史搜索 -->
@@ -46,16 +49,23 @@ const emit = defineEmits<{
const props = withDefaults(
defineProps<{
hot_search?: string[]
hot_search?: {
data: any[]
status: number
}
his_search?: string[]
}>(),
{
hot_search: () => [],
hot_search: () => ({
data: [],
status: 0
}),
his_search: () => []
}
)
const searchData = computed(() => {
return props.hot_search.filter((item) => item)
return props.hot_search.data.filter((item) => item.name)
})
const handleHistoreSearch = (text: string) => {

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="search">
<!-- 搜索框 -->
<view class="px-[24rpx] py-[14rpx] bg-white">
@@ -32,7 +40,7 @@
:fixed="false"
height="100%"
>
<block v-for="(item, index) in search.result" :key="item.id">
<block v-for="item in search.result" :key="item.id">
<news-card :item="item" :newsId="item.id"></news-card>
</block>
</z-paging>
@@ -44,20 +52,26 @@
<script lang="ts" setup>
import { ref, reactive, shallowRef } from 'vue'
import Suggest from './component/suggest.vue'
import { HISTORY } from '@/enums/cacheEnums'
import { HISTORY } from '@/enums/constantEnums'
import { getHotSearch } from '@/api/shop'
import { getArticleList } from '@/api/news'
import cache from '@/utils/cache'
import { getArticleList } from '@/api/news'
interface Search {
hot_search: string[]
hot_search: {
data: any[]
status: number
}
his_search: string[]
result: any
searching: boolean
}
const search = reactive<Search>({
hot_search: [],
hot_search: {
data: [],
status: 1
},
his_search: [],
result: [],
searching: false
@@ -97,12 +111,12 @@ const handleClear = async (): Promise<void> => {
}
}
const queryList = async (pageNo, pageSize) => {
const queryList = async (page_no: number, page_size: number) => {
try {
const { lists } = await getArticleList({
keyword: keyword.value,
pageNo,
pageSize
page_no,
page_size
})
paging.value.complete(lists)
} catch (e) {

View File

@@ -1,8 +1,17 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="user">
<view v-for="(item, index) in state.pages" :key="index">
<template v-if="item.name == 'user-info'">
<w-user-info
:pageMeta="state.meta"
:content="item.content"
:styles="item.styles"
:user="userInfo"
@@ -27,13 +36,19 @@ import { onShow } from '@dcloudio/uni-app'
import { storeToRefs } from 'pinia'
import { reactive } from 'vue'
const state = reactive<{
meta: any[]
pages: any[]
}>({
meta: [],
pages: []
})
const getData = async () => {
const data = await getDecorate({ id: 2 })
state.pages = JSON.parse(data.pages)
state.meta = JSON.parse(data.meta)
state.pages = JSON.parse(data.data)
uni.setNavigationBarTitle({
title: state.meta[0].content.title
})
}
const userStore = useUserStore()
const { userInfo, isLogin } = storeToRefs(userStore)

View File

@@ -1,19 +1,23 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<!-- Main Start -->
<!-- 头部修改头像 -->
<view class="header bg-white py-[30rpx]">
<view class="flex">
<button
class="flex flex-col items-center after:border-0"
hover-class="none"
open-type="chooseAvatar"
style="background-color: transparent"
@click="chooseAvatar"
@chooseavatar="chooseAvatar"
<view class="header bg-white pt-[30rpx]">
<view class="flex justify-center pb-5">
<avatar-upload
:modelValue="userInfo?.avatar"
file-key="url"
:round="true"
@update:modelValue="handleAvatarChange"
>
<image :src="userInfo?.avatar"></image>
<view class="mt-[10rpx] text-center text-muted text-xs"> 点击修改头像 </view>
</button>
</avatar-upload>
</view>
</view>
@@ -23,7 +27,7 @@
@click=";(showUserName = true), (newUsername = userInfo?.username)"
>
<view class="label">账号</view>
<view class="content">{{ userInfo?.username }}</view>
<view class="content">{{ userInfo?.account }}</view>
<u-icon name="arrow-right" size="22" color="#666"></u-icon>
</view>
@@ -79,7 +83,7 @@
<!-- 注册时间 -->
<view class="item text-nr flex justify-between">
<view class="label">注册时间</view>
<view class="content">{{ userInfo?.createTime }}</view>
<view class="content">{{ userInfo?.create_time }}</view>
</view>
<!-- 昵称修改组件 -->
@@ -106,8 +110,8 @@
<button
class="bg-primary text-white w-full h-[80rpx] !text-lg !leading-[80rpx] rounded-full"
form-type="submit"
hover-class="none"
size="mini"
hover-class="none"
>
确定
</button>
@@ -149,7 +153,7 @@
<!-- 账号修改组件 -->
<u-popup v-model="showMobilePop" :closeable="true" mode="center" border-radius="20">
<view class="px-[50rpx] py-[40rpx] bg-white" style="width: 85vw">
<view class="mb-[70rpx] text-xl text-center">修改手机号码</view>
<view class="mb-[70rpx] text-xl text-center">{{ userInfo?.mobile == '' ? '绑定手机号' : '更换手机号' }}</view>
<u-form-item borderBottom>
<u-input
class="flex-1"
@@ -191,7 +195,6 @@ import { onShow, onUnload } from '@dcloudio/uni-app'
import { getUserInfo, userEdit, userBindMobile, userMnpMobile } from '@/api/user'
import { smsSend } from '@/api/app'
import { FieldType, SMSEnum } from '@/enums/appEnums'
import { uploadImage } from '@/api/app'
// 用户信息
const userInfo = ref<any>({})
@@ -244,6 +247,11 @@ const sendSms = async () => {
}
}
const handleAvatarChange = (value) => {
fieldType.value = FieldType.AVATAR
setUserInfoFun(value)
}
// 验证码修改手机号-非微信小程序
const changeCodeMobile = async () => {
await userBindMobile({
@@ -266,21 +274,6 @@ const setUserInfoFun = async (value: string): Promise<void> => {
getUser()
}
// 上传头像
const chooseAvatar = (e: any) => {
fieldType.value = FieldType.AVATAR
// #ifndef MP-WEIXIN
uni.navigateTo({
url: '/uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper?destWidth=300&rectWidth=200&fileType=jpg'
})
// #endif
// #ifdef MP-WEIXIN
if (e.detail.avatarUrl) {
uploadAvatar(e.detail.avatarUrl)
}
// #endif
}
// 显示修改用户性别弹窗
const changeSex = () => {
showPicker.value = true
@@ -294,12 +287,12 @@ const changeSexConfirm = (value) => {
}
// 修改用户账号
const changeUserNameConfirm = async () => {
const changeUserNameConfirm = () => {
if (newUsername.value == '') return uni.$u.toast('账号不能为空')
if (newUsername.value.length > 10) return uni.$u.toast('账号长度不得超过十位数')
fieldType.value = FieldType.USERNAME
await setUserInfoFun(newUsername.value)
setUserInfoFun(newUsername.value)
showUserName.value = false
}
@@ -337,34 +330,11 @@ const goPage = (url: string) => {
})
}
const uploadAvatar = (path: string) => {
uni.showLoading({
title: '正在上传中...',
mask: true
})
uploadImage(path)
.then((res) => {
uni.hideLoading()
setUserInfoFun(res.url)
})
.catch(() => {
uni.hideLoading()
uni.$u.toast('上传失败')
})
}
// 监听从裁剪页发布的事件,获得裁剪结果
uni.$on('uAvatarCropper', (path) => {
uploadAvatar(path)
})
onShow(async () => {
getUser()
})
onUnload(() => {
uni.$off('uAvatarCropper')
})
onUnload(() => {})
</script>
<style lang="scss">

View File

@@ -1,4 +1,12 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="user-set">
<navigator :url="`/pages/user_data/user_data`">
<view class="item flex bg-white mt-[20rpx]">
@@ -6,7 +14,7 @@
<view class="ml-[20rpx] flex flex-1 justify-between items-center">
<view>
<view class="mb-[15rpx] text-xl font-medium">{{ userInfo.nickname }}</view>
<view class="text-content text-xs">账号{{ userInfo.username }}</view>
<view class="text-content text-xs">账号{{ userInfo.account }}</view>
</view>
<u-icon name="arrow-right" color="#666"></u-icon>
</view>
@@ -19,7 +27,7 @@
<view class="">登录密码</view>
<u-icon name="arrow-right" color="#666"></u-icon>
</view>
<!-- #ifdef MP-WEIXIN || H5 -->
<!-- #ifdef H5 || MP-WEIXIN -->
<view
v-if="isWeixin"
class="item bg-white flex flex-1 justify-between"
@@ -28,9 +36,9 @@
<view class="">绑定微信</view>
<view class="flex justify-between">
<view class="text-muted mr-[20rpx]">
{{ userInfo.isBindWechat ? '已绑定' : '未绑定' }}
{{ userInfo.is_auth ? '已绑定' : '未绑定' }}
</view>
<u-icon v-if="userInfo.isBindWechat == 0" name="arrow-right" color="#666"></u-icon>
<u-icon v-if="userInfo.is_auth == 0" name="arrow-right" color="#666"></u-icon>
</view>
</view>
<!-- #endif -->
@@ -59,7 +67,7 @@
</navigator>
<view class="mt-[60rpx] mx-[26rpx]">
<u-button type="primary" shape="circle" @click="logoutHandle"> 退出登录 </u-button>
<u-button type="primary" shape="circle" @click="showLogout = true"> 退出登录</u-button>
</view>
<u-action-sheet
@@ -68,23 +76,71 @@
@click="handleClick"
:safe-area-inset-bottom="true"
></u-action-sheet>
<u-popup
class="pay-popup"
v-model="showLogout"
round
mode="center"
borderRadius="10"
:maskCloseAble="false"
>
<view class="content bg-white w-[560rpx] p-[40rpx]">
<view class="text-2xl font-medium text-center"> 温馨提示</view>
<view class="pt-[30rpx] pb-[40rpx]">
<view> 是否清除当前登录信息退出登录</view>
</view>
<view class="flex">
<view class="flex-1 mr-[20rpx]">
<u-button
shape="circle"
type="primary"
plain
size="medium"
hover-class="none"
:customStyle="{ width: '100%' }"
@click="showLogout = false"
>
取消
</u-button>
</view>
<view class="flex-1">
<u-button
shape="circle"
type="primary"
size="medium"
hover-class="none"
:customStyle="{ width: '100%' }"
@click="logoutHandle"
>
确认
</u-button>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
import { mnpAuthBind, oaAuthBind } from '@/api/user'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { ref, computed } from 'vue'
import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user'
import { AgreementEnum } from '@/enums/agreementEnums'
import { isWeixinClient } from '@/utils/client'
import {onLoad, onShow} from '@dcloudio/uni-app'
import {computed, ref} from 'vue'
import {useAppStore} from '@/stores/app'
import {useUserStore} from '@/stores/user'
import {AgreementEnum} from '@/enums/agreementEnums'
import {isWeixinClient} from '@/utils/client'
import {mnpAuthBind, oaAuthBind} from '@/api/account'
import {useLockFn} from '@/hooks/useLockFn'
import {useRouter} from "uniapp-router-next";
// #ifdef H5
import wechatOa from '@/utils/wechat'
import { useLockFn } from '@/hooks/useLockFn'
// #endif
const router = useRouter()
const appStore = useAppStore()
const userStore = useUserStore()
const userInfo = computed(() => userStore.userInfo)
const list = ref([
{
text: '修改密码'
@@ -100,53 +156,45 @@ isWeixin.value = isWeixinClient()
// #endif
const show = ref(false)
const showLogout = ref(false)
// 修改/忘记密码
const handleClick = (index: number) => {
switch (index) {
case 0:
uni.navigateTo({ url: '/pages/change_password/change_password' })
router.navigateTo('/pages/change_password/change_password')
break
case 1:
uni.navigateTo({ url: '/pages/forget_pwd/forget_pwd' })
router.navigateTo('/pages/forget_pwd/forget_pwd')
break
}
}
const handlePwd = () => {
if (!userInfo.value.hasPwd)
return uni.navigateTo({ url: '/pages/change_password/change_password?type=set' })
if (!userInfo.value.has_password)
return router.navigateTo('/pages/change_password/change_password?type=set')
show.value = true
}
// 退出登录
const logoutHandle = () => {
uni.showModal({
content: '是否退出登录?',
confirmColor: '#4173FF',
success: ({ cancel }) => {
if (cancel) return
userStore.logout()
uni.redirectTo({ url: '/pages/login/login' })
}
})
userStore.logout()
router.redirectTo('/pages/login/login')
}
const bindWechat = async () => {
if (userInfo.value.isBindWechat) return
if (userInfo.value.is_auth) return
try {
uni.showLoading({
title: '请稍后...'
})
// #ifdef MP-WEIXIN
const { code }: any = await uni.login({
const {code}: any = await uni.login({
provider: 'weixin'
})
await mnpAuthBind({
code: code
})
uni.$u.toast('绑定成功')
//#endif
// #ifdef H5
if (isWeixin.value) {
@@ -160,28 +208,27 @@ const bindWechat = async () => {
uni.$u.toast(e)
}
}
const { lockFn: bindWechatLock } = useLockFn(bindWechat)
const {lockFn: bindWechatLock} = useLockFn(bindWechat)
onShow(() => {
userStore.getUser()
})
onLoad(async (options) => {
// #ifdef H5
const { code } = options
const {code} = options
if (!isWeixin.value) return
if (code) {
uni.showLoading({
title: '请稍后...'
})
try {
await oaAuthBind({ code })
uni.$u.toast('绑定成功')
await oaAuthBind({code})
await userStore.getUser()
} catch (error) {}
} catch (error) {
}
//用于清空code
uni.redirectTo({
url: '/pages/user_set/user_set'
})
router.redirectTo('/pages/user_set/user_set')
}
// #endif

View File

@@ -1,14 +1,18 @@
// #ifdef H5
// 提交前需要注释 本地调试使用
import Vconsole from 'vconsole'
import { isDevMode } from '@/utils/env'
// #endif
// url中携带参数vconsole == vconsoleMd5时打开Vconsole可以用于手机浏览器中调试
// 如/mobile/pages/user/user?vconsole=47b1e3a9d33e6064e58cc4796c708447此时在个人中心页面打开vconsole
export default () => {
const vconsoleMd5 = '47b1e3a9d33e6064e58cc4796c708447'
export default async () => {
// #ifdef H5
if (isDevMode()) {
const url = new URL(location.href)
const searchParams = new URLSearchParams(url.search)
const vconsole = searchParams.get('vconsole')
if (vconsole == vconsoleMd5) {
const module: any = await import('vconsole')
const Vconsole = module.default
const vConsole = new Vconsole()
return vConsole
}
// #endif
}

View File

@@ -1,56 +1,91 @@
import routes from 'uni-router-routes'
import { createRouter } from 'uniapp-router-next'
import { ClientEnum } from '@/enums/appEnums'
import { BACK_URL } from '@/enums/cacheEnums'
import { useUserStore } from '@/stores/user'
import { getToken } from '@/utils/auth'
import cache from '@/utils/cache'
import { client } from '@/utils/client'
// #ifdef H5
import wechatOa from '@/utils/wechat'
// #endif
import { routes } from './routes'
import cache from '@/utils/cache'
import { BACK_URL } from '@/enums/constantEnums'
const whiteList = ['register', 'login', 'forget_pwd']
const list = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab']
list.forEach((item) => {
uni.addInterceptor(item, {
invoke(e) {
// 获取要跳转的页面路径url去掉"?"和"?"后的参数)
const url = e.url.split('?')[0]
const currentRoute = routes.find((item) => {
return url === item.path
})
// 需要登录并且没有token
if (currentRoute?.auth && !getToken()) {
uni.navigateTo({
url: '/pages/login/login'
})
return false
const router = createRouter({
routes: [
...routes,
{
path: '*',
redirect() {
return {
name: '404'
}
}
return e
},
fail(err) {
// 失败回调拦截
console.log(err)
}
})
],
debug: import.meta.env.DEV,
//@ts-ignore
platform: process.env.UNI_PLATFORM,
h5: {}
})
export function setupRouter() {
// #ifdef H5
const app = getApp()
app.$router.afterEach((to: any, from: any) => {
const index = whiteList.findIndex((item) => from.path.includes(item) || from.path === '/')
//存储登陆前的页面
let isFirstEach = true
router.beforeEach(async (to, from) => {
//保存第一次进来时的页面路径(需要登陆才能访问的页面)
if (isFirstEach) {
const userStore = useUserStore()
if (index == -1 && !userStore.isLogin) {
//保存登录前的路径
cache.set(BACK_URL, from.fullPath)
if (!userStore.isLogin && !to.meta.white) {
cache.set(BACK_URL, to.fullPath)
}
})
isFirstEach = false
}
})
router.afterEach((to, from) => {
const userStore = useUserStore()
if (!userStore.isLogin && !to.meta.white) {
cache.set(BACK_URL, to.fullPath)
}
})
// 登录拦截
router.beforeEach(async (to, from) => {
const userStore = useUserStore();
if (!userStore.isLogin && to.meta.auth) {
return '/pages/login/login'
}
})
// #ifdef H5
//用于收集微信公众号的授权的code并清除路径上微信带的参数
router.beforeEach(async (to, form) => {
const { code, state, scene } = to.query
if (code && state && scene) {
wechatOa.setAuthData({
code,
scene
})
//收集完删除路径上的参数
delete to.query.code
delete to.query.state
return {
path: to.path,
force: true,
navType: 'reLaunch',
query: to.query
}
}
})
// #endif
// #ifdef H5
router.afterEach((to, from) => {
setTimeout(async () => {
if (client == ClientEnum.OA_WEIXIN) {
if (client == ClientEnum.OA_WEIXIN && !to.meta.webview) {
// jssdk配置
await wechatOa.config()
}
})
// #endif
}
})
// #endif
export default router

View File

@@ -1,47 +0,0 @@
import PagesJSON from '../pages.json'
const CONFIG = {
includes: ['path', 'aliasPath', 'name', 'auth']
}
function getPagesRoutes(pages: any[], rootPath = null) {
const routes: any[] = []
for (let i = 0; i < pages.length; i++) {
const item = pages[i]
const route: any = {}
for (let j = 0; j < CONFIG.includes.length; j++) {
const key = CONFIG.includes[j]
let value = item[key]
if (key === 'path') {
value = rootPath ? `/${rootPath}/${value}` : `/${value}`
}
if (key === 'aliasPath' && i == 0 && rootPath == null) {
route[key] = route[key] || '/'
} else if (value !== undefined) {
route[key] = value
}
}
routes.push(route)
}
return routes
}
function getSubPackagesRoutes(pagesJson: any) {
const { subPackages } = pagesJson
let routes: any[] = []
if (subPackages == null || subPackages.length == 0) {
return []
}
for (let i = 0; i < subPackages.length; i++) {
const subPages = subPackages[i].pages
const root = subPackages[i].root
const subRoutes = getPagesRoutes(subPages, root)
routes = routes.concat(subRoutes)
}
return routes
}
export function generateRoutes() {
return getPagesRoutes(PagesJSON.pages).concat(getSubPackagesRoutes(PagesJSON))
}
export const routes = generateRoutes()

Binary file not shown.

After

Width:  |  Height:  |  Size: 972 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -14,11 +14,12 @@ export const useAppStore = defineStore({
getLoginConfig: (state) => state.config.login || {},
getTabbarConfig: (state) => state.config.tabbar || [],
getStyleConfig: (state) => state.config.style || {},
getH5Config: (state) => state.config.h5 || {}
getH5Config: (state) => state.config.webPage || {},
getCopyrightConfig: (state) => state.config.copyright || [],
},
actions: {
getImageUrl(url: string) {
return url ? `${this.config.domain}${url}` : ''
return url.indexOf('http') ? `${this.config.domain}${url}` : url
},
async getConfig() {
const data = await getConfig()

View File

@@ -0,0 +1,54 @@
import { getDecorate } from '@/api/shop'
import { generateVars } from '@/utils/theme'
import { defineStore } from 'pinia'
interface ThemeStore {
primaryColor: string
minorColor: string
btnColor: string
navColor: string
navBgColor: string
vars: string
}
export const useThemeStore = defineStore({
id: 'themeStore',
state: (): ThemeStore => ({
primaryColor: '',
minorColor: '',
btnColor: 'white',
navColor: '#000000',
navBgColor: '#ffffff',
vars: ''
}),
actions: {
async getTheme() {
const data = await getDecorate({
id: 5
})
const {
themeColor1,
themeColor2,
buttonColor,
navigationBarColor,
topTextColor
} = JSON.parse(data.data)
this.primaryColor = themeColor1
this.minorColor = themeColor2
this.btnColor = buttonColor
this.navColor = topTextColor === 'white' ? '#ffffff' : '#000000'
this.navBgColor = navigationBarColor || themeColor1
this.vars = generateVars(
{
primary: themeColor1
},
{
'--color-minor': themeColor2,
'--color-btn-text': buttonColor
}
)
},
setTheme(color: string) {
this.primaryColor = color
}
}
})

View File

@@ -1,5 +1,5 @@
import { getUserCenter } from '@/api/user'
import { TOKEN_KEY } from '@/enums/cacheEnums'
import { TOKEN_KEY } from '@/enums/constantEnums'
import cache from '@/utils/cache'
import { defineStore } from 'pinia'

View File

@@ -1,4 +1,16 @@
page {
background-color: $u-bg-color;
font-size: 28rpx;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: theme('fontFamily.sans')
//font-family: PingFang SC;
}
uni-modal {
z-index: 999999 !important;
}
button::after {
border: initial;
}

View File

@@ -1,37 +1,41 @@
@import '@/uni_modules/vk-uview-ui/theme.scss';
// 替换uview颜色变量
$u-main-color: theme("colors.main");
$u-content-color: theme("colors.content");
$u-tips-color: theme("colors.muted");
$u-light-color: theme("colors.light");
$u-border-color: theme("colors.light");
$u-bg-color: theme("colors.page");
$u-disabled-color: theme("colors.disabled");
$u-minor-color: theme("colors[minor]");
$u-type-primary: theme("colors.primary.DEFAULT");
$u-type-primary-disabled: theme("colors.primary[light-3]");
$u-type-primary-dark: theme("colors.primary[dark-2]");
$u-type-primary-light: theme("colors.primary[light-9]");
$u-main-color: #333333;
$u-content-color: #666666;
$u-tips-color: #999999;
$u-light-color: #c0c4cc;
$u-border-color: #e5e5e5;
$u-bg-color: #f3f4f6;
$u-disabled-color: #c8c9cc;
$u-type-warning: theme("colors.warning.DEFAULT");
$u-type-warning-disabled: theme("colors.warning[light-3]");
$u-type-warning-dark: theme("colors.warning[dark-2]");
$u-type-warning-light: theme("colors.warning[light-9]");
$u-type-primary: #4173ff;
$u-type-primary-light: #ecf5ff;
$u-type-primary-disabled: #a0cfff;
$u-type-primary-dark: #2b85e4;
$u-type-success: theme("colors.success.DEFAULT");
$u-type-success-disabled: theme("colors.success[light-3]");
$u-type-success-dark: theme("colors.success[dark-2]");
$u-type-success-light: theme("colors.success[light-9]");
$u-type-warning: #ff9900;
$u-type-warning-disabled: #fcbd71;
$u-type-warning-dark: #f29100;
$u-type-warning-light: #fdf6ec;
$u-type-error: theme("colors.error.DEFAULT");
$u-type-error-disabled: theme("colors.error[light-3]");
$u-type-error-dark: theme("colors.error[dark-2]");
$u-type-error-light: theme("colors.error[light-9]");
$u-type-success: #19be6b;
$u-type-success-disabled: #71d5a1;
$u-type-success-dark: #18b566;
$u-type-success-light: #dbf1e1;
$u-type-error: #fa3534;
$u-type-error-disabled: #fab6b6;
$u-type-error-dark: #dd6161;
$u-type-error-light: #fef0f0;
$u-type-info: #909399;
$u-type-info-disabled: #c8c9cc;
$u-type-info-dark: #82848a;
$u-type-info-light: #f4f4f5;
$u-type-info: theme("colors.info.DEFAULT");
$u-type-info-disabled: theme("colors.info[light-3]");
$u-type-info-dark: theme("colors.info[dark-2]");
$u-type-info-light: theme("colors.info[light-9]");
$u-form-item-height: 60rpx;
$u-form-item-border-color: #e5e5e5;
$u-form-item-border-color: theme("colors.light");
$-color-white: theme("colors.white");
$-color-black: theme("colors.black");
$u-color-btn-text: theme("colors[btn-text]");

View File

@@ -524,7 +524,6 @@ export default {
font-size: 26rpx;
height: 70rpx;
line-height: 70rpx;
padding: 0 80rpx;
}
.u-size-mini {
@@ -532,7 +531,7 @@ export default {
display: inline-flex;
/* #endif */
width: auto;
font-size: 22rpx;
font-size: 24rpx;
padding-top: 1px;
height: 50rpx;
line-height: 50rpx;

View File

@@ -9,16 +9,18 @@
</view>
<view class="u-icon-wrap u-back-text u-line-1" v-if="backText" :style="[backTextStyle]">{{ backText }}</view>
</view>
<view class="u-navbar-content-title" v-if="title" :style="[titleStyle]">
<view
class="u-title u-line-1"
:style="{
<view class="u-navbar-content-title" v-if="title || customTitle" :style="[titleStyle]">
<slot name="title" v-if="customTitle"></slot>
<view
v-else
class="u-title u-line-1"
:style="{
color: titleColor,
fontSize: titleSize + 'rpx',
fontWeight: titleBold ? 'bold' : 'normal'
}">
{{ title }}
</view>
{{ title }}
</view>
</view>
<view class="u-slot-content">
<slot></slot>
@@ -101,6 +103,11 @@
}
}
},
// 自定义导航栏标题
customTitle: {
type: Boolean,
default: false
},
// 导航栏标题
title: {
type: String,

View File

@@ -122,7 +122,7 @@ export default {
// 拉取父组件新的变化后的参数
parentData() {
return [
this.value,
this.valueCom,
this.disabled,
this.activeColor,
this.size,
@@ -173,4 +173,4 @@ export default {
flex-wrap: wrap;
/* #endif */
}
</style>
</style>

View File

@@ -117,6 +117,7 @@
this.observeContent();
});
});
},
observeContent() {
this.disconnectObserver('contentObserver');

View File

@@ -336,7 +336,7 @@ export default {
&__text {
color: $u-content-color;
font-size: 22rpx;
font-size: 20rpx;
line-height: 28rpx;
position: absolute;
bottom: 14rpx;

View File

@@ -1,6 +1,6 @@
import { TOKEN_KEY } from '@/enums/cacheEnums'
import { TOKEN_KEY } from '@/enums/constantEnums'
import cache from './cache'
export function getToken() {
return cache.get(TOKEN_KEY) || ''
return cache.get(TOKEN_KEY)
}

View File

@@ -1,7 +1,7 @@
const cache = {
key: 'app_',
//设置缓存(expire为缓存时效)
set(key: string, value: any, expire?: string) {
set(key: string, value: any, expire?: number) {
key = this.getKey(key)
let data: any = {
expire: expire ? this.time() + expire : '',
@@ -14,7 +14,7 @@ const cache = {
try {
uni.setStorageSync(key, data)
} catch (e) {
return undefined
return null
}
},
get(key: string) {
@@ -22,16 +22,16 @@ const cache = {
try {
const data = uni.getStorageSync(key)
if (!data) {
return undefined
return null
}
const { value, expire } = JSON.parse(data)
if (expire && expire < this.time()) {
uni.removeStorageSync(key)
return undefined
return null
}
return value
} catch (e) {
return undefined
return null
}
},
//获取当前时间

View File

@@ -0,0 +1,21 @@
export class MiddleWare {
private middleware = new Map()
private nextIterator = this.middleware.values()
use(fn: any) {
if (typeof fn !== 'function') {
throw 'middleware must be a function'
}
this.middleware.set(fn, fn)
return this
}
private next(params?: any): any {
const middleware = this.nextIterator.next().value
if (middleware) {
middleware.call(this, this.next.bind(this), params)
}
}
run() {
this.nextIterator = this.middleware.values()
this.next()
}
}

View File

@@ -0,0 +1,65 @@
import { PayStatusEnum } from '@/enums/appEnums'
import { handleClientEvent } from '../client'
export class Alipay {
init(name: string, pay: any) {
pay[name] = this
}
openNewPage(options: any) {
uni.navigateBack()
const alipayPage = window.open('', '_self')!
alipayPage.document.body.innerHTML = options
alipayPage.document.forms[0].submit()
}
async run(options: any) {
try {
const res = await handleClientEvent({
H5: () => {
return new Promise((resolve) => {
this.openNewPage(options)
resolve(PayStatusEnum.PENDING)
})
},
OA_WEIXIN: () => {
return new Promise((resolve) => {
this.openNewPage(options)
resolve(PayStatusEnum.PENDING)
})
},
ANDROID: () => {
// const option =
return new Promise((resolve, reject) => {
uni.requestPayment({
provider: 'alipay',
orderInfo: options,
success() {
resolve(PayStatusEnum.SUCCESS)
},
fail() {
resolve(PayStatusEnum.FAIL)
}
})
})
},
IOS: () => {
// const option =
return new Promise((resolve, reject) => {
uni.requestPayment({
provider: 'alipay',
orderInfo: options,
success() {
resolve(PayStatusEnum.SUCCESS)
},
fail() {
resolve(PayStatusEnum.FAIL)
}
})
})
}
})
return res
} catch (error) {
return Promise.reject(error)
}
}
}

View File

@@ -1,4 +1,5 @@
import { Pay } from './pay'
import { Alipay } from './alipay'
import { Wechat } from './wechat'
// 支付方式
@@ -7,8 +8,14 @@ enum PayWayEnum {
WECHAT = 2,
ALIPAY = 3
}
const wechat = new Wechat()
// 注入微信支付
const wechat = new Wechat()
Pay.inject(PayWayEnum[2], wechat)
// 注入支付宝支付
const alipay = new Alipay()
Pay.inject(PayWayEnum[3], alipay)
const pay = new Pay()
export { pay, PayWayEnum }

View File

@@ -13,15 +13,9 @@ export class Wechat {
const res = await handleClientEvent({
MP_WEIXIN: () => {
return new Promise((resolve) => {
console.log(options)
uni.requestPayment({
orderInfo: '',
provider: 'wxpay',
timeStamp: options.timeStamp,
nonceStr: options.nonceStr,
package: options.packageValue,
paySign: options.paySign,
signType: options.signType,
...options,
success() {
resolve(PayStatusEnum.SUCCESS)
},
@@ -45,7 +39,7 @@ export class Wechat {
},
H5: () => {
return new Promise((resolve) => {
window.open(options.url, '_self')
window.open(options, '_self')
resolve(PayStatusEnum.PENDING)
})
}

View File

@@ -1,94 +1,84 @@
import HttpRequest from './http'
import { merge } from 'lodash-es'
import { HttpRequestOptions, RequestHooks } from './type'
import { getToken } from '../auth'
import { RequestCodeEnum, RequestMethodsEnum } from '@/enums/requestEnums'
import { useUserStore } from '@/stores/user'
import { client } from '../client'
import HttpRequest from "./http";
import { merge } from "lodash-es";
import { HttpRequestOptions, RequestHooks } from "./type";
import { getToken } from "../auth";
import { RequestCodeEnum, RequestMethodsEnum } from "@/enums/requestEnums";
import { useUserStore } from "@/stores/user";
import appConfig from "@/config";
import { getClient } from "../client";
const requestHooks: RequestHooks = {
requestInterceptorsHook(options, config) {
const { urlPrefix, baseUrl, withToken } = config
options.header = options.header ?? {}
const { urlPrefix, baseUrl, withToken, isAuth } = config;
options.header = options.header ?? {};
if (urlPrefix) {
options.url = `${urlPrefix}${options.url}`
options.url = `${urlPrefix}${options.url}`;
}
if (baseUrl) {
options.url = `${baseUrl}${options.url}`
options.url = `${baseUrl}${options.url}`;
}
const token = getToken()
const token = getToken();
// 添加token
if (withToken) {
options.header['like-token'] = options.header.token || token
if (withToken && !options.header.token) {
options.header.token = token;
}
// 添加终端类型
options.header['terminal'] = client
delete options.header.token
return options
options.header.version = appConfig.version;
// options.header.terminal = getClient();
return options;
},
async responseInterceptorsHook(response, config) {
const { isTransformResponse, isReturnDefaultResponse, isAuth } = config
const { isTransformResponse, isReturnDefaultResponse, isAuth } = config;
//返回默认响应,当需要获取响应头及其他数据时可使用
if (isReturnDefaultResponse) {
return response
return response;
}
// 是否需要对数据进行处理
if (!isTransformResponse) {
return response.data
return response.data;
}
const { logout } = useUserStore()
const { code, data, msg, show } = response.data as any
const { logout } = useUserStore();
const { code, data, msg, show } = response.data as any;
switch (code) {
case RequestCodeEnum.SUCCESS:
return data
case RequestCodeEnum.PARAMS_TYPE_ERROR:
case RequestCodeEnum.PARAMS_VALID_ERROR:
case RequestCodeEnum.REQUEST_METHOD_ERROR:
case RequestCodeEnum.ASSERT_ARGUMENT_ERROR:
case RequestCodeEnum.ASSERT_MYBATIS_ERROR:
case RequestCodeEnum.LOGIN_ACCOUNT_ERROR:
case RequestCodeEnum.LOGIN_DISABLE_ERROR:
case RequestCodeEnum.NO_PERMISSTION:
msg && show && uni.$u.toast(msg);
return data;
case RequestCodeEnum.FAILED:
case RequestCodeEnum.SYSTEM_ERROR:
case RequestCodeEnum.REQUEST_404_ERROR:
uni.$u.toast(msg)
return Promise.reject(msg)
uni.$u.toast(msg);
return Promise.reject(msg);
case RequestCodeEnum.TOKEN_INVALID:
case RequestCodeEnum.TOKEN_EMPTY:
logout()
logout();
if (isAuth && !getToken()) {
uni.navigateTo({
url: '/pages/login/login'
})
url: "/pages/login/login",
});
}
return Promise.reject()
return Promise.reject(msg);
default:
return data
return data;
}
},
async responseInterceptorsCatchHook(options, error) {
if (options.method?.toUpperCase() == RequestMethodsEnum.POST) {
uni.$u.toast('请求失败,请重试')
uni.$u.toast("请求失败,请重试");
}
return Promise.reject(error)
}
}
return Promise.reject(error);
},
};
const defaultOptions: HttpRequestOptions = {
requestOptions: {
timeout: 10 * 1000
timeout: appConfig.timeout,
},
baseUrl: `${import.meta.env.VITE_APP_BASE_URL || ''}/`,
baseUrl: appConfig.baseUrl,
//是否返回默认的响应
isReturnDefaultResponse: false,
// 需要对返回数据进行处理
isTransformResponse: true,
// 接口拼接地址
urlPrefix: 'api',
urlPrefix: "api",
// 忽略重复请求
ignoreCancel: false,
// 是否携带token
@@ -96,14 +86,14 @@ const defaultOptions: HttpRequestOptions = {
isAuth: false,
retryCount: 2,
retryTimeout: 1000,
requestHooks: requestHooks
}
requestHooks: requestHooks,
};
function createRequest(opt?: HttpRequestOptions) {
return new HttpRequest(
// 深度合并
merge(defaultOptions, opt || {})
)
);
}
const request = createRequest()
export default request
const request = createRequest();
export default request;

63
uniapp/src/utils/theme.ts Normal file
View File

@@ -0,0 +1,63 @@
import colors from 'css-color-function'
const lightConfig = {
'dark-2': 'shade(20%)',
'light-3': 'tint(30%)',
'light-5': 'tint(50%)',
'light-7': 'tint(70%)',
'light-9': 'tint(90%)'
}
const darkConfig = {
'light-3': 'shade(20%)',
'light-5': 'shade(30%)',
'light-7': 'shade(50%)',
'light-9': 'shade(70%)',
'dark-2': 'tint(20%)'
}
/**
* @author Jason
* @description 用于生成主题的行为变量
* 可选值有primary、success、warning、error、info
*/
export const generateVarsMap = (
color: string,
type = 'primary',
isDark = false
) => {
const colors = {
[`--color-${type}`]: color
}
const config: Record<string, string> = isDark ? darkConfig : lightConfig
for (const key in config) {
colors[`--color-${type}-${key}`] = `color(${color} ${config[key]})`
}
return colors
}
/**
* @author Jason
* @description 生成主题
*/
export const generateVars = (
options: Record<string, string>,
extra: Record<string, string> = {},
isDark = false
) => {
const varsMap: Record<string, string> = Object.keys(options).reduce(
(prev, key) => {
return Object.assign(
prev,
generateVarsMap(options[key], key, isDark)
)
},
extra
)
const vars = Object.keys(varsMap).reduce((prev, key) => {
const color = colors.convert(varsMap[key])
return `${prev}${key}:${color};`
}, '')
return vars
}

View File

@@ -1,4 +1,6 @@
import { isObject } from '@vue/shared'
import {isObject} from '@vue/shared'
import {getToken} from './auth'
import {parseQuery} from "uniapp-router-next";
/**
* @description 获取元素节点信息在组件中的元素必须要传ctx
@@ -8,11 +10,11 @@ import { isObject } from '@vue/shared'
*/
export const getRect = (selector: string, all = false, context?: any) => {
return new Promise((resolve, reject) => {
let query = uni.createSelectorQuery()
let qurey = uni.createSelectorQuery()
if (context) {
query = uni.createSelectorQuery().in(context)
qurey = uni.createSelectorQuery().in(context)
}
query[all ? 'selectAll' : 'select'](selector)
qurey[all ? 'selectAll' : 'select'](selector)
.boundingClientRect(function (rect) {
if (all && Array.isArray(rect) && rect.length) {
return resolve(rect)
@@ -42,19 +44,64 @@ interface Link {
path: string
name?: string
type: string
isTab: boolean
canTab: boolean
query?: Record<string, any>
}
export enum LinkTypeEnum {
'SHOP_PAGES' = 'shop',
'CUSTOM_LINK' = 'custom'
'CUSTOM_LINK' = 'custom',
'MINI_PROGRAM' = 'mini_program'
}
export function navigateTo(link: Link, navigateType: 'navigateTo' | 'reLaunch' = 'navigateTo') {
const url = link.query ? `${link.path}?${objectToQuery(link.query)}` : link.path
navigateType == 'navigateTo' && uni.navigateTo({ url })
navigateType == 'reLaunch' && uni.reLaunch({ url })
export function navigateTo(link: Link, navigateType: 'navigateTo' | 'switchTab' | 'reLaunch' = 'navigateTo') {
// 如果是小程序跳转
if (link.type === LinkTypeEnum.MINI_PROGRAM) {
navigateToMiniProgram(link)
return
}
const url = link?.query ? `${link.path}?${objectToQuery(link?.query)}` : link.path;
(navigateType == 'switchTab' || link.canTab) && uni.switchTab({url})
navigateType == 'navigateTo' && uni.navigateTo({url})
navigateType == 'reLaunch' && uni.reLaunch({url})
}
/**
* @description 小程序跳转
* @param link 跳转信息,由装修数据进行输入
*/
export function navigateToMiniProgram(link: Link) {
const query = link.query;
// #ifdef H5
window.open(
`weixin://dl/business/?appid=${query?.appId}&path=${query?.path}&env_version=${query?.env_version}&query=${encodeURIComponent(query?.query)}`
)
// #endif
// #ifdef MP
uni.navigateToMiniProgram({
appId: query?.appId,
path: query?.path,
extraData: parseQuery(query?.query),
envVersion: query?.env_version,
})
// #endif
}
/**
* @description 将一个数组分成几个同等长度的数组
* @param { Array } array[分割的原数组]
* @param { Number } size[每个子数组的长度]
*/
export const sliceArray = (array: any[], size: number) => {
const result = []
for (let x = 0; x < Math.ceil(array.length / size); x++) {
const start = x * size
const end = start + size
result.push(array.slice(start, end))
}
return result
}
/**
@@ -94,13 +141,22 @@ export function objectToQuery(params: Record<string, any>): string {
return query.slice(0, -1)
}
/**
* @description 添加单位
* @param {String | Number} value 值 100
* @param {String} unit 单位 px em rem
*/
export const addUnit = (value: string | number, unit = 'rpx') => {
return !Object.is(Number(value), NaN) ? `${value}${unit}` : value
}
/**
* @description 格式化输出价格
* @param { string } price 价格
* @param { string } take 小数点操作
* @param { string } prec 小数位补
*/
export function formatPrice({ price, take = 'all', prec = undefined }: any) {
export function formatPrice({price, take = 'all', prec = undefined}: any) {
let [integer, decimals = ''] = (price + '').split('.')
// 小数位补
@@ -120,7 +176,6 @@ export function formatPrice({ price, take = 'all', prec = undefined }: any) {
}
}
/**
* @description 组合异步任务
* @param { string } task 异步任务
@@ -142,12 +197,3 @@ export function series(...task: Array<(_arg: any) => any>) {
})
}
}
/**
* @description 添加单位
* @param {String | Number} value 值 100
* @param {String} unit 单位 px em rem
*/
export const addUnit = (value: string | number, unit = 'rpx') => {
return !Object.is(Number(value), NaN) ? `${value}${unit}` : value
}

View File

@@ -1,18 +1,47 @@
import weixin from 'weixin-js-sdk'
import { getWxCodeUrl, OALogin } from '@/api/account'
import wx from 'weixin-js-sdk'
import { getWxCodeUrl } from '@/api/account'
import { isAndroid } from './client'
import { wxJsConfig } from '@/api/app'
import { objectToQuery } from './util'
export enum UrlScene {
LOGIN = 'login',
PC_LOGIN = 'pcLogin',
BIND_WX = 'bindWx',
BASE = 'base'
}
const wechatOa = {
_authData: {
code: '',
scene: ''
},
setAuthData(data: any = {}) {
this._authData = data
},
getAuthData() {
return this._authData
},
getSignLink() {
if (typeof window.signLink === 'undefined' || window.signLink === '') {
window.signLink = location.href.split('#')[0]
}
return isAndroid() ? location.href.split('#')[0] : window.signLink
},
getUrl() {
getWxCodeUrl().then((res) => {
location.href = res.url
getUrl(
scene: UrlScene,
scope = 'snsapi_userinfo',
extra = {}
): Promise<void> {
const currentUrl = `${location.href}${
location.search ? '&' : '?'
}scene=${scene || ''}&${objectToQuery(extra)}`
return new Promise((resolve, reject) => {
getWxCodeUrl({
url: currentUrl,
scope
}).then((res) => {
location.href = res.url
resolve()
}, reject)
})
},
config() {
@@ -20,39 +49,26 @@ const wechatOa = {
wxJsConfig({
url: this.getSignLink()
}).then((res) => {
weixin.config({
appId: res.appid, // 必填,公众号的唯一标识
timestamp: res.timestamp, // 必填,生成签名的时间戳
nonceStr: res.nonceStr, // 必填,生成签名的随机串
signature: res.signature, // 必填,签名
jsApiList: res.jsApiList,
wx.config({
...res,
success: () => {
resolve('success')
},
fail: (res: any) => {
reject('weixin config is fail')
reject('wx config is fail')
}
})
})
})
},
authLogin(code: string) {
miniProgram: wx.miniProgram,
ready(): Promise<void> {
return new Promise((resolve, reject) => {
OALogin({
code
wx.ready(() => {
resolve()
})
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
})
},
ready() {
return new Promise((resolve) => {
weixin.ready(() => {
resolve('success')
wx.error(() => {
reject()
})
})
},
@@ -60,10 +76,10 @@ const wechatOa = {
return new Promise((resolve, reject) => {
this.ready()
.then(() => {
weixin.chooseWXPay({
wx.chooseWXPay({
timestamp: options.timeStamp,
nonceStr: options.nonceStr,
package: options.packageValue,
package: options.package,
signType: options.signType,
paySign: options.paySign,
success: (res: any) => {
@@ -86,34 +102,37 @@ const wechatOa = {
})
})
},
share(options: Record<any, any>) {
this.ready().then(() => {
const { shareTitle, shareLink, shareImage, shareDesc } = options
weixin.updateTimelineShareData({
title: shareTitle, // 分享标题
link: shareLink, // 分享链接该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareImage // 分享图标
})
// 发送给好友
weixin.updateAppMessageShareData({
title: shareTitle, // 分享标题
link: shareLink, // 分享链接该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareImage, // 分享图标
desc: shareDesc
})
// 发送到tx微博
weixin.onMenuShareWeibo({
title: shareTitle, // 分享标题
link: shareLink, // 分享链接该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareImage, // 分享图标
desc: shareDesc
})
async share(options: Record<any, any>): Promise<void> {
return new Promise((resolve, reject) => {
this.ready()
.then(() => {
const { title, link, imgUrl, desc } = options
const shareApi = [
'updateTimelineShareData',
'updateAppMessageShareData'
]
for (const api of shareApi) {
wx[api]({
title: title,
link: link,
imgUrl: imgUrl,
desc: desc,
success() {
resolve()
},
fail() {
reject()
}
})
}
})
.catch(reject)
})
},
getAddress() {
return new Promise((reslove, reject) => {
this.ready().then(() => {
weixin.openAddress({
wx.openAddress({
success: (res: any) => {
reslove(res)
},
@@ -125,12 +144,42 @@ const wechatOa = {
})
},
getLocation() {
return new Promise((reslove, reject) => {
return new Promise((resolve, reject) => {
this.ready().then(() => {
weixin.getLocation({
wx.getLocation({
type: 'gcj02',
success: (res: any) => {
reslove(res)
resolve(res)
},
fail: (res: any) => {
reject(res)
}
})
})
})
},
hideMenuItems(menuList: string[]) {
return new Promise((resolve, reject) => {
this.ready().then(() => {
wx.hideMenuItems({
menuList,
success: (res: any) => {
resolve(res)
},
fail: (res: any) => {
reject(res)
}
})
})
})
},
showMenuItems(menuList: string[]) {
return new Promise((resolve, reject) => {
this.ready().then(() => {
wx.showMenuItems({
menuList,
success: (res: any) => {
resolve(res)
},
fail: (res: any) => {
reject(res)