第一次提交
This commit is contained in:
232
package/solution/apply.vue
Normal file
232
package/solution/apply.vue
Normal file
@@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<view class="partner">
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper" v-if="setting">
|
||||
<u-form :model="form" ref="uForm" label-width="240rpx">
|
||||
<view class="brand-poster">
|
||||
<image :src="setting.background" mode="widthFix" class="banner"></image>
|
||||
<view class="brand-name" v-html="setting.content"></view>
|
||||
</view>
|
||||
<view class="buy-desc">如果有意向,请填写以下信息给平台留言</view>
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper">
|
||||
<u-form :model="form" ref="uForm" label-width="140rpx">
|
||||
<u-form-item label="姓名" prop="real_name">
|
||||
<u-input v-model="form.real_name" :disabled="disabled" placeholder="请输入姓名" />
|
||||
</u-form-item>
|
||||
<u-form-item label="电话" prop="phone">
|
||||
<u-input v-model="form.phone" maxlength="11" :disabled="disabled" placeholder="请输入联系电话" />
|
||||
</u-form-item>
|
||||
<u-form-item label="性别" prop="sex">
|
||||
<u-radio-group v-model="form.sex">
|
||||
<u-radio @change="groupChange" v-for="(item, index) in sex" :key="index"
|
||||
:name="item.name" :disabled="item.disabled">
|
||||
{{item.name}}
|
||||
</u-radio>
|
||||
</u-radio-group>
|
||||
</u-form-item>
|
||||
<u-form-item label="定制预算" prop="money">
|
||||
<u-input type="number" v-model="form.money" :disabled="disabled" maxlength="11" placeholder="请输入定制预算" />
|
||||
</u-form-item>
|
||||
<u-form-item label="微信号" prop="weixin">
|
||||
<u-input v-model="form.weixin" :disabled="disabled" placeholder="请输入微信号" />
|
||||
</u-form-item>
|
||||
<u-form-item label="意向区域" prop="region">
|
||||
<select-region ref="sRegion" :disabled="disabled" v-model="form.region" />
|
||||
</u-form-item>
|
||||
<u-form-item label="整体需求" prop="comments">
|
||||
<u-input v-model="form.comments" :disabled="disabled" placeholder="请输入整体需求" />
|
||||
</u-form-item>
|
||||
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="footer">
|
||||
<view class="btn">
|
||||
<u-button type="primary" shape="circle" @click="handleSubmit()">提交</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<!-- <view class="footer">
|
||||
<view class="btn">
|
||||
<u-button type="primary" shape="circle">更新资料</u-button>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 表单字段元素
|
||||
const form = {
|
||||
name: '',
|
||||
phone: '',
|
||||
sex: '',
|
||||
money: '',
|
||||
region: [],
|
||||
weixin: '',
|
||||
comments: '',
|
||||
}
|
||||
|
||||
const sex = [{
|
||||
name: '男',
|
||||
value: 1,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '女',
|
||||
value: 2,
|
||||
disabled: false
|
||||
}
|
||||
]
|
||||
|
||||
import * as Api from '@/api/solution/index.js'
|
||||
import * as ApplyApi from '@/api/solution/apply.js'
|
||||
import * as SettingApi from '@/api/solution/setting.js'
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form,
|
||||
disabled: false,
|
||||
detail: {},
|
||||
solutionId: 0,
|
||||
sex,
|
||||
setting: {}
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
// 获取当前用户信息
|
||||
init() {
|
||||
const app = this
|
||||
SettingApi.data().then(result => {
|
||||
app.setting = result.data.setting
|
||||
// 设置当前页面标题
|
||||
app.setPageTitle()
|
||||
})
|
||||
},
|
||||
|
||||
// 设置当前页面标题
|
||||
setPageTitle() {
|
||||
uni.setNavigationBarTitle({ title: this.setting.title })
|
||||
},
|
||||
|
||||
groupChange(e) {
|
||||
this.form.sex = e
|
||||
},
|
||||
|
||||
// 表单提交
|
||||
handleSubmit() {
|
||||
const app = this
|
||||
// if (app.disabled) {
|
||||
// return false
|
||||
// }
|
||||
const {
|
||||
form,
|
||||
solutionId
|
||||
} = this
|
||||
form.brand_id = solutionId
|
||||
app.$refs.uForm.validate(valid => {
|
||||
if (valid) {
|
||||
app.disabled = true
|
||||
app.onSubmit()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 提交到后端
|
||||
onSubmit() {
|
||||
const app = this
|
||||
const {
|
||||
form
|
||||
} = this
|
||||
let req;
|
||||
if (form.apply_status == 30) {
|
||||
req = ApplyApi.edit(form.apply_id, form)
|
||||
} else {
|
||||
console.log('add');
|
||||
req = ApplyApi.add(form)
|
||||
}
|
||||
req.then(result => {
|
||||
console.log("result: ", result);
|
||||
app.$toast(result.message)
|
||||
setTimeout(function() {
|
||||
uni.navigateBack()
|
||||
}, 2000)
|
||||
|
||||
})
|
||||
.finally(() => app.disabled = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.partner {
|
||||
.banner {
|
||||
padding-top: 20rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
|
||||
.shop-box {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.shop-name {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.brand-poster{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 100rpx;
|
||||
}
|
||||
|
||||
.shipin {
|
||||
width: 400rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 500rpx;
|
||||
margin: 50rpx auto;
|
||||
padding-bottom: 50rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
padding: 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.buy-desc {
|
||||
text-align: center;
|
||||
color: #ff0000;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.buy-text {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
238
package/solution/article/index.vue
Normal file
238
package/solution/article/index.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption" @up="upCallback">
|
||||
|
||||
<!-- 文章列表 -->
|
||||
<view class="article-list">
|
||||
<view class="article-item" :class="[`show-type__${item.show_type}`]" v-for="(item, index) in articleList.data" :key="index"
|
||||
@click="onTargetDetail(item.solution_id)">
|
||||
<!-- 小图模式 -->
|
||||
<block v-if="item.show_type == 10">
|
||||
<view class="article-item__image article-item__left">
|
||||
<image class="image" mode="widthFix" :src="item.image_url"></image>
|
||||
</view>
|
||||
<view class="flex-box">
|
||||
<view class="article-item__title">
|
||||
<text class="twoline-hide">{{ item.title }}</text>
|
||||
</view>
|
||||
<!-- <view class="article-item__footer m-top10">
|
||||
<text class="article-views f-24 col-8">{{ item.show_views }}次浏览</text>
|
||||
</view> -->
|
||||
</view>
|
||||
</block>
|
||||
<!-- 大图模式 -->
|
||||
<block v-if="item.show_type == 20">
|
||||
<view class="article-item__title">
|
||||
<text class="twoline-hide">{{ item.title }}</text>
|
||||
</view>
|
||||
<view class="article-item__image m-top20">
|
||||
<image class="image" mode="widthFix" :src="item.image_url"></image>
|
||||
</view>
|
||||
<!-- <view class="article-item__footer m-top10">
|
||||
<text class="article-views f-24 col-8">{{ item.show_views }}次浏览</text>
|
||||
</view> -->
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
|
||||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins'
|
||||
import * as Api from '@/api/solution/index.js'
|
||||
import * as UserApi from '@/api/user'
|
||||
import * as CategoryApi from '@/api/solution/category'
|
||||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app'
|
||||
|
||||
const pageSize = 15
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MescrollBody
|
||||
},
|
||||
mixins: [MescrollMixin],
|
||||
data() {
|
||||
return {
|
||||
CategoryId: 0,
|
||||
// 文章列表
|
||||
articleList: getEmptyPaginateObj(),
|
||||
userInfo: {},
|
||||
// 订单类型
|
||||
orderType: false,
|
||||
// 上拉加载配置
|
||||
upOption: {
|
||||
// 首次自动执行
|
||||
auto: true,
|
||||
// 每页数据的数量; 默认10
|
||||
page: { size: pageSize },
|
||||
// 数量要大于3条才显示无更多数据
|
||||
noMoreSize: 3,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
const app = this
|
||||
console.log("options: ",options);
|
||||
app.CategoryId = options.categoryId
|
||||
app.orderType = options.orderType
|
||||
// 获取文章分类数据
|
||||
app.getArticleList()
|
||||
app.getUserInfo()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 上拉加载的回调 (页面初始化时也会执行一次)
|
||||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
|
||||
* @param {Object} page
|
||||
*/
|
||||
upCallback(page) {
|
||||
const app = this
|
||||
// 设置列表数据
|
||||
app.getArticleList(page.num)
|
||||
.then(list => {
|
||||
const curPageLen = list.data.length
|
||||
const totalSize = list.data.total
|
||||
app.mescroll.endBySize(curPageLen, totalSize)
|
||||
})
|
||||
.catch(() => app.mescroll.endErr())
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取文章列表
|
||||
* @param {Number} pageNo 页码
|
||||
*/
|
||||
getArticleList(pageNo = 1) {
|
||||
const app = this
|
||||
return new Promise((resolve, reject) => {
|
||||
Api.list({ categoryId: app.CategoryId, page: pageNo }, { load: false })
|
||||
.then(result => {
|
||||
// 合并新数据
|
||||
const newList = result.data.list
|
||||
app.articleList.data = getMoreListData(newList, app.articleList, pageNo)
|
||||
resolve(newList)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取当前用户信息
|
||||
getUserInfo() {
|
||||
const app = this
|
||||
UserApi.info()
|
||||
.then(result => {
|
||||
app.userInfo = result.data.userInfo
|
||||
})
|
||||
},
|
||||
|
||||
// 获取当前标签项的值
|
||||
getTabValue() {
|
||||
const app = this
|
||||
return app.tabList.length ? app.tabList[app.curTab].value : 0
|
||||
},
|
||||
|
||||
// 刷新列表数据
|
||||
onRefreshList() {
|
||||
this.articleList = getEmptyPaginateObj()
|
||||
setTimeout(() => this.mescroll.resetUpScroll(), 120)
|
||||
},
|
||||
|
||||
// 跳转文章详情页
|
||||
onTargetDetail(articleId) {
|
||||
const { orderType } = this
|
||||
if( orderType ){
|
||||
return this.$navTo('package/solution/detail', { articleId })
|
||||
}
|
||||
return this.$navTo('package/solution/buy/index')
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享当前页面
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '文章首页',
|
||||
path: "/pages/article/index?" + this.$getShareUrlParams()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享到朋友圈
|
||||
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta)
|
||||
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
|
||||
*/
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '文章首页',
|
||||
path: "/pages/article/index?" + this.$getShareUrlParams()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
// 文章列表
|
||||
.article-list {
|
||||
padding-top: 20rpx;
|
||||
line-height: 1;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
|
||||
.article-item {
|
||||
margin-bottom: 20rpx;
|
||||
padding: 30rpx;
|
||||
background: #fff;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.article-item__title {
|
||||
max-height: 74rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 38rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.article-item__image .image {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
// 小图模式
|
||||
.show-type__10 {
|
||||
display: flex;
|
||||
|
||||
.article-item__left {
|
||||
padding-right: 20rpx;
|
||||
}
|
||||
|
||||
.article-item__title {
|
||||
// min-height: 72rpx;
|
||||
}
|
||||
|
||||
.article-item__image .image {
|
||||
width: 240rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 大图模式
|
||||
.show-type__20 .article-item__image .image {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
225
package/solution/buy/index.vue
Normal file
225
package/solution/buy/index.vue
Normal file
@@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<view class="partner">
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper" v-if="setting">
|
||||
<u-form :model="form" ref="uForm" label-width="240rpx">
|
||||
<view class="brand-poster">
|
||||
<image :src="setting.background" mode="widthFix" class="banner"></image>
|
||||
<view class="brand-name" v-html="setting.content"></view>
|
||||
</view>
|
||||
<view class="buy-info">
|
||||
<u-radio-group v-model="agree" placement="column">
|
||||
<u-radio name="购买协议" @change="radioChange">同意<text class="show-agreement">《购买协议》</text></u-radio>
|
||||
</u-radio-group>
|
||||
<text class="price">¥{{ setting.money }}</text>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="footer">
|
||||
<view class="btn">
|
||||
<u-button :disabled="!agree" type="primary" shape="circle" @click="handleSubmit()">立即购买</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</u-form>
|
||||
</view>
|
||||
<u-modal v-model="show" ref="uModal" title="购买协议" @confirm="confirm">
|
||||
<view v-html="setting.agreement" class="agreement-content"></view>
|
||||
</u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 表单字段元素
|
||||
const form = {
|
||||
name: '',
|
||||
phone: '',
|
||||
sex: '',
|
||||
money: '',
|
||||
region: [],
|
||||
weixin: '',
|
||||
comments: '',
|
||||
}
|
||||
|
||||
const sex = [{
|
||||
name: '男',
|
||||
value: 1,
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: '女',
|
||||
value: 2,
|
||||
disabled: false
|
||||
}
|
||||
]
|
||||
|
||||
import * as Api from '@/api/solution/index.js'
|
||||
import * as ApplyApi from '@/api/solution/apply.js'
|
||||
import * as SettingApi from '@/api/solution/setting.js'
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form,
|
||||
disabled: false,
|
||||
detail: {},
|
||||
solutionId: 0,
|
||||
sex,
|
||||
setting: {
|
||||
money: 0
|
||||
},
|
||||
agree: 0,
|
||||
// 是否显示协议内容
|
||||
show: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
// 获取当前用户信息
|
||||
init() {
|
||||
const app = this
|
||||
SettingApi.data().then(result => {
|
||||
app.setting = result.data.setting
|
||||
// 设置当前页面标题
|
||||
app.setPageTitle()
|
||||
})
|
||||
},
|
||||
|
||||
// 设置当前页面标题
|
||||
setPageTitle() {
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.setting.title
|
||||
})
|
||||
},
|
||||
|
||||
radioChange() {
|
||||
this.show = true
|
||||
},
|
||||
|
||||
groupChange(e) {
|
||||
this.form.sex = e
|
||||
},
|
||||
|
||||
confirm(e){
|
||||
let app = this
|
||||
},
|
||||
|
||||
// 表单提交
|
||||
handleSubmit() {
|
||||
const app = this
|
||||
const {
|
||||
form
|
||||
} = this
|
||||
app.onSubmit()
|
||||
},
|
||||
|
||||
// 提交到后端
|
||||
onSubmit() {
|
||||
const app = this
|
||||
return this.$navTo('package/solution/cashier/index')
|
||||
// const {
|
||||
// form
|
||||
// } = this
|
||||
// let req;
|
||||
// if (form.apply_status == 30) {
|
||||
// req = ApplyApi.edit(form.apply_id, form)
|
||||
// } else {
|
||||
// console.log('add');
|
||||
// req = ApplyApi.add(form)
|
||||
// }
|
||||
// req.then(result => {
|
||||
// console.log("result: ", result);
|
||||
// app.$toast(result.message)
|
||||
// setTimeout(function() {
|
||||
// uni.navigateBack()
|
||||
// }, 2000)
|
||||
|
||||
// })
|
||||
// .finally(() => app.disabled = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.partner {
|
||||
.banner {
|
||||
padding-top: 20rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
|
||||
.shop-box {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.shop-name {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.brand-poster{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.logo {
|
||||
width: 100rpx;
|
||||
}
|
||||
|
||||
.shipin {
|
||||
width: 400rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 500rpx;
|
||||
margin: 50rpx auto;
|
||||
padding-bottom: 50rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.buy-desc {
|
||||
text-align: center;
|
||||
color: #ff0000;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.buy-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 40rpx;
|
||||
|
||||
.price {
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.show-agreement{
|
||||
color: #0000ff;
|
||||
}
|
||||
}
|
||||
|
||||
.buy-text {
|
||||
text-align: center;
|
||||
}
|
||||
.agreement-content{
|
||||
padding: 20rpx;
|
||||
}
|
||||
</style>
|
||||
460
package/solution/cashier/index.vue
Executable file
460
package/solution/cashier/index.vue
Executable file
@@ -0,0 +1,460 @@
|
||||
<template>
|
||||
<view v-if="!isLoading" class="container" :style="appThemeStyle">
|
||||
<!-- 订单信息 -->
|
||||
<view class="order-info">
|
||||
<!-- 支付剩余时间 -->
|
||||
<view class="order-countdown">
|
||||
<text class="m-r-6">剩余时间</text>
|
||||
<count-down :date="order.expirationTime" separator="zh" theme="text" />
|
||||
</view>
|
||||
<!-- 付款金额 -->
|
||||
<view class="order-amount">
|
||||
<text class="unit">¥</text>
|
||||
<text class="amount">{{ order.pay_price }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式 -->
|
||||
<view class="payment-method">
|
||||
<view v-for="(item, index) in methods" :key="index" class="pay-item dis-flex flex-x-between" @click="handleSelectPayType(index)">
|
||||
<view class="item-left dis-flex flex-y-center">
|
||||
<view class="item-left_icon" :class="[item.method]">
|
||||
<text class="iconfont" :class="[PayMethodIconEnum[item.method]]"></text>
|
||||
</view>
|
||||
<view class="item-left_text">
|
||||
<text>{{ PayMethodEnum[item.method].name }}</text>
|
||||
</view>
|
||||
<view v-if="item.method === PayMethodEnum.BALANCE.value" class="user-balance">
|
||||
<text>(可用¥{{ personal.balance }}元)</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-right col-m" v-if="curPaymentItem && curPaymentItem.method == item.method">
|
||||
<text class="iconfont icon-check"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 确认按钮 -->
|
||||
<view class="footer-fixed">
|
||||
<view class="btn-wrapper">
|
||||
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">确认支付</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付确认弹窗 -->
|
||||
<!-- #ifdef H5 -->
|
||||
<u-modal v-if="tempUnifyData" v-model="showConfirmModal" title="支付确认" show-cancel-button confirm-text="已完成支付"
|
||||
:confirm-color="appTheme.mainBg" negative-top="100" :asyncClose="true"
|
||||
@confirm="onTradeQuery(tempUnifyData.outTradeNo, tempUnifyData.method)">
|
||||
<view class="modal-content">
|
||||
<text>请在{{ PayMethodClientNameEnum[tempUnifyData.method] }}内完成支付,如果您已经支付成功,请点击“已完成支付”按钮</text>
|
||||
</view>
|
||||
</u-modal>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import storage from '@/utils/storage'
|
||||
import { inArray, urlEncode } from '@/utils/util'
|
||||
import { Alipay, Wechat } from '@/core/payment'
|
||||
import CountDown from '@/components/countdown'
|
||||
import { PayMethodEnum } from '@/common/enum/payment'
|
||||
import { PayStatusEnum } from '@/common/enum/order'
|
||||
import * as Api from '@/api/solution/cashier.js'
|
||||
|
||||
// 支付方式对应的图标
|
||||
const PayMethodIconEnum = {
|
||||
[PayMethodEnum.WECHAT.value]: 'icon-wechat-pay',
|
||||
[PayMethodEnum.ALIPAY.value]: 'icon-alipay',
|
||||
[PayMethodEnum.BALANCE.value]: 'icon-balance-pay'
|
||||
}
|
||||
|
||||
// 支付方式的终端名称
|
||||
const PayMethodClientNameEnum = {
|
||||
[PayMethodEnum.WECHAT.value]: '微信',
|
||||
[PayMethodEnum.ALIPAY.value]: '支付宝'
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CountDown
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 加载中
|
||||
isLoading: true,
|
||||
// 确认按钮禁用
|
||||
disabled: false,
|
||||
// 枚举类
|
||||
PayMethodEnum,
|
||||
PayMethodIconEnum,
|
||||
PayMethodClientNameEnum,
|
||||
// 当前选中的支付方式
|
||||
curPaymentItem: null,
|
||||
// 当前订单ID
|
||||
orderId: null,
|
||||
// 当前结算订单信息
|
||||
order: {},
|
||||
// 个人信息
|
||||
personal: { balance: '0.00' },
|
||||
// 当前客户端的支付方式列表(后端根据platform判断)
|
||||
methods: [],
|
||||
// 支付确认弹窗
|
||||
showConfirmModal: false,
|
||||
// #ifdef H5
|
||||
// 当前微信支付信息 (临时数据, 仅用于H5端)
|
||||
tempUnifyData: { outTradeNo: '', method: '' },
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad({ orderId }) {
|
||||
// 记录订单ID
|
||||
this.orderId = Number(orderId)
|
||||
// 获取收银台信息
|
||||
this.getCashierInfo()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取收银台信息
|
||||
getCashierInfo() {
|
||||
const app = this
|
||||
app.isLoading = true
|
||||
Api.orderInfo()
|
||||
.then(result => {
|
||||
app.order = result.data.order
|
||||
app.personal = result.data.personal
|
||||
app.methods = result.data.paymentMethods
|
||||
app.isLoading = false
|
||||
app.setDefaultPayType()
|
||||
app.checkOrderPayStatus()
|
||||
// #ifdef H5
|
||||
// 判断当前页面来源于浏览器返回
|
||||
this.performance()
|
||||
// #endif
|
||||
})
|
||||
},
|
||||
|
||||
// 设置默认的支付方式
|
||||
setDefaultPayType() {
|
||||
const app = this
|
||||
if (app.disabled) return
|
||||
const defaultIndex = app.methods.findIndex(item => item.is_default == true)
|
||||
defaultIndex > -1 && app.handleSelectPayType(defaultIndex)
|
||||
},
|
||||
|
||||
// 判断当前订单是否为已支付
|
||||
checkOrderPayStatus() {
|
||||
const app = this
|
||||
if (app.order.pay_status == PayStatusEnum.SUCCESS.value) {
|
||||
app.$toast('恭喜您,订单已付款成功')
|
||||
app.onSuccessNav()
|
||||
}
|
||||
},
|
||||
|
||||
// 选择支付方式
|
||||
handleSelectPayType(index) {
|
||||
this.curPaymentItem = this.methods[index]
|
||||
},
|
||||
|
||||
// 判断当前页面来源于浏览器返回
|
||||
// #ifdef H5
|
||||
performance() {
|
||||
const app = this
|
||||
// 判断订单状态, 异步回调会将订单状态变为已支付, 那么就不需要让用户手动查单了
|
||||
if (app.order.pay_status == PayStatusEnum.PENDING.value) {
|
||||
app.alipayPerformance()
|
||||
app.wechatPerformance()
|
||||
}
|
||||
},
|
||||
|
||||
// H5端支付宝支付完成跳转回当前页面时触发
|
||||
alipayPerformance() {
|
||||
const app = this
|
||||
app.tempUnifyData = Alipay.performance()
|
||||
if (app.tempUnifyData) {
|
||||
app.onTradeQuery(app.tempUnifyData.outTradeNo, app.tempUnifyData.method)
|
||||
}
|
||||
},
|
||||
|
||||
// H5端微信支付完成或返回时触发
|
||||
wechatPerformance() {
|
||||
const app = this
|
||||
app.tempUnifyData = Wechat.performance(app.orderId)
|
||||
if (app.tempUnifyData) {
|
||||
app.showConfirmModal = true
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
|
||||
// 确认支付
|
||||
handleSubmit() {
|
||||
const app = this
|
||||
// 判断是否选择了支付方式
|
||||
if (!app.curPaymentItem) {
|
||||
app.$toast('您还没有选择支付方式')
|
||||
return
|
||||
}
|
||||
// 按钮禁用
|
||||
if (app.disabled) return
|
||||
app.disabled = true
|
||||
// 提交到后端API
|
||||
Api.orderPay(app.orderId, {
|
||||
method: app.curPaymentItem.method,
|
||||
client: app.platform,
|
||||
extra: app.getExtraAsUnify(app.curPaymentItem.method)
|
||||
})
|
||||
.then(result => app.onSubmitCallback(result))
|
||||
.finally(err => {
|
||||
setTimeout(() => app.disabled = false, 10)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取第三方支付的扩展参数
|
||||
getExtraAsUnify(method) {
|
||||
if (method === PayMethodEnum.ALIPAY.value) {
|
||||
return Alipay.extraAsUnify()
|
||||
}
|
||||
if (method === PayMethodEnum.WECHAT.value) {
|
||||
return Wechat.extraAsUnify()
|
||||
}
|
||||
return {}
|
||||
},
|
||||
|
||||
// 订单提交成功后回调
|
||||
onSubmitCallback(result) {
|
||||
const app = this
|
||||
const method = app.curPaymentItem.method
|
||||
const paymentData = result.data.payment
|
||||
// 余额支付
|
||||
if (method === PayMethodEnum.BALANCE.value) {
|
||||
app.onShowSuccess(result)
|
||||
}
|
||||
// 发起支付宝支付
|
||||
if (method === PayMethodEnum.ALIPAY.value) {
|
||||
console.log('paymentData', paymentData)
|
||||
Alipay.payment(paymentData)
|
||||
.then(res => app.onPaySuccess(res))
|
||||
.catch(err => app.onPayFail(err))
|
||||
}
|
||||
// 发起微信支付
|
||||
if (method === PayMethodEnum.WECHAT.value) {
|
||||
console.log('paymentData', paymentData)
|
||||
Wechat.payment({ orderKey: app.orderId, ...paymentData })
|
||||
.then(res => app.onPaySuccess(res))
|
||||
.catch(err => app.onPayFail(err))
|
||||
}
|
||||
},
|
||||
|
||||
// 订单支付成功的回调方法
|
||||
// 这里只是前端支付api返回结果success,实际订单是否支付成功 以后端的查单和异步通知为准
|
||||
onPaySuccess({ res, option: { isRequireQuery, outTradeNo, method } }) {
|
||||
const app = this
|
||||
// 判断是否需要主动查单
|
||||
// isRequireQuery为true代表需要主动查单
|
||||
if (isRequireQuery) {
|
||||
app.onTradeQuery(outTradeNo, method)
|
||||
return true
|
||||
}
|
||||
this.onShowSuccess(res)
|
||||
},
|
||||
|
||||
// 显示支付成功信息并页面跳转
|
||||
onShowSuccess({ message }) {
|
||||
this.$toast(message || '订单支付成功')
|
||||
this.onSuccessNav()
|
||||
},
|
||||
|
||||
// 订单支付失败
|
||||
onPayFail(err) {
|
||||
console.log('onPayFail', err)
|
||||
const errMsg = err.message || '订单未支付'
|
||||
this.$error(errMsg)
|
||||
},
|
||||
|
||||
// 已完成支付按钮事件: 请求后端查单
|
||||
onTradeQuery(outTradeNo, method) {
|
||||
const app = this
|
||||
// 交易查询
|
||||
// 查询第三方支付订单是否付款成功
|
||||
Api.tradeQuery({ outTradeNo, method, client: app.platform })
|
||||
.then(result => result.data.isPay ? app.onShowSuccess(result) : app.onPayFail(result))
|
||||
.finally(() => app.showConfirmModal = false)
|
||||
},
|
||||
|
||||
// 支付成功后的跳转
|
||||
onSuccessNav() {
|
||||
const pages = getCurrentPages()
|
||||
const lastPage = pages.length < 2 ? null : pages[pages.length - 2]
|
||||
const backRoutes = [
|
||||
'package/solution/index',
|
||||
'package/solution/detail'
|
||||
]
|
||||
if (lastPage && inArray(lastPage.route, backRoutes)) {
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1000)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.$navTo('package/solution/index', {}, 'redirectTo')
|
||||
}, 1200)
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background: #F4F4F4;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
background-color: #F4F4F4;
|
||||
}
|
||||
|
||||
// 订单信息
|
||||
.order-info {
|
||||
padding: 80rpx 0;
|
||||
text-align: center;
|
||||
|
||||
.order-countdown {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.order-amount {
|
||||
margin: 0 auto;
|
||||
max-width: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #111111;
|
||||
|
||||
.unit {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: -18rpx;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 56rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 支付方式
|
||||
.payment-method {
|
||||
width: 94%;
|
||||
margin: 0 auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
|
||||
.pay-item {
|
||||
padding: 26rpx 0;
|
||||
font-size: 28rpx;
|
||||
border-bottom: 1rpx solid rgb(248, 248, 248);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-left_icon {
|
||||
margin-right: 20rpx;
|
||||
font-size: 44rpx;
|
||||
|
||||
&.wechat {
|
||||
color: #00c800;
|
||||
}
|
||||
|
||||
&.alipay {
|
||||
color: #009fe8;
|
||||
}
|
||||
|
||||
&.balance {
|
||||
color: #ff9700;
|
||||
}
|
||||
}
|
||||
|
||||
.item-left_text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.user-balance {
|
||||
margin-left: 20rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 支付确认弹窗
|
||||
.modal-content {
|
||||
padding: 40rpx 48rpx;
|
||||
font-size: 30rpx;
|
||||
line-height: 50rpx;
|
||||
text-align: left;
|
||||
color: #606266;
|
||||
// height: 620rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
// 底部操作栏
|
||||
.footer-fixed {
|
||||
position: fixed;
|
||||
bottom: var(--window-bottom);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 11;
|
||||
box-shadow: 0 -4rpx 40rpx 0 rgba(151, 151, 151, 0.24);
|
||||
background: #fff;
|
||||
|
||||
// 设置ios刘海屏底部横线安全区域
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.btn-wrapper {
|
||||
height: 120rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 80rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
|
||||
// 禁用按钮
|
||||
&.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
67
package/solution/components/search.vue
Executable file
67
package/solution/components/search.vue
Executable file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-wrapper">
|
||||
<view class="index-search" @click="onClick">
|
||||
<view class="index-cont-search t-c">
|
||||
<text class="search-icon iconfont icon-search"></text>
|
||||
<text class="search-text">{{ tips }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
tips: {
|
||||
type: String,
|
||||
default: '搜索关键词'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('event')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search-wrapper {
|
||||
padding: 13rpx;
|
||||
}
|
||||
|
||||
.index-search {
|
||||
border-bottom: 0;
|
||||
border-radius: 50rpx;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
color: #6d6d6d;
|
||||
box-sizing: border-box;
|
||||
line-height: 64rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.index-cont-search {
|
||||
width: 100%;
|
||||
font-size: 28rpx;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.index-cont-search .search-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.index-cont-search .search-text {
|
||||
margin-left: 14rpx;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
107
package/solution/detail.vue
Executable file
107
package/solution/detail.vue
Executable file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<view v-if="!isLoading" class="container b-f p-b">
|
||||
<view class="article-title">
|
||||
<text class="f-32">{{ detail.title }}</text>
|
||||
</view>
|
||||
<view class="article-little dis-flex flex-x-between m-top10">
|
||||
<view class="article-little__left">
|
||||
<text class="article-views f-24 col-8">{{ detail.show_views }}次浏览</text>
|
||||
</view>
|
||||
<view class="article-little__right">
|
||||
<text class="article-views f-24 col-8">{{ detail.view_time }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="article-content m-top20">
|
||||
<mp-html :content="detail.content" />
|
||||
</view>
|
||||
<!-- 快捷导航 -->
|
||||
<shortcut />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Shortcut from '@/components/shortcut'
|
||||
import * as ArticleApi from '@/api/article'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Shortcut
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 当前文章ID
|
||||
articleId: null,
|
||||
// 加载中
|
||||
isLoading: true,
|
||||
// 当前文章详情
|
||||
detail: null
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 记录文章ID
|
||||
this.articleId = options.articleId
|
||||
// 获取文章详情
|
||||
this.getArticleDetail()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取文章详情
|
||||
getArticleDetail() {
|
||||
const app = this
|
||||
app.isLoading = true
|
||||
ArticleApi.detail(app.articleId)
|
||||
.then(result => {
|
||||
app.detail = result.data.detail
|
||||
})
|
||||
.finally(() => app.isLoading = false)
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享当前页面
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
const app = this
|
||||
// 构建页面参数
|
||||
const params = app.$getShareUrlParams({ articleId: app.articleId });
|
||||
return {
|
||||
title: app.detail.title,
|
||||
path: "/pages/article/detail?" + params
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享到朋友圈
|
||||
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta)
|
||||
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
|
||||
*/
|
||||
onShareTimeline() {
|
||||
const app = this
|
||||
// 构建页面参数
|
||||
const params = app.$getShareUrlParams({ articleId: app.articleId });
|
||||
return {
|
||||
title: app.detail.title,
|
||||
path: "/pages/article/detail?" + params
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.article-content {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
109
package/solution/index.vue
Normal file
109
package/solution/index.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<view class="solution">
|
||||
<view class="search">
|
||||
<search class="search" :tips="options.search ? options.search : '搜索关键词'" @event="onTargetDetail(2)" />
|
||||
</view>
|
||||
<view class="btn">
|
||||
<u-button type="primary" shape="circle" text="门店定制解决方案预定" @click="onApply">门店定制解决方案预定</u-button>
|
||||
</view>
|
||||
<view class="grid">
|
||||
<u-grid :border="false">
|
||||
<u-grid-item v-for="(item,index) in baseList" :key="index" @click="onTargetDetail(item.category_id)">
|
||||
<image
|
||||
:src="item.image ? item.image.preview_url : 'https://file.gxwebsoft.com/20220820/5794a3c1ed9b4d6b94737e4ebc36ce90.png'"
|
||||
class="avatar" mode="widthFix"></image>
|
||||
<text class="grid-text">{{item.name}}</text>
|
||||
</u-grid-item>
|
||||
</u-grid>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CategoryApi from '@/api/solution/category.js'
|
||||
import * as SolutionOrderApi from '@/api/order.js'
|
||||
import Search from './components/search'
|
||||
export default {
|
||||
components: {
|
||||
Search
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
baseList: [],
|
||||
// 是否已购买门店解决方案
|
||||
orderType: false
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
const app = this
|
||||
// 获取文章分类数据
|
||||
app.getCategoryList(options.categoryId)
|
||||
// 门店解决方案订单
|
||||
app.getSolutionOrder()
|
||||
},
|
||||
methods: {
|
||||
// 获取文章分类数据
|
||||
getCategoryList(categoryId) {
|
||||
CategoryApi.list({
|
||||
type: 'solution'
|
||||
}).then(result => {
|
||||
this.baseList = result.data.list
|
||||
})
|
||||
},
|
||||
// 门店解决方案订单
|
||||
getSolutionOrder() {
|
||||
const app = this
|
||||
SolutionOrderApi.list({
|
||||
dataType: 'all',
|
||||
page: 1,
|
||||
orderType: 1
|
||||
}, {
|
||||
load: false
|
||||
}).then(result => {
|
||||
if (result.data.list.total > 0) {
|
||||
app.orderType = true
|
||||
}
|
||||
})
|
||||
},
|
||||
// 跳转文章详情页
|
||||
onTargetDetail(categoryId) {
|
||||
const app = this
|
||||
const { orderType } = this
|
||||
// 已付款
|
||||
if (orderType) {
|
||||
return this.$navTo('package/solution/article/index', {
|
||||
categoryId, orderType
|
||||
})
|
||||
}
|
||||
return this.$navTo('package/solution/buy/index')
|
||||
},
|
||||
onApply() {
|
||||
this.$navTo('package/solution/apply')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.solution {
|
||||
.search {
|
||||
padding: 10rpx 20rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 700rpx;
|
||||
border-radius: 100%;
|
||||
margin: 25rpx auto;
|
||||
}
|
||||
|
||||
.grid {
|
||||
width: 700rpx;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 120rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user