新增
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<view class="p-[30rpx]">
|
||||
<u-parse :html="agreementContent"></u-parse>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getPolicy } from '@/api/app'
|
||||
|
||||
let agreementType = ref('') // 协议类型
|
||||
const agreementContent = ref('') // 协议内容
|
||||
|
||||
const getData = async (type) => {
|
||||
const res = await getPolicy({ type })
|
||||
agreementContent.value = res.content
|
||||
uni.setNavigationBarTitle({
|
||||
title: String(res.title)
|
||||
})
|
||||
}
|
||||
|
||||
onLoad((options: any) => {
|
||||
if (options.type) {
|
||||
agreementType = options.type
|
||||
getData(agreementType)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,30 @@
|
||||
<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.getWebsiteConfig.shop_logo" mode="" class="img"></image>
|
||||
<view class="text-content mt-[20rpx]">当前版本{{ appStore.config.version }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppStore } from '@/stores/app'
|
||||
const appStore = useAppStore()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.as-us {
|
||||
.img {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 20rpx;
|
||||
margin-top: 96rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,112 @@
|
||||
<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">
|
||||
<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秒"
|
||||
/>
|
||||
<text :class="formData.mobile ? 'text-primary' : 'text-muted'">
|
||||
{{ codeTips }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-[40rpx]">
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { userBindMobile } from '@/api/user'
|
||||
import { smsSend } from '@/api/app'
|
||||
import { SMSEnum } from '@/enums/appEnums'
|
||||
import { reactive, ref, shallowRef } from 'vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
const uCodeRef = shallowRef()
|
||||
const codeTips = ref('')
|
||||
|
||||
const userStore = useUserStore()
|
||||
const codeChange = (text: string) => {
|
||||
codeTips.value = text
|
||||
}
|
||||
|
||||
const formData = reactive({
|
||||
type: 'bind',
|
||||
mobile: '',
|
||||
code: ''
|
||||
})
|
||||
const sendSms = async () => {
|
||||
if (!formData.mobile) return uni.$u.toast('请输入手机号码')
|
||||
if (uCodeRef.value?.canGetCode) {
|
||||
await smsSend({
|
||||
scene: SMSEnum.BIND_MOBILE,
|
||||
mobile: formData.mobile
|
||||
})
|
||||
uni.$u.toast('发送成功')
|
||||
uCodeRef.value?.start()
|
||||
}
|
||||
}
|
||||
const handleConfirm = async () => {
|
||||
if (!formData.mobile) return uni.$u.toast('请输入手机号码')
|
||||
if (!formData.code) return uni.$u.toast('请输入验证码')
|
||||
await userBindMobile(formData, { token: userStore.temToken })
|
||||
uni.$u.toast('绑定成功')
|
||||
userStore.login(userStore.temToken!)
|
||||
uni.navigateBack()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,90 @@
|
||||
<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"
|
||||
>
|
||||
<view class="w-full">
|
||||
<view class="text-2xl font-medium mb-[60rpx]">
|
||||
{{ type == 'set' ? '设置登录密码' : '修改登录密码' }}
|
||||
</view>
|
||||
<u-form borderBottom :label-width="150">
|
||||
<u-form-item label="原密码" borderBottom v-if="type != 'set'">
|
||||
<u-input
|
||||
class="flex-1"
|
||||
type="password"
|
||||
v-model="formData.old_password"
|
||||
: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.password_confirm"
|
||||
placeholder="再次输入新密码"
|
||||
:border="false"
|
||||
/>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="mt-[100rpx]">
|
||||
<u-button type="primary" shape="circle" @click="handleConfirm"> 确定 </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { userChangePwd } from '@/api/user'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
const type = ref('')
|
||||
const formData = reactive<any>({
|
||||
password: '',
|
||||
password_confirm: ''
|
||||
})
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (!formData.old_password && type.value != 'set') return uni.$u.toast('请输入原来的密码')
|
||||
if (!formData.password) 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()
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
type.value = options.type || ''
|
||||
if (type.value == 'set') {
|
||||
uni.setNavigationBarTitle({
|
||||
title: '设置登录密码'
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,70 @@
|
||||
<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"
|
||||
@query="queryList"
|
||||
:fixed="false"
|
||||
height="100%"
|
||||
use-page-scroll
|
||||
>
|
||||
<u-swipe-action
|
||||
:show="item.show"
|
||||
:index="index"
|
||||
v-for="(item, index) in collectData"
|
||||
:key="item.id"
|
||||
@click="handleCollect"
|
||||
:options="options"
|
||||
btn-width="120"
|
||||
>
|
||||
<news-card :item="item" :newsId="item.article_id"></news-card>
|
||||
</u-swipe-action>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, shallowRef } from 'vue'
|
||||
import { getCollect, cancelCollect } from '@/api/news'
|
||||
|
||||
const paging = shallowRef()
|
||||
const options = reactive([
|
||||
{
|
||||
text: '取消收藏',
|
||||
style: {
|
||||
color: '#FFFFFF',
|
||||
backgroundColor: '#FF2C3C'
|
||||
}
|
||||
}
|
||||
])
|
||||
const collectData: any = ref([])
|
||||
|
||||
const queryList = async (pageNo, pageSize) => {
|
||||
const { lists } = await getCollect()
|
||||
lists.forEach((item: any) => {
|
||||
item.show = false
|
||||
})
|
||||
collectData.value = lists
|
||||
paging.value.complete(lists)
|
||||
}
|
||||
|
||||
const handleCollect = async (index: number): Promise<void> => {
|
||||
try {
|
||||
const article_id: number = collectData.value[index].article_id
|
||||
await cancelCollect({ id: article_id })
|
||||
uni.$u.toast('已取消收藏')
|
||||
paging.value.reload()
|
||||
} catch (err) {
|
||||
//TODO handle the exception
|
||||
console.log('取消收藏报错=>', err)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,34 @@
|
||||
<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'">
|
||||
<w-customer-service :content="item.content" :styles="item.styles" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getDecorate } from '@/api/shop'
|
||||
import { reactive } from 'vue'
|
||||
const state = reactive<{
|
||||
pages: any[]
|
||||
}>({
|
||||
pages: []
|
||||
})
|
||||
const getData = async () => {
|
||||
const data = await getDecorate({ id: 3 })
|
||||
state.pages = JSON.parse(data.data)
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,119 @@
|
||||
<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"
|
||||
>
|
||||
<view class="w-full">
|
||||
<view class="text-2xl font-medium mb-[60rpx]">忘记登录密码</view>
|
||||
<u-form borderBottom :label-width="150">
|
||||
<u-form-item label="手机号" borderBottom>
|
||||
<u-input
|
||||
class="flex-1"
|
||||
v-model="formData.mobile"
|
||||
:border="false"
|
||||
placeholder="请输入手机号码"
|
||||
/>
|
||||
</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 }}
|
||||
</text>
|
||||
</view>
|
||||
</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.password_confirm"
|
||||
placeholder="再次输入新密码"
|
||||
:border="false"
|
||||
/>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="mt-[100rpx]">
|
||||
<u-button type="primary" shape="circle" @click="handleConfirm"> 确定 </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { smsSend } from '@/api/app'
|
||||
import { forgotPassword } from '@/api/user'
|
||||
import { SMSEnum } from '@/enums/appEnums'
|
||||
import { reactive, ref, shallowRef } from 'vue'
|
||||
|
||||
const uCodeRef = shallowRef()
|
||||
const codeTips = ref('')
|
||||
const formData = reactive({
|
||||
mobile: '',
|
||||
code: '',
|
||||
password: '',
|
||||
password_confirm: ''
|
||||
})
|
||||
|
||||
const codeChange = (text: string) => {
|
||||
codeTips.value = text
|
||||
}
|
||||
|
||||
const sendSms = async () => {
|
||||
if (!formData.mobile) return
|
||||
if (uCodeRef.value?.canGetCode) {
|
||||
await smsSend({
|
||||
scene: SMSEnum.FIND_PASSWORD,
|
||||
mobile: formData.mobile
|
||||
})
|
||||
uni.$u.toast('发送成功')
|
||||
uCodeRef.value?.start()
|
||||
}
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (!formData.mobile) return uni.$u.toast('请输入手机号码')
|
||||
if (!formData.password) 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)
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<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
|
||||
: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"
|
||||
:isLargeScreen="isLargeScreen"
|
||||
@change="handleBanner"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="item.name == 'nav'">
|
||||
<w-nav :content="item.content" :styles="item.styles"/>
|
||||
</template>
|
||||
<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-lg font-medium"
|
||||
>
|
||||
最新资讯
|
||||
</view>
|
||||
<news-card
|
||||
v-for="item in state.article"
|
||||
:key="item.id"
|
||||
:news-id="item.id"
|
||||
:item="item"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- #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 {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: [],
|
||||
meta: [],
|
||||
article: [],
|
||||
bannerImage: ''
|
||||
})
|
||||
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
|
||||
}
|
||||
|
||||
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" 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: '';
|
||||
width: 8rpx;
|
||||
height: 34rpx;
|
||||
display: block;
|
||||
margin-right: 10rpx;
|
||||
@apply bg-primary;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,480 @@
|
||||
<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-[120rpx] box-border"
|
||||
>
|
||||
<view>
|
||||
<image
|
||||
:src="appStore.getWebsiteConfig.shop_logo"
|
||||
mode="widthFix"
|
||||
class="w-[160rpx] h-[160rpx] rounded-full"
|
||||
/>
|
||||
</view>
|
||||
<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="
|
||||
formData.scene == LoginWayEnum.ACCOUNT &&
|
||||
includeLoginWay(LoginWayEnum.ACCOUNT)
|
||||
"
|
||||
>
|
||||
<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] 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="输入密码"
|
||||
:border="false"
|
||||
/>
|
||||
<navigator url="/pages/forget_pwd/forget_pwd" hover-class="none">
|
||||
<view
|
||||
class="border-l border-solid border-0 border-light pl-3 text-muted leading-4 ml-3"
|
||||
>
|
||||
忘记密码?
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 验证码登录 -->
|
||||
<template
|
||||
v-if="
|
||||
formData.scene == LoginWayEnum.MOBILE &&
|
||||
includeLoginWay(LoginWayEnum.MOBILE)
|
||||
"
|
||||
>
|
||||
<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"
|
||||
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秒"
|
||||
/>
|
||||
<text :class="formData.account ? 'text-primary' : 'text-muted'">
|
||||
{{ codeTips }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</block>
|
||||
|
||||
<view class="mt-[40rpx]" v-if="isOpenAgreement">
|
||||
<u-checkbox v-model="isCheckAgreement" shape="circle">
|
||||
<view class="text-xs flex">
|
||||
已阅读并同意
|
||||
<view @click.stop>
|
||||
<navigator
|
||||
class="text-primary"
|
||||
hover-class="none"
|
||||
url="/pages/agreement/agreement?type=service"
|
||||
>
|
||||
《服务协议》
|
||||
</navigator>
|
||||
</view>
|
||||
|
||||
和
|
||||
<view @click.stop>
|
||||
<navigator
|
||||
class="text-primary"
|
||||
hover-class="none"
|
||||
url="/pages/agreement/agreement?type=privacy"
|
||||
>
|
||||
《隐私协议》
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</u-checkbox>
|
||||
</view>
|
||||
<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"
|
||||
>
|
||||
登录
|
||||
</u-button>
|
||||
</view>
|
||||
<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
|
||||
>
|
||||
</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.shop_logo"
|
||||
:title="websiteConfig.shop_name"
|
||||
@update="handleUpdateUser"
|
||||
/>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { login, mnpLogin, updateUser, OALogin } from '@/api/account'
|
||||
import { smsSend } from '@/api/app'
|
||||
import { SMSEnum } from '@/enums/appEnums'
|
||||
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, { UrlScene } from '@/utils/wechat'
|
||||
// #endif
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import { computed, reactive, ref, shallowRef, watch } from 'vue'
|
||||
|
||||
enum LoginWayEnum {
|
||||
ACCOUNT = 1,
|
||||
MOBILE = 2
|
||||
}
|
||||
|
||||
const isWeixin = ref(true)
|
||||
// #ifdef H5
|
||||
isWeixin.value = isWeixinClient()
|
||||
// #endif
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
const appStore = useAppStore()
|
||||
const showModel = ref(false)
|
||||
const uCodeRef = shallowRef()
|
||||
const codeTips = ref('')
|
||||
const showLoginPopup = ref(false)
|
||||
const isCheckAgreement = ref(false)
|
||||
|
||||
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.account) return
|
||||
if (uCodeRef.value?.canGetCode) {
|
||||
await smsSend({
|
||||
scene: SMSEnum.LOGIN,
|
||||
mobile: formData.account
|
||||
})
|
||||
uni.$u.toast('发送成功')
|
||||
uCodeRef.value?.start()
|
||||
}
|
||||
}
|
||||
|
||||
const changeLoginWay = (way: LoginWayEnum) => {
|
||||
formData.scene = way
|
||||
}
|
||||
|
||||
const includeLoginWay = (way: LoginWayEnum) => {
|
||||
return appStore.getLoginConfig.login_way?.includes(String(way))
|
||||
}
|
||||
|
||||
const inWxAuth = computed(() => {
|
||||
return appStore.getLoginConfig.wechat_auth
|
||||
})
|
||||
|
||||
const isOpenAgreement = computed(() => appStore.getLoginConfig.login_agreement == 1)
|
||||
|
||||
const isOpenOtherAuth = computed(() => appStore.getLoginConfig.third_auth == 1)
|
||||
const isForceBindMobile = computed(() => appStore.getLoginConfig.coerce_mobile == 1)
|
||||
|
||||
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 {
|
||||
const data = await login(formData)
|
||||
loginHandle(data)
|
||||
} catch (error: any) {
|
||||
uni.hideLoading()
|
||||
uni.$u.toast(error)
|
||||
}
|
||||
}
|
||||
|
||||
const loginHandle = async (data: any) => {
|
||||
const { token, mobile } = data
|
||||
if (!mobile && isForceBindMobile.value) {
|
||||
userStore.temToken = token
|
||||
router.navigateTo('/pages/bind_mobile/bind_mobile')
|
||||
uni.hideLoading()
|
||||
return
|
||||
}
|
||||
userStore.login(data.token)
|
||||
await userStore.getUser()
|
||||
uni.$u.toast('登录成功')
|
||||
uni.hideLoading()
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
const prevPage = pages[pages.length - 2]
|
||||
await router.navigateBack()
|
||||
// @ts-ignore
|
||||
const { onLoad, options } = prevPage
|
||||
// 刷新上一个页面
|
||||
onLoad && onLoad(options)
|
||||
} else if (cache.get(BACK_URL)) {
|
||||
try {
|
||||
router.redirectTo(cache.get(BACK_URL))
|
||||
} catch (error) {
|
||||
router.switchTab(cache.get(BACK_URL))
|
||||
}
|
||||
} else {
|
||||
router.reLaunch('/pages/index/index')
|
||||
}
|
||||
cache.remove(BACK_URL)
|
||||
}
|
||||
|
||||
const { lockFn: handleLogin } = useLockFn(loginFun)
|
||||
|
||||
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
|
||||
})
|
||||
loginData.value = data
|
||||
if (data.is_new_user) {
|
||||
uni.hideLoading()
|
||||
userStore.temToken = data.token
|
||||
showLoginPopup.value = true
|
||||
return
|
||||
}
|
||||
loginHandle(data)
|
||||
} 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
|
||||
loginHandle(loginData.value)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => appStore.getLoginConfig,
|
||||
(value) => {
|
||||
if (value.login_way) {
|
||||
formData.scene = value.login_way[0]
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
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
|
||||
}
|
||||
})
|
||||
|
||||
const removeWxQuery = () => {
|
||||
const options = route.query
|
||||
if (options.code && options.state) {
|
||||
delete options.code
|
||||
delete options.state
|
||||
router.redirectTo({ path: route.path, query: options })
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<z-paging
|
||||
auto-show-back-to-top
|
||||
:auto="i == index"
|
||||
ref="paging"
|
||||
v-model="dataList"
|
||||
:data-key="i"
|
||||
@query="queryList"
|
||||
:fixed="false"
|
||||
height="100%"
|
||||
>
|
||||
<block v-for="(newsItem, newsIndex) in dataList" :key="newsIndex">
|
||||
<news-card :item="newsItem" :newsId="newsItem.id"></news-card>
|
||||
</block>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, nextTick, shallowRef } from 'vue'
|
||||
import { getArticleList } from '@/api/news'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
cid: number
|
||||
i: number
|
||||
index: number
|
||||
}>(),
|
||||
{
|
||||
cid: 0
|
||||
}
|
||||
)
|
||||
|
||||
const paging = shallowRef<any>(null)
|
||||
const dataList = ref([])
|
||||
const isFirst = ref<boolean>(true)
|
||||
|
||||
watch(
|
||||
() => props.index,
|
||||
async () => {
|
||||
await nextTick()
|
||||
if (props.i == props.index && isFirst.value) {
|
||||
isFirst.value = false
|
||||
paging.value?.reload()
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const queryList = async (page_no, page_size) => {
|
||||
try {
|
||||
const { lists } = await getArticleList({
|
||||
cid: props.cid,
|
||||
page_no,
|
||||
page_size
|
||||
})
|
||||
paging.value.complete(lists)
|
||||
} catch (e) {
|
||||
console.log('报错=>', e)
|
||||
//TODO handle the exception
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,85 @@
|
||||
<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">
|
||||
<u-search placeholder="请输入关键词搜索" disabled :show-action="false"></u-search>
|
||||
</navigator>
|
||||
|
||||
<!-- 内容 -->
|
||||
<tabs
|
||||
:current="current"
|
||||
@change="handleChange"
|
||||
height="80"
|
||||
bar-width="60"
|
||||
:barStyle="{ bottom: '0' }"
|
||||
>
|
||||
<tab v-for="(item, i) in tabList" :key="i" :name="item.name">
|
||||
<view class="news-list pt-[20rpx]">
|
||||
<news-list :cid="item.id" :i="i" :index="current"></news-list>
|
||||
</view>
|
||||
</tab>
|
||||
</tabs>
|
||||
<tabbar />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
|
||||
import NewsList from './component/news-list.vue'
|
||||
import { getArticleCate } from '@/api/news'
|
||||
|
||||
const tabList = ref<any>([])
|
||||
const current = ref<number>(0)
|
||||
|
||||
const handleChange = (index: number) => {
|
||||
console.log(index)
|
||||
current.value = Number(index)
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const data = await getArticleCate()
|
||||
tabList.value = [{ name: '全部', id: '' }].concat(data)
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
getData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.news {
|
||||
&-search {
|
||||
margin-bottom: 2rpx;
|
||||
}
|
||||
|
||||
&-list {
|
||||
height: calc(100vh - 272rpx - env(safe-area-inset-bottom));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,108 @@
|
||||
<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.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.click }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 咨询内容 -->
|
||||
<view class="news-detail-section bg-white p-[24rpx]">
|
||||
<!-- 摘要 -->
|
||||
<view class="summary p-[20rpx] text-base" v-if="newsData.abstract">
|
||||
<text class="font-medium">摘要: </text> {{ newsData.abstract }}
|
||||
</view>
|
||||
<!-- 内容 -->
|
||||
<view class="mt-[20rpx]">
|
||||
<u-parse :html="newsData.content"></u-parse>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="panel-btn flex items-center px-[34rpx]" @click="handleAddCollect(newsData.id)">
|
||||
<u-icon
|
||||
:name="newsData.collect ? 'star-fill' : 'star'"
|
||||
size="40"
|
||||
:color="newsData.collect ? '#F7BA47' : '#333'"
|
||||
></u-icon>
|
||||
<text class="ml-[10rpx]">收藏</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getArticleDetail, addCollect, cancelCollect } from '@/api/news'
|
||||
|
||||
const newsData = ref<any>({})
|
||||
let newsId = ''
|
||||
|
||||
const getData = async (id) => {
|
||||
newsData.value = await getArticleDetail({ id })
|
||||
}
|
||||
|
||||
const handleAddCollect = async (id: number) => {
|
||||
try {
|
||||
if (newsData.value.collect) {
|
||||
await cancelCollect({ id })
|
||||
uni.$u.toast('已取消收藏')
|
||||
} else {
|
||||
await addCollect({ id })
|
||||
uni.$u.toast('收藏成功')
|
||||
}
|
||||
getData(newsId)
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options: any) => {
|
||||
newsId = options.id
|
||||
getData(newsId)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.news-detail {
|
||||
height: 100%;
|
||||
|
||||
&-header {
|
||||
border-bottom: 2rpx solid #f8f8f8;
|
||||
}
|
||||
|
||||
&-section {
|
||||
.summary {
|
||||
border-radius: 12rpx;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-btn {
|
||||
position: fixed;
|
||||
right: 30rpx;
|
||||
height: 80rpx;
|
||||
bottom: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,168 @@
|
||||
<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>
|
||||
<u-empty text="订单不存在" mode="order"></u-empty>
|
||||
</template>
|
||||
<template #default>
|
||||
<view class="payment-result p-[20rpx]">
|
||||
<view class="result bg-white p-[20rpx] rounded-md">
|
||||
<view class="flex flex-col items-center my-[40rpx]">
|
||||
<!-- 支付状态图片 -->
|
||||
<u-image
|
||||
class="status-image"
|
||||
:src="paymentStatus['image']"
|
||||
width="100"
|
||||
height="100"
|
||||
shape="circle"
|
||||
/>
|
||||
<!-- 支付状态文字 -->
|
||||
<text class="text-2xl font-medium mt-[20rpx]">{{
|
||||
paymentStatus['text']
|
||||
}}
|
||||
</text>
|
||||
<view class="text-3xl font-medium mt-[20rpx]">
|
||||
¥ {{ orderInfo.order.order_amount }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付信息 -->
|
||||
<view class="result-info">
|
||||
<view class="result-info__item">
|
||||
<text>订单编号</text>
|
||||
<text>{{ orderInfo.order.order_sn }}</text>
|
||||
</view>
|
||||
<view class="result-info__item">
|
||||
<text>付款时间</text>
|
||||
<text>{{ orderInfo.order.pay_time }}</text>
|
||||
</view>
|
||||
<view class="result-info__item">
|
||||
<text>支付方式</text>
|
||||
<template v-if="orderInfo.pay_status">
|
||||
<text>{{ orderInfo.order.pay_way || '-' }}</text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<text>未支付</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-[40rpx]">
|
||||
<view class="mb-[20rpx]">
|
||||
<u-button
|
||||
v-if="pageOptions.from == 'recharge'"
|
||||
type="primary"
|
||||
shape="circle"
|
||||
hover-class="none"
|
||||
@click="goOrder"
|
||||
>
|
||||
继续充值
|
||||
</u-button>
|
||||
</view>
|
||||
<view class="mb-[20rpx]">
|
||||
<u-button
|
||||
type="primary"
|
||||
plain
|
||||
shape="circle"
|
||||
hover-class="none"
|
||||
@click="goHome"
|
||||
>
|
||||
返回首页
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</page-status>
|
||||
</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 {useRouter} from "uniapp-router-next";
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const mapStatus = {
|
||||
succeed: {
|
||||
text: '支付成功',
|
||||
image: '/static/images/payment/icon_succeed.png'
|
||||
},
|
||||
waiting: {
|
||||
text: '等待支付',
|
||||
image: '/static/images/payment/icon_waiting.png'
|
||||
}
|
||||
}
|
||||
const status = ref(PageStatusEnum['LOADING'])
|
||||
const pageOptions = ref({
|
||||
id: '',
|
||||
from: ''
|
||||
})
|
||||
const orderInfo = reactive<any>({
|
||||
order: {}
|
||||
})
|
||||
const paymentStatus = computed(() => {
|
||||
const status = !!orderInfo.pay_status
|
||||
return mapStatus[status ? 'succeed' : 'waiting']
|
||||
})
|
||||
|
||||
const initPageData = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
getPayResult({
|
||||
order_id: pageOptions.value.id,
|
||||
from: pageOptions.value.from
|
||||
})
|
||||
.then((data) => {
|
||||
Object.assign(orderInfo, data)
|
||||
resolve(data)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const goHome = () => {
|
||||
router.reLaunch('/pages/index/index')
|
||||
}
|
||||
|
||||
const goOrder = () => {
|
||||
switch (pageOptions.value.from) {
|
||||
case 'recharge':
|
||||
router.navigateBack()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
onLoad(async (options: any) => {
|
||||
try {
|
||||
if (!options.id) throw new Error('订单不存在')
|
||||
pageOptions.value = options
|
||||
await initPageData()
|
||||
status.value = PageStatusEnum['NORMAL']
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
status.value = PageStatusEnum['ERROR']
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.result-info {
|
||||
.result-info__item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,150 @@
|
||||
<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">
|
||||
<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>
|
||||
<router-navigate
|
||||
class="text-primary"
|
||||
hover-class="none"
|
||||
to="/pages/agreement/agreement?type=service"
|
||||
>
|
||||
《服务协议》
|
||||
</router-navigate>
|
||||
</view>
|
||||
|
||||
和
|
||||
<view @click.stop>
|
||||
<router-navigate
|
||||
class="text-primary"
|
||||
hover-class="none"
|
||||
to="/pages/agreement/agreement?type=privacy"
|
||||
>
|
||||
《隐私协议》
|
||||
</router-navigate>
|
||||
</view>
|
||||
</view>
|
||||
</u-checkbox>
|
||||
</view>
|
||||
<view class="mt-[60rpx]">
|
||||
<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'
|
||||
|
||||
const isCheckAgreement = ref(false)
|
||||
const appStore = useAppStore()
|
||||
const isOpenAgreement = computed(() => appStore.getLoginConfig.login_agreement == 1)
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
password: '',
|
||||
password_confirm: ''
|
||||
})
|
||||
const showModel = ref(false)
|
||||
const accountRegister = async () => {
|
||||
if (!formData.account) return uni.$u.toast('请输入账号')
|
||||
if (!formData.password) 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.navigateBack()
|
||||
setTimeout(function () {
|
||||
uni.navigateBack()
|
||||
}, 1000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<view class="suggest bg-white">
|
||||
<!-- 热门搜索 -->
|
||||
<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.name)"
|
||||
>
|
||||
{{ hotItem.name }}
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="mx-[24rpx] my-[40rpx] border-b border-solid border-0 border-light"
|
||||
v-if="hot_search.status == 1 && searchData.length && his_search.length"
|
||||
></view>
|
||||
|
||||
<!-- 历史搜索 -->
|
||||
<view class="history" v-if="his_search.length">
|
||||
<view class="flex justify-between px-[24rpx] pb-[6rpx] pt-[26rpx]">
|
||||
<view class="text-lg font-medium">历史搜索</view>
|
||||
<view class="text-xs text-muted" @click="() => emit('clear')">清空</view>
|
||||
</view>
|
||||
|
||||
<view class="w-full px-[24rpx]">
|
||||
<block v-for="(hisItem, index) in his_search" :key="index">
|
||||
<view class="keyword truncate" @click="handleHistoreSearch(hisItem)">{{
|
||||
hisItem
|
||||
}}</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'search', value: string): void
|
||||
(event: 'clear', value: void): void
|
||||
}>()
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
hot_search?: {
|
||||
data: any[]
|
||||
status: number
|
||||
}
|
||||
his_search?: string[]
|
||||
}>(),
|
||||
{
|
||||
hot_search: () => ({
|
||||
data: [],
|
||||
status: 0
|
||||
}),
|
||||
his_search: () => []
|
||||
}
|
||||
)
|
||||
|
||||
const searchData = computed(() => {
|
||||
return props.hot_search.data.filter((item) => item.name)
|
||||
})
|
||||
|
||||
const handleHistoreSearch = (text: string) => {
|
||||
emit('search', text)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.suggest {
|
||||
height: 100%;
|
||||
.keyword {
|
||||
display: inline-block;
|
||||
margin: 24rpx 16rpx 0 0;
|
||||
padding: 8rpx 24rpx;
|
||||
border-radius: 26rpx;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +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="search">
|
||||
<!-- 搜索框 -->
|
||||
<view class="px-[24rpx] py-[14rpx] bg-white">
|
||||
<u-search
|
||||
v-model="keyword"
|
||||
placeholder="请输入关键词搜索"
|
||||
height="72"
|
||||
@search="handleSearch"
|
||||
@custom="handleSearch"
|
||||
@clear="search.searching = false"
|
||||
></u-search>
|
||||
</view>
|
||||
|
||||
<!-- 搜索 -->
|
||||
<view class="search-content">
|
||||
<!-- -->
|
||||
<suggest
|
||||
v-show="!search.searching"
|
||||
@search="handleSearch"
|
||||
@clear="handleClear"
|
||||
:hot_search="search.hot_search"
|
||||
:his_search="search.his_search"
|
||||
></suggest>
|
||||
|
||||
<!-- -->
|
||||
<view class="search-content-s pt-[20rpx]" v-show="search.searching">
|
||||
<z-paging
|
||||
ref="paging"
|
||||
v-model="search.result"
|
||||
@query="queryList"
|
||||
:fixed="false"
|
||||
height="100%"
|
||||
>
|
||||
<block v-for="item in search.result" :key="item.id">
|
||||
<news-card :item="item" :newsId="item.id"></news-card>
|
||||
</block>
|
||||
</z-paging>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, shallowRef } from 'vue'
|
||||
import Suggest from './component/suggest.vue'
|
||||
import { HISTORY } from '@/enums/constantEnums'
|
||||
import { getHotSearch } from '@/api/shop'
|
||||
import cache from '@/utils/cache'
|
||||
import { getArticleList } from '@/api/news'
|
||||
|
||||
interface Search {
|
||||
hot_search: {
|
||||
data: any[]
|
||||
status: number
|
||||
}
|
||||
his_search: string[]
|
||||
result: any
|
||||
searching: boolean
|
||||
}
|
||||
|
||||
const search = reactive<Search>({
|
||||
hot_search: {
|
||||
data: [],
|
||||
status: 1
|
||||
},
|
||||
his_search: [],
|
||||
result: [],
|
||||
searching: false
|
||||
})
|
||||
const keyword = ref<string>('')
|
||||
const paging = shallowRef()
|
||||
|
||||
const handleSearch = (value: string) => {
|
||||
keyword.value = value
|
||||
if (keyword.value) {
|
||||
if (!search.his_search.includes(keyword.value)) {
|
||||
search.his_search.unshift(keyword.value)
|
||||
cache.set(HISTORY, search.his_search)
|
||||
}
|
||||
}
|
||||
paging.value.reload()
|
||||
search.searching = true
|
||||
}
|
||||
|
||||
const getHotSearchFunc = async () => {
|
||||
try {
|
||||
search.hot_search = await getHotSearch()
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
console.log('获取热门搜索失败=>', e)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClear = async (): Promise<void> => {
|
||||
const resModel: any = await uni.showModal({
|
||||
title: '温馨提示',
|
||||
content: '是否清空历史记录?'
|
||||
})
|
||||
if (resModel.confirm) {
|
||||
cache.set(HISTORY, '')
|
||||
search.his_search = []
|
||||
}
|
||||
}
|
||||
|
||||
const queryList = async (page_no: number, page_size: number) => {
|
||||
try {
|
||||
const { lists } = await getArticleList({
|
||||
keyword: keyword.value,
|
||||
page_no,
|
||||
page_size
|
||||
})
|
||||
paging.value.complete(lists)
|
||||
} catch (e) {
|
||||
console.log('报错=>', e)
|
||||
//TODO handle the exception
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
|
||||
getHotSearchFunc()
|
||||
search.his_search = cache.get(HISTORY) || []
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search {
|
||||
&-content {
|
||||
height: calc(100vh - 46px - env(safe-area-inset-bottom));
|
||||
&-s {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,61 @@
|
||||
<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"
|
||||
:is-login="isLogin"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="item.name == 'my-service'">
|
||||
<w-my-service :content="item.content" :styles="item.styles" />
|
||||
</template>
|
||||
<template v-if="item.name == 'user-banner'">
|
||||
<w-user-banner :content="item.content" :styles="item.styles" />
|
||||
</template>
|
||||
</view>
|
||||
<tabbar />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getDecorate } from '@/api/shop'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
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.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)
|
||||
onShow(() => {
|
||||
userStore.getUser()
|
||||
})
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,365 @@
|
||||
<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 pt-[30rpx]">
|
||||
<view class="flex justify-center pb-5">
|
||||
<avatar-upload
|
||||
:modelValue="userInfo?.avatar"
|
||||
file-key="url"
|
||||
:round="true"
|
||||
@update:modelValue="handleAvatarChange"
|
||||
>
|
||||
</avatar-upload>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户ID -->
|
||||
<view
|
||||
class="item text-nr flex justify-between"
|
||||
@click=";(showUserName = true), (newUsername = userInfo?.username)"
|
||||
>
|
||||
<view class="label">账号</view>
|
||||
<view class="content">{{ userInfo?.account }}</view>
|
||||
<u-icon name="arrow-right" size="22" color="#666"></u-icon>
|
||||
</view>
|
||||
|
||||
<!-- 昵称 -->
|
||||
<view
|
||||
class="item text-nr flex justify-between"
|
||||
@click=";(showNickName = true), (newNickname = userInfo?.nickname)"
|
||||
>
|
||||
<view class="label">昵称</view>
|
||||
<view class="content">{{ userInfo?.nickname }}</view>
|
||||
<u-icon name="arrow-right" size="22" color="#666"></u-icon>
|
||||
</view>
|
||||
|
||||
<!-- 性别 -->
|
||||
<view class="item text-nr flex justify-between" @click="changeSex">
|
||||
<view class="label">性别</view>
|
||||
<view class="content">{{ userInfo?.sex }}</view>
|
||||
<u-icon name="arrow-right" size="22" color="#666"></u-icon>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 -->
|
||||
<view class="item text-nr flex justify-between">
|
||||
<view class="label">手机号</view>
|
||||
<view class="content">{{
|
||||
userInfo?.mobile == '' ? '未绑定手机号' : userInfo?.mobile
|
||||
}}</view>
|
||||
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<u-button
|
||||
open-type="getPhoneNumber"
|
||||
@getphonenumber="getPhoneNumber"
|
||||
type="primary"
|
||||
shape="circle"
|
||||
size="mini"
|
||||
:plain="true"
|
||||
>
|
||||
{{ userInfo?.mobile == '' ? '绑定手机号' : '更换手机号' }}
|
||||
</u-button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<u-button
|
||||
@click="showMobilePop = true"
|
||||
size="mini"
|
||||
type="primary"
|
||||
shape="circle"
|
||||
:plain="true"
|
||||
>
|
||||
{{ userInfo?.mobile == '' ? '绑定手机号' : '更换手机号' }}
|
||||
</u-button>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
|
||||
<!-- 注册时间 -->
|
||||
<view class="item text-nr flex justify-between">
|
||||
<view class="label">注册时间</view>
|
||||
<view class="content">{{ userInfo?.create_time }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 昵称修改组件 -->
|
||||
<u-popup
|
||||
v-model="showNickName"
|
||||
:closeable="true"
|
||||
mode="center"
|
||||
:maskCloseAble="false"
|
||||
border-radius="20"
|
||||
>
|
||||
<view class="px-[50rpx] py-[40rpx] bg-white" style="width: 85vw">
|
||||
<form @submit="changeNameConfirm">
|
||||
<view class="mb-[70rpx] text-xl text-center">修改昵称</view>
|
||||
<u-form-item borderBottom>
|
||||
<input
|
||||
class="nr h-[60rpx] w-full"
|
||||
:value="userInfo.nickname"
|
||||
name="nickname"
|
||||
type="nickname"
|
||||
placeholder="请输入昵称"
|
||||
/>
|
||||
</u-form-item>
|
||||
<view class="mt-[80rpx]">
|
||||
<button
|
||||
class="bg-primary text-white w-full h-[80rpx] !text-lg !leading-[80rpx] rounded-full"
|
||||
form-type="submit"
|
||||
size="mini"
|
||||
hover-class="none"
|
||||
>
|
||||
确定
|
||||
</button>
|
||||
</view>
|
||||
</form>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<!-- 账号修改组件 -->
|
||||
<u-popup v-model="showUserName" :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>
|
||||
<u-form-item borderBottom>
|
||||
<u-input
|
||||
class="flex-1"
|
||||
v-model="newUsername"
|
||||
placeholder="请输入账号"
|
||||
:border="false"
|
||||
/>
|
||||
</u-form-item>
|
||||
<view class="mt-[80rpx]">
|
||||
<u-button @click="changeUserNameConfirm" type="primary" shape="circle">
|
||||
确定
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<!-- 性别修改组件 -->
|
||||
<u-picker
|
||||
mode="selector"
|
||||
v-model="showPicker"
|
||||
confirm-color="#4173FF"
|
||||
:default-selector="[0]"
|
||||
:range="sexList"
|
||||
@confirm="changeSexConfirm"
|
||||
/>
|
||||
|
||||
<!-- 账号修改组件 -->
|
||||
<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">{{ userInfo?.mobile == '' ? '绑定手机号' : '更换手机号' }}</view>
|
||||
<u-form-item borderBottom>
|
||||
<u-input
|
||||
class="flex-1"
|
||||
v-model="newMobile"
|
||||
placeholder="请输入新的手机号码"
|
||||
:border="false"
|
||||
/>
|
||||
</u-form-item>
|
||||
<u-form-item borderBottom>
|
||||
<u-input
|
||||
class="flex-1"
|
||||
v-model="mobileCode"
|
||||
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秒"
|
||||
/>
|
||||
{{ codeTips }}
|
||||
</view>
|
||||
</u-form-item>
|
||||
<view class="mt-[80rpx]">
|
||||
<u-button @click="changeCodeMobile" type="primary" shape="circle"> 确定 </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, shallowRef } from 'vue'
|
||||
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'
|
||||
|
||||
// 用户信息
|
||||
const userInfo = ref<any>({})
|
||||
// 用户信息的枚举
|
||||
const fieldType = ref(FieldType.NONE)
|
||||
//选择性别数据
|
||||
const sexList = ref<Array<string> | null>(['男', '女'])
|
||||
|
||||
//显示昵称弹窗
|
||||
const showNickName = ref<boolean | null>(false)
|
||||
//显示账户弹窗
|
||||
const showUserName = ref<boolean | null>(false)
|
||||
//显示性别选择弹窗
|
||||
const showPicker = ref<boolean | null>(false)
|
||||
// 显示手机号验证码调整弹窗 非小程序才需要
|
||||
const showMobilePop = ref<boolean | null>(false)
|
||||
|
||||
//新昵称
|
||||
const newNickname = ref<string>('')
|
||||
//新账号
|
||||
const newUsername = ref<string>('')
|
||||
//新的手机号码
|
||||
const newMobile = ref<string>('')
|
||||
|
||||
//修改手机验证码
|
||||
const mobileCode = ref<string>('')
|
||||
const codeTips = ref('')
|
||||
const uCodeRef = shallowRef()
|
||||
|
||||
// 获取用户信息
|
||||
const getUser = async (): Promise<void> => {
|
||||
userInfo.value = await getUserInfo()
|
||||
}
|
||||
|
||||
// 获取验证码显示字段
|
||||
const codeChange = (text: string) => {
|
||||
codeTips.value = text
|
||||
}
|
||||
|
||||
// 发送验证码
|
||||
const sendSms = async () => {
|
||||
if (!newMobile.value) return uni.$u.toast('请输入新的手机号码')
|
||||
if (uCodeRef.value?.canGetCode) {
|
||||
await smsSend({
|
||||
scene: userInfo.value.mobile ? SMSEnum.CHANGE_MOBILE : SMSEnum.BIND_MOBILE,
|
||||
mobile: newMobile.value
|
||||
})
|
||||
uni.$u.toast('发送成功')
|
||||
uCodeRef.value?.start()
|
||||
}
|
||||
}
|
||||
|
||||
const handleAvatarChange = (value) => {
|
||||
fieldType.value = FieldType.AVATAR
|
||||
setUserInfoFun(value)
|
||||
}
|
||||
|
||||
// 验证码修改手机号-非微信小程序
|
||||
const changeCodeMobile = async () => {
|
||||
await userBindMobile({
|
||||
type: userInfo.value.mobile ? 'change' : 'bind',
|
||||
mobile: newMobile.value,
|
||||
code: mobileCode.value
|
||||
})
|
||||
uni.$u.toast('操作成功')
|
||||
showMobilePop.value = false
|
||||
getUser()
|
||||
}
|
||||
|
||||
// 修改用户信息
|
||||
const setUserInfoFun = async (value: string): Promise<void> => {
|
||||
await userEdit({
|
||||
field: fieldType.value,
|
||||
value: value
|
||||
})
|
||||
uni.$u.toast('操作成功')
|
||||
getUser()
|
||||
}
|
||||
|
||||
// 显示修改用户性别弹窗
|
||||
const changeSex = () => {
|
||||
showPicker.value = true
|
||||
fieldType.value = FieldType.SEX
|
||||
}
|
||||
|
||||
// 修改用户性别
|
||||
const changeSexConfirm = (value) => {
|
||||
setUserInfoFun(value[0] + 1)
|
||||
showPicker.value = false
|
||||
}
|
||||
|
||||
// 修改用户账号
|
||||
const changeUserNameConfirm = () => {
|
||||
if (newUsername.value == '') return uni.$u.toast('账号不能为空')
|
||||
if (newUsername.value.length > 10) return uni.$u.toast('账号长度不得超过十位数')
|
||||
|
||||
fieldType.value = FieldType.USERNAME
|
||||
setUserInfoFun(newUsername.value)
|
||||
showUserName.value = false
|
||||
}
|
||||
|
||||
// 修改用户昵称
|
||||
const changeNameConfirm = async (e: any) => {
|
||||
newNickname.value = e.detail.value.nickname
|
||||
if (newNickname.value == '') return uni.$u.toast('昵称不能为空')
|
||||
if (newNickname.value.length > 10) return uni.$u.toast('昵称长度不得超过十位数')
|
||||
fieldType.value = FieldType.NICKNAME
|
||||
await setUserInfoFun(newNickname.value)
|
||||
|
||||
showNickName.value = false
|
||||
}
|
||||
|
||||
// 微信小程序 绑定||修改用户手机号
|
||||
const getPhoneNumber = async (e): Promise<void> => {
|
||||
const { encryptedData, iv, code } = e.detail
|
||||
const data = {
|
||||
code,
|
||||
encrypted_data: encryptedData,
|
||||
iv
|
||||
}
|
||||
if (encryptedData) {
|
||||
await userMnpMobile({
|
||||
...data
|
||||
})
|
||||
uni.$u.toast('操作成功')
|
||||
getUser()
|
||||
}
|
||||
}
|
||||
|
||||
const goPage = (url: string) => {
|
||||
uni.navigateTo({
|
||||
url: url
|
||||
})
|
||||
}
|
||||
|
||||
onShow(async () => {
|
||||
getUser()
|
||||
})
|
||||
|
||||
onUnload(() => {})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.header {
|
||||
width: 100%;
|
||||
|
||||
image {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
margin-top: 2rpx;
|
||||
padding: 30rpx;
|
||||
background-color: #ffffff;
|
||||
|
||||
.label {
|
||||
width: 150rpx;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,248 @@
|
||||
<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]">
|
||||
<u-avatar :src="userInfo.avatar" shape="square" :size="100"></u-avatar>
|
||||
<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.account }}</view>
|
||||
</view>
|
||||
<u-icon name="arrow-right" color="#666"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</navigator>
|
||||
<view
|
||||
class="item bg-white mt-[20rpx] btn-border flex flex-1 justify-between"
|
||||
@click="handlePwd"
|
||||
>
|
||||
<view class="">登录密码</view>
|
||||
<u-icon name="arrow-right" color="#666"></u-icon>
|
||||
</view>
|
||||
<!-- #ifdef H5 || MP-WEIXIN -->
|
||||
<view
|
||||
v-if="isWeixin"
|
||||
class="item bg-white flex flex-1 justify-between"
|
||||
@click="bindWechatLock"
|
||||
>
|
||||
<view class="">绑定微信</view>
|
||||
<view class="flex justify-between">
|
||||
<view class="text-muted mr-[20rpx]">
|
||||
{{ userInfo.is_auth ? '已绑定' : '未绑定' }}
|
||||
</view>
|
||||
<u-icon v-if="userInfo.is_auth == 0" name="arrow-right" color="#666"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<navigator :url="`/pages/agreement/agreement?type=${AgreementEnum.PRIVACY}`">
|
||||
<view class="item bg-white mt-[20rpx] btn-border flex flex-1 justify-between">
|
||||
<view class="">隐私政策</view>
|
||||
<u-icon name="arrow-right" color="#666"></u-icon>
|
||||
</view>
|
||||
</navigator>
|
||||
<navigator :url="`/pages/agreement/agreement?type=${AgreementEnum.SERVICE}`">
|
||||
<view class="item bg-white btn-border flex flex-1 justify-between">
|
||||
<view class="">服务协议</view>
|
||||
<u-icon name="arrow-right" color="#666"></u-icon>
|
||||
</view>
|
||||
</navigator>
|
||||
<navigator url="/pages/as_us/as_us">
|
||||
<view class="item bg-white flex flex-1 justify-between">
|
||||
<view class="">关于我们</view>
|
||||
<view class="flex justify-between">
|
||||
<view class="text-muted mr-[20rpx]">
|
||||
{{ appStore.config.version }}
|
||||
</view>
|
||||
<u-icon name="arrow-right" color="#666"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</navigator>
|
||||
|
||||
<view class="mt-[60rpx] mx-[26rpx]">
|
||||
<u-button type="primary" shape="circle" @click="showLogout = true"> 退出登录</u-button>
|
||||
</view>
|
||||
|
||||
<u-action-sheet
|
||||
:list="list"
|
||||
v-model="show"
|
||||
@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 {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'
|
||||
// #endif
|
||||
|
||||
const router = useRouter()
|
||||
const appStore = useAppStore()
|
||||
const userStore = useUserStore()
|
||||
const userInfo = computed(() => userStore.userInfo)
|
||||
|
||||
const list = ref([
|
||||
{
|
||||
text: '修改密码'
|
||||
},
|
||||
{
|
||||
text: '忘记密码'
|
||||
}
|
||||
])
|
||||
|
||||
const isWeixin = ref(true)
|
||||
// #ifdef H5
|
||||
isWeixin.value = isWeixinClient()
|
||||
// #endif
|
||||
|
||||
const show = ref(false)
|
||||
const showLogout = ref(false)
|
||||
|
||||
// 修改/忘记密码
|
||||
const handleClick = (index: number) => {
|
||||
switch (index) {
|
||||
case 0:
|
||||
router.navigateTo('/pages/change_password/change_password')
|
||||
break
|
||||
case 1:
|
||||
router.navigateTo('/pages/forget_pwd/forget_pwd')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const handlePwd = () => {
|
||||
if (!userInfo.value.has_password)
|
||||
return router.navigateTo('/pages/change_password/change_password?type=set')
|
||||
show.value = true
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
const logoutHandle = () => {
|
||||
userStore.logout()
|
||||
router.redirectTo('/pages/login/login')
|
||||
}
|
||||
|
||||
const bindWechat = async () => {
|
||||
if (userInfo.value.is_auth) return
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '请稍后...'
|
||||
})
|
||||
// #ifdef MP-WEIXIN
|
||||
const {code}: any = await uni.login({
|
||||
provider: 'weixin'
|
||||
})
|
||||
await mnpAuthBind({
|
||||
code: code
|
||||
})
|
||||
//#endif
|
||||
// #ifdef H5
|
||||
if (isWeixin.value) {
|
||||
wechatOa.getUrl()
|
||||
}
|
||||
// #endif
|
||||
await userStore.getUser()
|
||||
uni.hideLoading()
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
uni.$u.toast(e)
|
||||
}
|
||||
}
|
||||
const {lockFn: bindWechatLock} = useLockFn(bindWechat)
|
||||
|
||||
onShow(() => {
|
||||
userStore.getUser()
|
||||
})
|
||||
|
||||
onLoad(async (options) => {
|
||||
// #ifdef H5
|
||||
const {code} = options
|
||||
if (!isWeixin.value) return
|
||||
if (code) {
|
||||
uni.showLoading({
|
||||
title: '请稍后...'
|
||||
})
|
||||
try {
|
||||
await oaAuthBind({code})
|
||||
await userStore.getUser()
|
||||
} catch (error) {
|
||||
}
|
||||
//用于清空code
|
||||
router.redirectTo('/pages/user_set/user_set')
|
||||
}
|
||||
|
||||
// #endif
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-set {
|
||||
.item {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.btn-border {
|
||||
border-bottom: 2rpx solid #f8f8f8;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<web-view :src="url" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const url = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
url.value = decodeURIComponent(options.url!)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
Reference in New Issue
Block a user