Browse Source

feat: init

master
mo-bai 3 years ago
parent
commit
3bc4a4e9f6
184 changed files with 13494 additions and 0 deletions
  1. 10
      .gitignore
  2. 20
      .hbuilderx/launch.json
  3. 65
      App.vue
  4. 3
      README copy.md
  5. 34
      apis/addressApi.js
  6. 379
      apis/commonApi.js
  7. 79
      apis/mineApi.js
  8. 275
      common/css/reset.scss
  9. 501
      components/qn-easyinput/qn-easyinput.vue
  10. 95
      components/qn-input-number/qn-input-number.vue
  11. 95
      components/qn-mask/qn-mask.vue
  12. 5
      components/scroll-list/images.js
  13. 696
      components/scroll-list/scroll-list.vue
  14. 110
      enums/index.js
  15. 8
      env/index.js
  16. 12
      jsconfig.json
  17. 29
      main.js
  18. 192
      manifest.json
  19. 12
      package-lock.json
  20. 13
      package.json
  21. 103
      pages.json
  22. 313
      pages/address/index.vue
  23. 41
      pages/h5-page/index.vue
  24. 35
      pages/h5-view/index.vue
  25. 25
      pages/index/index.vue
  26. 192
      pages/login/index.vue
  27. 25
      pages/mine/index.vue
  28. 87
      pages/page-view/index.vue
  29. 114
      pages/pay-result/index.vue
  30. 151
      pages/pay/components/FileItem.vue
  31. 82
      pages/pay/components/OrderInfo.vue
  32. 454
      pages/pay/components/OtherItem.vue
  33. 77
      pages/pay/components/officialAccountPopup.vue
  34. 24
      pages/pay/index.vue
  35. 20
      prettier.config.js
  36. 25
      static/icon/iconfont.css
  37. BIN
      static/icon/iconfont.ttf
  38. BIN
      static/imgs/general/add-icon.png
  39. BIN
      static/imgs/general/baiduPan-icon.png
  40. BIN
      static/imgs/general/blue-arrow-down.png
  41. BIN
      static/imgs/general/blue-plus-icon.png
  42. BIN
      static/imgs/general/camera-icon.png
  43. BIN
      static/imgs/general/cart-icon.png
  44. BIN
      static/imgs/general/close-circle-icon.png
  45. BIN
      static/imgs/general/close-icon.png
  46. BIN
      static/imgs/general/coupon-txt-icon.png
  47. BIN
      static/imgs/general/customer-service-icon.png
  48. BIN
      static/imgs/general/default-fn-logo.png
  49. BIN
      static/imgs/general/doc-icon.png
  50. BIN
      static/imgs/general/down-act-icon.png
  51. BIN
      static/imgs/general/down-icon.png
  52. BIN
      static/imgs/general/down.png
  53. BIN
      static/imgs/general/eye-icon.png
  54. BIN
      static/imgs/general/folder-icon.png
  55. BIN
      static/imgs/general/gesture.png
  56. BIN
      static/imgs/general/hand-up-icon.gif
  57. BIN
      static/imgs/general/jinShan-icon.png
  58. BIN
      static/imgs/general/local-icon.png
  59. BIN
      static/imgs/general/logo-icon.png
  60. BIN
      static/imgs/general/not-support-icon.png
  61. BIN
      static/imgs/general/order-success-icon.png
  62. BIN
      static/imgs/general/pdf-icon.png
  63. BIN
      static/imgs/general/plus-icon.png
  64. BIN
      static/imgs/general/ppt-icon.png
  65. BIN
      static/imgs/general/qn-txt.png
  66. BIN
      static/imgs/general/question-mask-icon.png
  67. BIN
      static/imgs/general/reduce-icon.png
  68. BIN
      static/imgs/general/right-arrow-blue.png
  69. BIN
      static/imgs/general/right-arrow.png
  70. BIN
      static/imgs/general/select-icon-small.png
  71. BIN
      static/imgs/general/select-icon.png
  72. BIN
      static/imgs/general/selected-icon-small.png
  73. BIN
      static/imgs/general/selected-icon.png
  74. BIN
      static/imgs/general/share.png
  75. BIN
      static/imgs/general/tenCent-icon.png
  76. BIN
      static/imgs/general/top-arrow-icon.png
  77. BIN
      static/imgs/general/txt-bg.png
  78. BIN
      static/imgs/general/up-act-icon.png
  79. BIN
      static/imgs/general/up-arrow-icon.png
  80. BIN
      static/imgs/general/up-icon.png
  81. BIN
      static/imgs/general/upload-tip.png
  82. BIN
      static/imgs/general/uploading.gif
  83. BIN
      static/imgs/general/wx-icon.png
  84. BIN
      static/imgs/index/customer-service-icon.png
  85. BIN
      static/imgs/index/horn-icon.png
  86. BIN
      static/imgs/index/hot-icon.gif
  87. BIN
      static/imgs/index/index-community-icon.png
  88. BIN
      static/imgs/index/index-coupon-icon.png
  89. BIN
      static/imgs/index/index-library-icon.png
  90. BIN
      static/imgs/index/index-luck-draw-icon.png
  91. BIN
      static/imgs/index/index-sign-in-icon.png
  92. BIN
      static/imgs/index/send-icon.gif
  93. BIN
      static/imgs/tabbar/category-blue.png
  94. BIN
      static/imgs/tabbar/category-gray.png
  95. BIN
      static/imgs/tabbar/index-blue.png
  96. BIN
      static/imgs/tabbar/index-gray.png
  97. BIN
      static/imgs/tabbar/mine-blue.png
  98. BIN
      static/imgs/tabbar/mine-gray.png
  99. BIN
      static/imgs/tabbar/order-blue.png
  100. BIN
      static/imgs/tabbar/order-gray.png

10
.gitignore

@ -0,0 +1,10 @@
.vscode/settings.json
/unpackage/dist
/unpackage/cache
/unpackage/release
/unpackage/debug
.vscode/
.DS_Store
/**/.DS_Store

20
.hbuilderx/launch.json

@ -0,0 +1,20 @@
{ // launch.json configurations app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtypelocalremote, localremote
"version": "0.0",
"configurations": [{
"app-plus" :
{
"launchtype" : "local"
},
"default" :
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
}
]
}

65
App.vue

@ -0,0 +1,65 @@
<script>
import { silentLogin } from '@/apis/mineApi'
import { getUserAccountInfo } from '@/apis/commonApi'
export default {
methods: {
handleLogin() {
getUserAccountInfo().then(({ openId, tmpAuthToken }) => {
this.$store.commit('setOpenId', openId)
silentLogin({ authCode: tmpAuthToken }).then((res) => {
if (this.$store.state.userInfo.userId !== res.userId) {
let userInfo = {
userId: res.userId,
name: res.nickName || '',
avatar: res.avatarUrl || '',
mobile: ''
}
this.$store.commit('setUserInfo', userInfo)
}
this.$store.commit('setToken', res.token)
})
})
}
},
onLaunch: function () {
const updateManager = uni.getUpdateManager()
this.handleLogin()
updateManager.onCheckForUpdate(function (res) {
//
console.log(res.hasUpdate)
})
updateManager.onUpdateReady(function (res) {
uni.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
// applyUpdate
updateManager.applyUpdate()
}
}
})
})
updateManager.onUpdateFailed(function (res) {
//
})
}
}
</script>
<style lang="scss">
/*每个页面公共css */
@import url('./common/css/reset.scss');
@import '@/static/icon/iconfont.css';
page {
height: 100%;
}
/* uni-dialog标题样式 */
.uni-dialog-title-text {
font-size: 32rpx !important;
color: #323233 !important;
font-weight: 500 !important;
}
</style>

3
README copy.md

@ -0,0 +1,3 @@
# 飞鸟快印微信小程序
uni-app

34
apis/addressApi.js

@ -0,0 +1,34 @@
import http from '@/utils/http/index.js'
/**
* 获取用户地址列表
* @param {object} data 参数 userId
*/
export function getAddressList(data = {}) {
return http.get({
url: `/wukong-fast-print/get/personal-shipping-address/list`,
data
})
}
/**
* 保存或修改用户地址列表
* @param {object} data 参数 id
*/
export function changeAddress(data = {}) {
return http.post({
url: `/wukong-fast-print/save/personal-shipping-address`,
data
})
}
/**
* 删除用户地址
* @param {object} data 参数 id
*/
export function deleteAddress(data = {}) {
return http.post({
url: `/wukong-fast-print/delete/my-address`,
data
})
}

379
apis/commonApi.js

@ -0,0 +1,379 @@
import http from '@/utils/http/index.js'
import store from '@/store/index'
import { XAPPID} from '@/enums/index.js'
import { wxAuthorize } from '@/apis/mineApi.js'
let priceMap = null
/**
* 获取价目表
* @param {boolean} refresh 是否刷新
* @returns
*/
export function getPriceMap(refresh = false) {
return new Promise((resolve) => {
if (!refresh && priceMap) {
resolve(priceMap)
} else {
http.get({ url: '/wukong-fast-print/get/printing/file/marked/price/by' }).then((res) => {
priceMap = res
resolve(res)
})
}
})
}
let postageMap = null
/**
* 获取邮费
* @param {boolean} refresh 是否刷新
* @returns
*/
export function getPostagePrice(refresh = true, goodsId = '') {
return new Promise((resolve) => {
if (!refresh && postageMap) {
resolve(postageMap)
} else {
let data = { goodsId }
let params = goodsId ? { url: '/wukong-fast-print/get/postage/conditions', data } : { url: '/wukong-fast-print/get/postage/conditions' }
http.get(params).then((res) => {
postageMap = res
resolve(res)
})
}
})
}
/**
* 获取OSS上传信息
* @returns
*/
export function getOssInfo() {
return http.get({
url: '/wukong-fast-print/getOssSign'
})
}
let loading = false
let resolveQueue = []
let rejectQueue = []
/**
* 获取用户tmpAuthToken和openId
* @return {Promise}
*/
export function getUserAccountInfo() {
if (loading) {
return new Promise((resolve, reject) => {
resolveQueue.push(resolve)
rejectQueue.push(reject)
})
}
loading = true
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: (loginRes) => {
let code = loginRes.code
getSession({ authCode: code })
.then((res) => {
resolve(res)
resolveQueue.forEach((fn) => {
fn(res)
})
})
.catch((err) => {
reject(err)
rejectQueue.forEach((fn) => {
fn(err)
})
})
.finally(() => {
loading = false
resolveQueue = []
rejectQueue = []
})
},
fail: (err) => {
reject(err)
rejectQueue.forEach((fn) => {
fn(err)
})
loading = false
resolveQueue = []
rejectQueue = []
}
})
})
}
/**
* 获取微信小程序认证会话
* @param {object} data 参数 authCode
*/
export function getSession(data = {}) {
return http.post(
{
url: `/uec/get/wechat-applet-session`,
data
},
{ hideLoading: true }
)
}
// wx登陆生成器缓存
let loginGenerator = {}
// wx会话缓存
let session = {}
/**
* 微信小程序登陆
* @param {object} data
* @returns {(login:Function,getSession:Function)}
*/
export function wxLoginGenerate() {
if (loginGenerator.login && loginGenerator.getSession) {
if (Date.now() > session.expireTime) {
loginGenerator.getSession()
}
return loginGenerator
}
let completed = false
function getSession() {
getUserAccountInfo()
.then(({ tmpAuthToken, openId, expireTime }) => {
expireTime = expireTime.replace(/-/g, '/')
store.commit('setOpenId', openId)
session = { tmpAuthToken, openId, expireTime: new Date(expireTime) }
completed = true
})
.catch((err) => {
console.log(err)
completed = false
})
}
getSession()
function login() {
return new Promise((resolve, reject) => {
if (!completed) {
reject('未获取到会话,请再次点击登陆')
return
}
if (Date.now() > session.expireTime) {
getSession()
reject('会话已失效,请再次点击登陆')
return
}
uni.getUserProfile({
desc: '获取你的昵称、头像',
success: (res) => {
let iv = res.iv
let encryptedData = res.encryptedData
uni.showLoading({
title: '加载中'
})
wxAuthorize({ iv, encryptedData, tmpAuthToken: session.tmpAuthToken })
.then((info) => {
let userInfo = {
name: res.userInfo.nickName,
userId: info.userId,
avatar: res.userInfo.avatarUrl,
mobile: ''
}
store.commit('setUserInfo', userInfo)
store.commit('setToken', info.token)
resolve(userInfo)
})
.catch(() => {
reject('获取用户信息异常,请联系客服')
})
.finally(() => {
uni.hideLoading()
})
},
fail: () => {
reject('请同意昵称和头像信息的授权')
}
})
})
}
loginGenerator = { login, getSession }
return loginGenerator
}
/**
* 获取当前账号的企业实名认证地址
* @param {object} data 参数 enterpriseId
*/
export function getVerifyUrl(data = {}) {
return http.post({ url: '/yyt-uec/get/fdd-enterprise-verify-url?enterpriseId=' + data.enterpriseId, data })
}
/**
* 生成担保合同的签约地址同意纸盘商只需要签约一次即可
* @param {object} data 参数 mallSupplierId
*/
export function getGuaranteeContract(data = {}) {
return http.post({
url: `/yyt-uec/create/supplier/guarantee-contract?mallSupplierId=${data.mallSupplierId}&customerEnterpriseId=${data.customerEnterpriseId}`,
data
})
}
/**
* 转换合同成图片
* @param {object} data 图片地址链接 fileUrl
*/
export function transformFileToImg(data) {
return http.get({
url: '/document/get/enterprise-documents/file-image-base64',
data: data
})
}
/**
* 获取快递列表
* @param {object} data
*/
export function getPostageList(data) {
return http.get({
url: '/wukong-fast-print/get/printing/express/type',
data: data
})
}
/**
* 获取网盘链接地址
* @param {object} data
*/
export function getBandingLink(data) {
return http.get({
url: '/uec/user/get/baidu-pan/authorize-page',
data: data
})
}
/**
* 获取当前账号企业的飞算额度
* @param {object} data 参数 enterpriseId
*/
export function getFsCredit(data = {}) {
return http.get({
url: '/yyt-uec/credit/get/enterprise-feisuan-credit',
data
})
}
/**
* 获取当前账号企业的被担保的月结额度
* @param {object} data 参数 enterpriseId supplierId
*/
export function getMonthCredit(data = {}) {
return http.get({ url: '/yyt-uec/customer/get/supplier-credit', data })
}
/**
* 推送客户绑定
*
*/
export function pushCustomerBind(cid, platformType = 'android', appId = XAPPID) {
return http.post({
url: '/base-paper-trading/user/binding/geTui/cid',
data: { cid, appId, platformType }
})
}
/**
* 推送客户绑定
*
*/
export function pushCustomerOff(cid, platformType = 'android', appId = XAPPID) {
return http.post({
url: '/base-paper-trading/user/geTui/offline',
data: { cid, appId, platformType }
})
}
/**
* 营业执照OCR识别 photoUrl
*/
export function getLicenseOcr(data = {}) {
return http.post({
url: '/base-paper-trading/ocr/business-license',
data: data
})
}
/**
* 身份证正面OCR识别 image
*/
export function getFrontIdCardOcr(data = {}) {
return http.post({
url: '/base-paper-trading/ocr/id-card/face',
data: data
})
}
/**
* 飞鸟快印绑定代销商
* @param {object} data storeUserId
*/
export function bindingStore(data = {}) {
return http.post(
{
url: '/wukong-fast-print/user/create/distribution-relation',
data: data
},
{ hideLoading: true }
)
}
/**
* 获取二维码绑定的userId
* @param {object} data host QrCodeRecordId
*/
export function getQrCodeRecordId(data = {}) {
return http.get(
{
url: '/uec/verify/qrcode',
data
},
{ hideLoading: true }
)
}
/**
* 获取半天妖客户经理列表
* @param {object} data host QrCodeRecordId
*/
export function getBTAreaList() {
return http.get(
{
url: '/wukong-fast-print/get/ban/tian/yao/area/customer/manager/list'
},
{ hideLoading: true }
)
}
/**
* 获取活动海报
*/
export function getPoster(data = {}) {
return http.get({
url: '/uec/fission/get/poster',
data
})
}
/**
* 用户修改用户昵称和头像
* @param {*} data
* @returns
*/
export function changeUserInfo(data = {}) {
return http.post({
url: '/uec/user/update/user-info',
data: data
})
}
export function uploadAvatar(path) {
return http.uploadFile({ data: { filePath: path } })
}

79
apis/mineApi.js

@ -0,0 +1,79 @@
import http from '@/utils/http/index.js'
/**
* 微信登录认证获取token
* @param {object} data 参数 encryptedData iv tmpAuthToken
*/
export function wxAuthorize(data = {}) {
return http.post({
url: `/uec/authorize/by-wechat-applet/without-regest`,
data
})
}
/**
* 微信小程序静默登录
* @param {object} data 参数 authCode
*/
export function silentLogin(data = {}) {
return http.post(
{
url: `/uec/authorize/by-wechat-applet/without-regest/unlogin`,
data
},
{ hideLoading: true }
)
}
/**
* 获取用户代理商状态
* @param {object} data 参数
*/
export function getStoreState(data = {}) {
return http.get(
{
url: `/wukong-fast-print/get/agency/shop/status`,
data
},
{ hideLoading: true }
)
}
/**
* 获取代理商佣金统计
* @param {object} data 参数
*/
export function getStoreStatistics(data = {}) {
return http.get(
{
url: `/wukong-fast-print/get/agency/commission/statistics`,
data
},
{ hideLoading: true }
)
}
/**
* 提交店铺申请
* @param {object} data 参数
*/
export function makeStoreApplication(data = {}) {
return http.post({
url: `/wukong-fast-print/submit/agency/store/apply`,
data
})
}
/**
* 获取代理商佣金统计
* @param {object} data 参数
*/
export function getPreferentialCardList(data = {}) {
return http.get(
{
url: `/wukong-fast-print/get/preferential/card/list`,
data
}
)
}

275
common/css/reset.scss

@ -0,0 +1,275 @@
page {
font-size: $uni-font-size-base;
line-height: 1;
background-color: #f7f8fa;
-webkit-overflow-scrolling: touch; /* 使ios列表滑动流畅*/
}
// 标签重置
page,
view,
input,
text,
form,
navigator,
rich-text,
picker,
scroll-view,
cover-view,
open-data {
box-sizing: border-box;
}
rich-text,
open-data,
form {
display: block;
}
view,
image,
text {
box-sizing: border-box;
flex-shrink: 0;
}
// flex快捷类
.flex-row {
display: flex;
flex-direction: row;
}
.flex-col {
display: flex;
flex-direction: column;
}
.justify-start {
display: flex;
justify-content: flex-start;
}
.justify-center {
display: flex;
justify-content: center;
}
.justify-end {
display: flex;
justify-content: flex-end;
}
.justify-evenly {
display: flex;
justify-content: space-evenly;
}
.justify-around {
display: flex;
justify-content: space-around;
}
.justify-between {
display: flex;
justify-content: space-between;
}
.items-start {
display: flex;
align-items: flex-start;
}
.items-center {
display: flex;
align-items: center;
}
.items-end {
display: flex;
align-items: flex-end;
}
.text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
cover-view {
line-height: 1.5;
white-space: normal;
}
// 隐藏滑动条
*::webkit-scrollbar {
display: none;
}
// 重置按钮样式
button::after {
border: 0;
}
/* 清除浮动 */
.clearfix:after {
content: '.';
display: block;
height: 0;
clear: both;
visibility: hidden;
}
// 两行省略号
.u-line-2 {
-webkit-line-clamp: 2;
overflow: hidden;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box; // 弹性伸缩盒
-webkit-box-orient: vertical; // 设置伸缩盒子元素排列方式
}
// flex 快捷类
.flex-row-start-start {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
}
.flex-row-start-center {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: center;
}
.flex-row-start-end {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-end;
}
.flex-row-start-space {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
}
.flex-row-center-start {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.flex-row-center-center {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.flex-row-center-end {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
}
.flex-row-center-space {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.flex-row-end-start {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: flex-start;
}
.flex-row-end-center {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: center;
}
.flex-row-end-end {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: flex-end;
}
.flex-row-end-space {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: space-between;
}
.flex-col-start-start {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
}
.flex-col-start-center {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
}
.flex-col-start-end {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-end;
}
.flex-col-start-space {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
}
.flex-col-center-start {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
.flex-col-center-center {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.flex-col-center-end {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
}
.flex-col-center-space {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.flex-col-end-start {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: flex-start;
}
.flex-col-end-center {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
}
.flex-col-end-end {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: flex-end;
}
.flex-col-end-space {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: space-between;
}
// flex 快捷子类
.flex-base {
flex-grow: 0;
flex-shrink: 0;
}

501
components/qn-easyinput/qn-easyinput.vue

@ -0,0 +1,501 @@
<template>
<view class="uni-easyinput" :class="{ 'uni-easyinput-error': msg }" :style="{ color: inputBorder && msg ? '#e43d33' : styles.color }">
<view
class="uni-easyinput__content"
:class="{ 'is-input-border': inputBorder, 'is-input-error-border': inputBorder && msg, 'is-textarea': type === 'textarea', 'is-disabled': disabled }"
:style="{
'border-color': inputBorder && msg ? '#dd524d' : styles.borderColor,
'background-color': disabled ? styles.disableColor : ''
}"
>
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" @click="onClickIcon('prefix')"></uni-icons>
<textarea
v-if="type === 'textarea'"
class="uni-easyinput__content-textarea"
:class="{ 'input-padding': inputBorder }"
:name="name"
:value="val"
:placeholder="placeholder"
:placeholderStyle="placeholderStyle"
:disabled="disabled"
placeholder-class="uni-easyinput__placeholder-class"
:maxlength="inputMaxlength"
:focus="focused"
:autoHeight="autoHeight"
@input="onInput"
@blur="onBlur"
@focus="onFocus"
@confirm="onConfirm"
></textarea>
<input
v-else
:type="type === 'password' ? 'text' : type"
class="uni-easyinput__content-input"
:style="{
'padding-right': type === 'password' || clearable || prefixIcon ? '' : '10px',
'padding-left': prefixIcon ? '' : '10px',
'text-align': text
}"
:name="name"
:value="val"
:password="!showPassword && type === 'password'"
:placeholder="placeholder"
:placeholderStyle="placeholderStyle"
placeholder-class="uni-easyinput__placeholder-class"
:disabled="disabled"
:maxlength="inputMaxlength"
:focus="focused"
:confirmType="confirmType"
@focus="onFocus"
@blur="onBlur"
@input="onInput"
@confirm="onConfirm"
/>
<template v-if="type === 'password' && passwordIcon">
<uni-icons
v-if="val != ''"
class="content-clear-icon"
:class="{ 'is-textarea-icon': type === 'textarea' }"
:type="showPassword ? 'eye-slash-filled' : 'eye-filled'"
:size="18"
color="#c0c4cc"
@click="onEyes"
></uni-icons>
</template>
<template v-else-if="suffixIcon">
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" @click="onClickIcon('suffix')"></uni-icons>
</template>
<template v-else>
<uni-icons
class="content-clear-icon"
:class="{ 'is-textarea-icon': type === 'textarea' }"
type="clear"
:size="clearSize"
v-if="clearable && val && !disabled"
color="#c0c4cc"
@click="onClear"
></uni-icons>
</template>
<slot name="right"></slot>
</view>
</view>
</template>
<script>
/**
* Easyinput 输入框
* @description 此组件可以实现表单的输入与校验包括 "text" "textarea" 类型
* @tutorial https://ext.dcloud.net.cn/plugin?id=3455
* @property {String} value 输入内容
* @property {String } type 输入框的类型默认text password/text/textarea/..
* @value text 文本输入键盘
* @value textarea 多行文本输入键盘
* @value password 密码输入键盘
* @value number 数字输入键盘注意iOS上app-vue弹出的数字键盘并非9宫格方式
* @value idcard 身份证输入键盘支付宝百度QQ小程序
* @value digit 带小数点的数字键盘 App的nvue页面微信支付宝百度头条QQ小程序支持
* @property {Boolean} clearable 是否显示右侧清空内容的图标控件点击可清空输入框内容默认true
* @property {Boolean} autoHeight 是否自动增高输入区域type为textarea时有效默认true
* @property {String } placeholder 输入框的提示文字
* @property {String } placeholderStyle placeholder的样式(内联样式字符串)"color: #ddd"
* @property {Boolean} focus 是否自动获得焦点默认false
* @property {Boolean} disabled 是否禁用默认false
* @property {Number } maxlength 最大输入长度设置为 -1 的时候不限制最大长度默认140
* @property {String } confirmType 设置键盘右下角按钮的文字仅在type="text"时生效默认done
* @property {Number } clearSize 清除图标的大小单位px默认15
* @property {String} prefixIcon 输入框头部图标
* @property {String} suffixIcon 输入框尾部图标
* @property {Boolean} trim 是否自动去除两端的空格
* @value both 去除两端空格
* @value left 去除左侧空格
* @value right 去除右侧空格
* @value start 去除左侧空格
* @value end 去除右侧空格
* @value all 去除全部空格
* @value none 不去除空格
* @property {Boolean} inputBorder 是否显示input输入框的边框默认true
* @property {Boolean} passwordIcon type=password时是否显示小眼睛图标
* @property {Object} styles 自定义颜色
* @event {Function} input 输入框内容发生变化时触发
* @event {Function} focus 输入框获得焦点时触发
* @event {Function} blur 输入框失去焦点时触发
* @event {Function} confirm 点击完成按钮时触发
* @event {Function} iconClick 点击图标时触发
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
*/
export default {
name: 'uni-easyinput',
emits: ['click', 'iconClick', 'update:modelValue', 'input', 'focus', 'blur', 'confirm'],
model: {
prop: 'modelValue',
event: 'update:modelValue'
},
props: {
name: String,
value: [Number, String],
modelValue: [Number, String],
type: {
type: String,
default: 'text'
},
clearable: {
type: Boolean,
default: true
},
autoHeight: {
type: Boolean,
default: false
},
placeholder: String,
placeholderStyle: String,
focus: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
maxlength: {
type: [Number, String],
default: 140
},
confirmType: {
type: String,
default: 'done'
},
clearSize: {
type: [Number, String],
default: 15
},
inputBorder: {
type: Boolean,
default: true
},
prefixIcon: {
type: String,
default: ''
},
suffixIcon: {
type: String,
default: ''
},
trim: {
type: [Boolean, String],
default: true
},
passwordIcon: {
type: Boolean,
default: true
},
styles: {
type: Object,
default() {
return {
color: '#333',
disableColor: '#F7F6F6',
borderColor: '#e5e5e5'
}
}
},
errorMessage: {
type: [String, Boolean],
default: ''
},
// left|center|right
text: {
type: String,
default: 'left'
}
},
data() {
return {
focused: false,
errMsg: '',
val: '',
showMsg: '',
border: false,
isFirstBorder: false,
showClearIcon: false,
showPassword: false
}
},
computed: {
msg() {
return this.errorMessage || this.errMsg
},
// uniappinputmaxlength
inputMaxlength() {
return Number(this.maxlength)
}
},
watch: {
value(newVal) {
this.resetValue(newVal)
},
modelValue(newVal) {
this.resetValue(newVal)
},
focus() {
this.$nextTick(() => {
this.focused = this.focus
})
}
},
created() {
if (!this.value) {
this.val = this.modelValue
}
if (!this.modelValue) {
this.val = this.value
}
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
if (this.form && this.formItem) {
if (this.formItem.name) {
if (!this.is_reset) {
this.is_reset = false
this.formItem.setValue(this.val)
}
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
},
mounted() {
this.$nextTick(() => {
this.focused = this.focus
})
},
methods: {
/**
* 监听value modelValue 变化
*/
resetValue(newVal) {
if (this.errMsg) this.errMsg = ''
this.val = newVal
if (this.form && this.formItem && !this.is_reset) {
this.is_reset = false
this.formItem.setValue(newVal)
}
},
onClickIcon(type) {
this.$emit('iconClick', type)
},
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
let parent = this.$parent
let parentName = parent.$options.name
while (parentName !== name) {
parent = parent.$parent
if (!parent) return false
parentName = parent.$options.name
}
return parent
},
onEyes() {
this.showPassword = !this.showPassword
},
onInput(event) {
let value = event.detail.value
//
if (this.trim) {
if (typeof this.trim === 'boolean' && this.trim) {
value = this.trimStr(value)
}
if (typeof this.trim === 'string') {
value = this.trimStr(value, this.trim)
}
}
if (this.errMsg) this.errMsg = ''
this.val = value
this.$emit('input', value)
this.$emit('update:modelValue', value)
},
onFocus(event) {
this.$emit('focus', event)
},
onBlur(event) {
this.$emit('blur', event)
},
onConfirm(e) {
this.$emit('confirm', e.detail.value)
},
onClear() {
this.val = ''
this.$emit('input', '')
this.$emit('update:modelValue', '')
},
fieldClick() {
this.$emit('click')
},
trimStr(str, pos = 'both') {
if (pos === 'both') {
return str.trim()
} else if (pos === 'left') {
return str.trimLeft()
} else if (pos === 'right') {
return str.trimRight()
} else if (pos === 'start') {
return str.trimStart()
} else if (pos === 'end') {
return str.trimEnd()
} else if (pos === 'all') {
return str.replace(/\s+/g, '')
} else if (pos === 'none') {
return str
}
return str
}
}
}
</script>
<style lang="scss" scoped>
$uni-error: #e43d33;
$uni-border-1: #dcdfe6 !default;
.uni-easyinput {
/* #ifndef APP-NVUE */
width: 100%;
/* #endif */
flex: 1;
position: relative;
text-align: left;
color: #333;
font-size: 14px;
}
.uni-easyinput__content {
flex: 1;
/* #ifndef APP-NVUE */
width: 100%;
display: flex;
box-sizing: border-box;
min-height: 21px;
height: 100%;
/* #endif */
flex-direction: row;
align-items: center;
}
.uni-easyinput__content-input {
/* #ifndef APP-NVUE */
width: auto;
/* #endif */
position: relative;
overflow: hidden;
flex: 1;
line-height: 1;
font-size: 14px;
}
.uni-easyinput__placeholder-class {
color: #999;
font-size: 12px;
font-weight: 200;
}
.is-textarea {
align-items: flex-start;
}
.is-textarea-icon {
margin-top: 5px;
}
.uni-easyinput__content-textarea {
position: relative;
overflow: hidden;
flex: 1;
line-height: 1.5;
font-size: 14px;
padding-top: 6px;
padding-bottom: 10px;
height: 80px;
/* #ifndef APP-NVUE */
min-height: 80px;
width: auto;
/* #endif */
}
.input-padding {
padding-left: 10px;
}
.content-clear-icon {
padding: 0 5px;
}
.label-icon {
margin-right: 5px;
margin-top: -1px;
}
//
.is-input-border {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
align-items: center;
border: 1px solid $uni-border-1;
border-radius: 4px;
}
.uni-error-message {
position: absolute;
bottom: -17px;
left: 0;
line-height: 12px;
color: $uni-error;
font-size: 12px;
text-align: left;
}
.uni-error-msg--boeder {
position: relative;
bottom: 0;
line-height: 22px;
}
.is-input-error-border {
border-color: $uni-error;
.uni-easyinput__placeholder-class {
color: mix(#fff, $uni-error, 50%);
}
}
.uni-easyinput--border {
margin-bottom: 0;
padding: 10px 15px;
// padding-bottom: 0;
border-top: 1px #eee solid;
}
.uni-easyinput-error {
padding-bottom: 0;
}
.is-first-border {
/* #ifndef APP-NVUE */
border: none;
/* #endif */
/* #ifdef APP-NVUE */
border-width: 0;
/* #endif */
}
.is-disabled {
border-color: red;
background-color: #f7f6f6;
color: #d5d5d5;
.uni-easyinput__placeholder-class {
color: #d5d5d5;
font-size: 12px;
}
}
</style>

95
components/qn-input-number/qn-input-number.vue

@ -0,0 +1,95 @@
<template>
<view class="wrapper">
<view class="minus-box" @tap="minusTap">
<uni-icons size="16" custom-prefix="iconfont" type="icon-Less" color="#007AFF"></uni-icons>
</view>
<view style="padding: 0rpx 4rpx">
<qn-easyinput
:inputBorder="false"
class="quantity-input"
style="height: 64rpx"
:clearable="false"
type="number"
:value="value"
placeholder="请输入"
@blur="blur"
@confirm="confirm"
@input="input"
></qn-easyinput>
</view>
<view class="minus-box" @tap="addTap"><uni-icons size="16" type="plusempty" color="#007AFF"></uni-icons></view>
</view>
</template>
<script>
export default {
props: {
quantity: {
type: [Number, String],
default: 0
}
},
data() {
return {
value: 0
}
},
watch: {
quantity: {
handler(nv, ov) {
this.value = nv
},
immediate: true
}
},
methods: {
input(value) {
this.$emit('input', value)
},
blur(e) {
this.$emit('change', e.detail.value)
},
confirm(value) {
if (value.trim()) {
this.$emit('change', value)
}
},
minusTap() {
if (this.value == 0) {
return
}
this.value--
this.$emit('change', this.value)
},
addTap() {
this.value++
this.$emit('change', this.value)
}
}
}
</script>
<style lang="scss" scoped>
.wrapper {
display: flex;
flex-direction: row;
align-items: center;
.minus-box {
width: 64rpx;
height: 64rpx;
line-height: 64rpx;
text-align: center;
background: #f2f3f5;
border-radius: 8rpx;
color: #007aff;
}
.quantity-input {
width: 120rpx;
height: 64rpx;
background: #f2f3f5;
/deep/ .uni-easyinput__content {
min-height: 64rpx;
}
}
}
</style>

95
components/qn-mask/qn-mask.vue

@ -0,0 +1,95 @@
<template>
<view class="mask" @click="hide" v-if="visible">
<view class="flex-col items-center group_7" @click.stop="() => {}" v-if="codeUrl">
<image :src="imgStamp['service-bg']" class="image_12" />
<view class="group_8">
<view class="flex-col items-center image-wrapper_1">
<image :src="codeUrl" :show-menu-by-longpress="true" class="image_13" />
</view>
<text class="text_10">{{ text }}</text>
</view>
</view>
</view>
</template>
<script>
import { imgStamp } from '@/enums/index'
export default {
props: {
codeUrl: {
type: String,
default: ''
},
text: {
type: String,
default: ''
}
},
data() {
return {
visible: false,
imgStamp: Object.freeze(imgStamp)
}
},
methods: {
show() {
this.visible = true
},
hide() {
this.visible = false
}
}
}
</script>
<style lang="scss" scoped>
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
.group_7 {
width: 588rpx;
position: relative;
.image_12 {
width: 588rpx;
height: 646rpx;
}
.group_8 {
display: flex;
flex-direction: column;
align-items: center;
width: 440rpx;
position: absolute;
top: 56rpx;
left: 50%;
transform: translateX(-50%);
.image-wrapper_1 {
padding: 20rpx 0 22rpx;
background-color: #ffffff;
width: 402rpx;
.image_13 {
border-radius: 16rpx;
width: 360rpx;
height: 360rpx;
}
}
.text_10 {
margin-top: 40rpx;
color: #4f270d;
font-size: 36rpx;
font-family: 'PingFangSC-Medium';
font-weight: 500;
line-height: 50rpx;
// letter-spacing: 14rpx;
}
}
}
}
</style>

5
components/scroll-list/images.js

@ -0,0 +1,5 @@
export default {
empty: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHoAAABoCAYAAAA+R+R0AAAG50lEQVR4Xu2df1PURhjHn71fOQ8ZsKIoWioWsHcOLU49O53OqbwDfQm+AugraN+B+grad1D7CkDPzrSeHbAM54+2YLHiyGAL43DclSTb2UgwQC7Zu01ySfbJPzdym2ef5/vJdzeX7KwE8JBCASJFlVgkIGhJLgIEjaAlUUCSMtHRCFoSBSQpEx2NoCVRQJIy0dEBgi5XqtOlYmEiwC53u0LQAalersxfBUhOA2gTpeLYTEDdIuighUbQQSsecH/vAJvHO0eb/wrS2Th0+wiezckAYAF9oLOZoOZsBO0jaBYaHe2zwGELj3N02Ij4lA+Ctgg7PTvbO3Hhwrr56ZPmHQuLv6MBgMFNqcocAPkOgN4oFQtnOkYkhh2H6masXFn4FoB8Qym5cflS/vsY6t2xkkIDmjk6qSrPgZIpAvpU6dL58Y6pEsOOQwM6htqGqiQEHSoc/iWDoP3TNlSREXSocPiXDIL2T9tQRUbQocLhXzII2j9tQxUZQYcKh3/JIGj/tA1VZGlAsydvaS1zk1JiPEMnhD7fTv73NXuJEioiPiUjBeifHiyM64TMJBKkK3com2Ja1rbqqq7TzQSlV7+6dH7OJ31DEzZ2oO89rF4jFCatChOAz0kikTt3diB5KKsYX23VG/B0cUWjul6jAL9a21MCty9fLNwJDSUPEokV6B3IP6TTSVXJZAznskNJp+B4Xw+YkM2/M9iraxvQ2FZ3pdyqN3RN0xOUwPU4wY4U6PKD6iQQuOZwgY9n0qme/PCHJJlMtO2Dueoi6Dplc3fTIZ0CzGkquT3xZf552x0FeGJkQN9/+Pg3SulYJp1SD2Xfu9Wq1WatDtmsAqNDA0ISPltagXq9AV25rG2czVpDVzUtAUDXVTVxIQqwIwH6fqU6RQFuDg70weDAsaYQ55/+BVuNbch/fBpEHP3o8RL0dndBfvh0075WXv8Diy9eAxC4XbpYmBK6sgI42TPQd39hq0MArnxx3vj08ihXqjNKJl0qfjrsOB6/WX8Lj//4GzKZtDEvt3PU6g3QNN2AfLS32zHEz7PPmLPLpWLBae12O2l4fo5noHcWq4MfC9IZ6J7u3JWxcx+5CsBgM7eJHAP9H7hCZvHZCLLxtnYXQYuobTm3FdAedckVRhrQbLhOJMgVO1V0nd71ahhH0FzXnWMjoaEbQePQLX4J4tDtqYZCjrZmEpabMU/VcQkmzRxt1cHvn1e8d90I2l4Bzxztp8B4MyauLoIW0FDKoVtAL9dTvXJ0vbENvy+9goH+I3D0iPNTL9ekZH1gwiNMu228Ar38cg2WV9bAeGZ+qq/ddHbPQ0cLS7g3AIIWF1SqOboVR2+8rUFPd85RYXS0+AW4JwKPo2cXluBwLgtDg8chlUzaZsADWtU0mH/yAti77fzwKce5HEEHDJrBqTz603i9yBYLjA6dsF008OZf9hrzJRztPQz5kYPvmhlcBpnFUzJpGPtkELJKumk1CDpg0Kw7BunZ0ivYrDUMR48MnTjgRjYczz9ZNu66zw7278ny9doGLC2vGpC7cooBudnIYJ6IoDsAmnXJIC0urxoL/tgxMnQS+vt69mTD2uwHaDqdNWSLCEeHTnJVgKC5ZOJvxDNHW6MZy3yWV22da9er6XS7C8MpSwTNz5CrZaugWVD2cMRpfuXq2KURgvZCRUuMdkB7nIJtOATtscoIWlxQqR6YiMu1NwI62mNF0dHigqKjBTQUcbSfCzXsSkLQHQLt59IrBC0A1e5UEUcjaBtF4zJHB7U8Gh3dYUcjaBcAcXG0tUwcumM8dCNoCR2NP68kcbTHtwuu4QL7HX2vUr1DgNwCoJOlYuG6a2b4UqMViVzbBgba3J6CAvx4uVhw2nDmQNLsZiyrpEsXx5x3PHCt1uMGUu544KZh+cHCHBCyTgHGtVTjTCs79r3fw+SYsSY7DIe0e5i4ic9272M79Jmfbu33f79zoXymZFJqVrHflajVmO22N3clogAbmkrGcVeidpVsct6Os1sa9j1O4X04AnPqNrkVBcgs6cDmaN8Ex8BcCiBoLpmi3whBR58hVwUImkum6DdC0NFnyFWBEOi9/9s5V39SNCoVx2ashVp12v+d2Y5Hy2bn8ojaNuid12yh3wOTRwQf2syYW2Ue1EmbOHghVKcBgEfL3bit5tw2aNYRz1XYakJxaB8rR8cBiEw1CDlaJqGiXiuCjjpBzvwRNKdQUW+GoKNOkDP/UIJ2WhbL6tq/F7i5opKzZk+bebkvuaeJ7QuGoAXVRdCCAuLp3ioQSkd7WyJGYwogaEmuAwSNoCVRQJIy0dEIWhIFJCkTHY2gJVFAkjLR0QhaEgUkKRMdjaAlUUCSMtHRkoD+H39JyZZ6zcs+AAAAAElFTkSuQmCC',
success: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgdmlld0JveD0iMCAwIDQ4IDQ4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgZmlsbD0id2hpdGUiIGZpbGwtb3BhY2l0eT0iMC4wMSIvPjxwYXRoIGQ9Ik0xMCAyNEwyMCAzNEw0MCAxNCIgc3Ryb2tlPSIjMzAzMTMzIiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjwvc3ZnPg==',
error: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgdmlld0JveD0iMCAwIDQ4IDQ4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgZmlsbD0id2hpdGUiIGZpbGwtb3BhY2l0eT0iMC4wMSIvPjxwYXRoIGQ9Ik0xNCAxNEwzNCAzNCIgc3Ryb2tlPSIjMzAzMTMzIiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0xNCAzNEwzNCAxNCIgc3Ryb2tlPSIjMzAzMTMzIiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjwvc3ZnPg=='
}

696
components/scroll-list/scroll-list.vue

@ -0,0 +1,696 @@
<template>
<view class="scroll-list-wrap" :style="[scrollListWrapStyle]">
<scroll-view
class="scroll-view"
:class="[elClass]"
:style="[listWrapStyle]"
scroll-y
scroll-anchoring
enable-back-to-top
:scroll-top="scrollTop"
:lower-threshold="defaultOption.lowerThreshold"
@scroll="handleScroll"
@touchend="handleTouchEnd"
@touchmove.prevent.stop="handleTouchMove"
@touchstart="handleTouchStart"
@scrolltolower="handleScrolltolower"
>
<view class="scroll-content" :style="[scrollContentStyle]">
<view class="pull-down-wrap">
<slot name="pulldown" v-if="$slots.pulldown"></slot>
<view class="refresh-view" :style="[refreshViewStyle]" v-else>
<view
class="pull-down-animation"
:class="{ refreshing: refreshing }"
:style="[pullDownAnimationStyle]"
></view>
<text class="pull-down-text" :style="[pullDownTextStyle]">{{
refreshStateText
}}</text>
</view>
</view>
<view class="empty-wrap" v-if="showEmpty">
<slot name="empty" v-if="$slots.empty"></slot>
<view class="empty-view flex-col-center-center" v-else>
<image
class="empty-image"
:src="defaultOption.emptyImage || images.empty"
mode="aspectFit"
></image>
<text class="empty-text" :style="[emptyTextStyle]">{{ emptyText }}</text>
</view>
</view>
<view class="list-content"><slot></slot></view>
<view class="pull-up-wrap" v-if="showPullUp">
<slot name="pullup" v-if="$slots.pullup"></slot>
<view class="load-view" v-else>
<view
class="pull-up-animation"
v-if="loading"
:style="[pullUpAnimationStyle]"
></view>
<text class="pull-up-text" :style="[pullUpTextStyle]">{{
loadStateText
}}</text>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import images from "./images.js";
export default {
name: "scroll-list",
props: {
//
option: {
type: Object,
default: () => ({}),
},
},
data() {
return {
defaultOption: {
page: 1, //
size: 15, //
auto: true, //
height: null, //
disabled: false, //
background: "", //
emptyImage: "", //
offsetBottom: 0, //
pullDownSpeed: 0.5, //
lowerThreshold: 40, //
refresherThreshold: 80, //
refreshDelayed: 800, //
refreshFinishDelayed: 800, //
safeArea: false, //
emptyTextColor: "#82848a", //
loadTextColor: "#82848a", //
loadIconColor: "#82848a", //
refresherTextColor: "#82848a", //
refresherIconColor: "#82848a", //
emptyText: "暂无列表~", //
loadingText: "正在加载中~", //
loadFailText: "加载失败啦~", //
noMoreText: "没有更多啦~", //
refreshingText: "正在刷新~", //
refreshFailText: "刷新失败~", //
refreshSuccessText: "刷新成功~", //
pulldownText: "下拉刷新~", //
pulldownFinishText: "松开刷新~", //
},
images, //
elClass: "", // class
windowInfo: {}, //
scrollTop: 0, //
scrollViewTop: -1, //
scrollViewHeight: 0, //
currentPage: 1, //
currentSize: 15, //
currentScrollTop: 0, //
emptyText: "暂无列表~",
loadStateText: "正在加载中~", //
refreshStateText: "下拉刷新~", //
loadDisabled: false, //
loading: false, //
refreshing: false, //
refreshFinish: false, //
pulldowning: false, //
pullDownHeight: 0, //
showEmpty: false, //
showPullUp: false, //
showPullDown: false, //
};
},
methods: {
//
handleInit() {
//
this.defaultOption = Object.assign(this.defaultOption, this.option);
this.showEmpty = !this.defaultOption.auto;
this.currentPage = this.defaultOption.page;
this.currentSize = this.defaultOption.size;
this.emptyText = this.defaultOption.emptyText;
this.loadStateText = this.defaultOption.loadingText;
this.refreshStateText = this.defaultOption.pulldownText;
//
this.queryRect("." + this.elClass).then((rect) => {
//
this.scrollViewTop = rect.top;
//
if (this.defaultOption.auto) this.load();
});
},
//
load() {
if (this.defaultOption.disabled || this.loading || this.loadDisabled) return;
//
this.loading = true;
//
this.loadStateText = this.defaultOption.loadingText;
//
this.showPullUp = true;
//
let paging = { page: this.currentPage, size: this.currentSize };
// load
this.$emit("load", paging);
},
//
loadSuccess(data = {}) {
//
const { list, total } = data;
//
if (Array.isArray(list)) {
//
if (list.length) {
//
if (list.length >= total) {
//
this.loadDisabled = true;
//
this.loadStateText = this.defaultOption.noMoreText;
} else {
//
this.loadDisabled = false;
//
this.currentPage++;
//
this.loadStateText = this.defaultOption.loadingText;
//
this.loadCompute();
}
//
this.showPullUp = true;
//
this.showEmpty = false;
} else {
//
this.loadDisabled = true;
//
this.showPullUp = false;
//
this.showPullUp = false;
//
this.showEmpty = true;
}
//
this.loading = false;
//
this.$emit("loadSuccess", list);
} else {
//
this.loadFail();
console.error("the list must be a array");
}
},
//
loadFail() {
//
this.loading = false;
//
this.showEmpty = false;
//
this.showPullUp = true;
//
this.loadStateText = this.defaultOption.loadFailText;
//
this.$emit("loadFail");
},
//
refresh() {
//
if (this.pullDownHeight == this.defaultOption.refresherThreshold) {
//
this.loading = false;
//
this.showPullUp = false;
} else {
//
this.loading = true;
//
this.showEmpty = false;
//
this.showPullUp = true;
//
this.loadStateText = this.defaultOption.refreshingText;
}
//
this.refreshFinish = false;
//
this.refreshing = true;
//
this.refreshStateText = this.defaultOption.refreshingText;
//
this.currentPage = 1;
this.currentSize = this.defaultOption.size;
let paging = { page: this.currentPage, size: this.currentSize };
// refresh
setTimeout(() => {
this.$emit("refresh", paging);
}, this.defaultOption.refreshDelayed);
},
//
refreshSuccess(data) {
//
const { list, total } = data;
//
if (Array.isArray(list)) {
//
if (list.length) {
//
if (list.length >= total) {
//
this.loadDisabled = true;
//
this.loadStateText = this.defaultOption.noMoreText;
} else {
//
this.currentPage++;
//
this.loadDisabled = false;
//
this.loadStateText = this.defaultOption.loadingText;
//
this.defaultOption.auto = true;
//
this.loadCompute();
}
//
this.showEmpty = false;
//
this.showPullUp = true;
} else {
//
this.loadDisabled = true;
//
this.showPullUp = false;
//
this.showEmpty = true;
//
this.loadStateText = this.defaultOption.noMoreText;
}
//
this.loading = false;
//
this.refreshStateText = this.defaultOption.refreshSuccessText;
//
this.refreshing = false;
//
this.pulldowning = false;
//
this.$emit("refreshSuccess", list);
setTimeout(() => {
//
this.refreshFinish = true;
//
this.pullDownHeight = 0;
//
this.showPullDown = false;
this.$emit("refreshSuccess");
}, this.defaultOption.refreshFinishDelayed);
} else {
//
this.refreshFail();
console.error("the list must be a array");
}
},
//
refreshFail() {
//
this.loadStateText = this.defaultOption.refreshFailText;
//
this.refreshStateText = this.defaultOption.refreshFailText;
//
this.loading = false;
//
this.showPullUp = true;
//
this.refreshing = false;
//
this.pulldowning = false;
//
setTimeout(() => {
//
this.refreshFinish = true;
//
this.pullDownHeight = 0;
//
this.showPullDown = false;
//
this.$emit("refreshError");
}, this.defaultOption.refreshFinishDelayed);
},
//
loadCompute() {
//
if (this.defaultOption.auto) {
//
setTimeout(() => {
this.$nextTick(() => {
this.queryRect(".list-content").then((rect) => {
if (rect.height <= this.scrollViewHeight) {
this.load();
}
});
});
}, 100);
}
},
//
handleScrolltolower(e) {
if (this.loadDisabled) return;
this.$emit("scrolltolower", e);
this.load();
},
//
handleScroll(event) {
this.currentScrollTop = event.detail.scrollTop;
this.$emit("scroll", event.detail);
},
//
handleTouchStart(event) {
if (this.defaultOption.disabled) return;
this.currentTouchStartY = event.touches[0].clientY;
this.$emit("touchStart", event);
},
//
handleTouchMove(event) {
if (this.defaultOption.disabled || this.currentScrollTop) return;
if (event.touches[0].clientY >= this.currentTouchStartY) {
this.pulldowning = true;
this.showPullDown = true;
let pullDownDistance =
(event.touches[0].clientY - this.currentTouchStartY) *
this.defaultOption.pullDownSpeed;
this.pullDownHeight =
pullDownDistance > this.defaultOption.refresherThreshold
? this.defaultOption.refresherThreshold
: pullDownDistance;
this.refreshStateText =
this.pullDownHeight >= this.defaultOption.refresherThreshold
? this.defaultOption.pulldownFinishText
: this.defaultOption.pulldownText;
this.$emit("touchMove", event);
}
},
//
handleTouchEnd(event) {
if (this.defaultOption.disabled) return;
//
if (this.pullDownHeight < this.defaultOption.refresherThreshold) {
//
this.pulldowning = false;
//
this.pullDownHeight = 0;
//
this.showPullDown = false;
//
this.$emit("refreshStop");
} else {
this.refresh();
}
//
this.$emit("touchEnd", event);
},
//
updateScrollView() {
if (this.defaultOption.height) {
this.scrollViewHeight = uni.upx2px(this.defaultOption.height);
} else {
this.scrollViewHeight = this.windowInfo.windowHeight - this.scrollViewTop;
}
this.scrollViewObserve();
},
//
listContentObserve() {
this.disconnectObserve("_listContentObserve");
const listContentObserve = this.createIntersectionObserver({
thresholds: [0, 0.5, 1],
});
listContentObserve.relativeToViewport({
// #ifdef H5
top: -(this.windowInfo.windowTop + rect.top),
// #endif
// #ifndef H5
top: -rect.top,
// #endif
});
},
//
scrollViewObserve() {
this.disconnectObserve("_scrollViewObserve");
this.$nextTick(() => {
this.queryRect("." + this.elClass).then((rect) => {
const scrollViewObserve = this.createIntersectionObserver({
thresholds: [0, 0.5, 1],
});
scrollViewObserve.relativeToViewport({
// #ifdef H5
top: -(this.windowInfo.windowTop + rect.top),
// #endif
// #ifndef H5
top: -rect.top,
// #endif
});
scrollViewObserve.observe("." + this.elClass, (position) => {
// #ifdef H5
this.scrollViewTop =
position.boundingClientRect.top - this.windowInfo.windowTop;
// #endif
// #ifndef H5
this.scrollViewTop = position.boundingClientRect.top;
// #endif
});
this._scrollViewObserve = scrollViewObserve;
});
});
},
//
disconnectObserve(observerName) {
const observer = this[observerName];
observer && observer.disconnect();
},
// dom
queryRect(selector, all) {
return new Promise((resolve) => {
uni
.createSelectorQuery()
.in(this)
[all ? "selectAll" : "select"](selector)
.boundingClientRect((rect) => {
if (all && Array.isArray(rect) && rect.length) {
resolve(rect);
}
if (!all && rect) {
resolve(rect);
}
})
.exec();
});
},
// 16RGB
hexToRgb(hex) {
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, (m, r, g, b) => {
return r + r + g + g + b + b;
});
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
}
: null;
},
},
computed: {
scrollListWrapStyle() {
return {
background: this.defaultOption.background,
};
},
//
listWrapStyle() {
let style = {};
const { offsetBottom } = this.defaultOption;
style.height = this.scrollViewHeight - uni.upx2px(offsetBottom) + "px";
if (this.defaultOption.safeArea)
style.paddingBottom = "env(safe-area-inset-bottom) !important";
return style;
},
//
scrollContentStyle() {
const style = {};
const { pullDownHeight, pulldowning, showPullDown } = this;
style.transform = showPullDown
? `translateY(${pullDownHeight}px)`
: `translateY(0px)`;
style.transition = pulldowning
? `transform 100ms ease-out`
: `transform 200ms cubic-bezier(0.19,1.64,0.42,0.72)`;
return style;
},
//
refreshViewStyle() {
const style = {};
const { showPullDown } = this;
style.opacity = showPullDown ? 1 : 0;
return style;
},
//
pullDownAnimationStyle() {
const style = {};
const { refresherIconColor, refresherThreshold } = this.defaultOption;
const { refreshing, pullDownHeight } = this;
const { r, g, b } = this.hexToRgb(refresherIconColor);
const rate = pullDownHeight / refresherThreshold;
style.borderColor = `rgba(${r},${g},${b},0.2)`;
style.borderTopColor = refresherIconColor;
if (!refreshing) {
style.transform = `rotate(${360 * rate}deg)`;
style.transition = "transform 100ms linear";
}
return style;
},
pullDownTextStyle() {
const style = {};
const { refresherTextColor } = this.defaultOption;
style.color = refresherTextColor;
return style;
},
//
pullUpAnimationStyle() {
const style = {};
const { loadIconColor } = this.defaultOption;
const { r, g, b } = this.hexToRgb(loadIconColor);
style.borderColor = `rgba(${r},${g},${b},0.2)`;
style.borderTopColor = loadIconColor;
return style;
},
//
pullUpTextStyle() {
const style = {};
const { loadTextColor } = this.defaultOption;
style.color = loadTextColor;
return style;
},
//
emptyTextStyle() {
const style = {};
const { emptyTextColor } = this.defaultOption;
style.color = emptyTextColor;
return style;
},
},
watch: {
scrollViewTop(val) {
this.updateScrollView();
},
},
created() {
this.elClass = "scroll-view-" + this._uid;
this.windowInfo = uni.getSystemInfoSync();
},
mounted() {
this.handleInit();
},
};
</script>
<style scoped lang="scss">
.scroll-list-wrap {
box-sizing: border-box;
.scroll-view {
position: relative;
.scroll-content {
height: 100%;
display: flex;
// will-change: transform;
flex-direction: column;
.pull-down-wrap {
left: 0;
width: 100%;
display: flex;
padding: 30rpx 0;
position: absolute;
align-items: flex-end;
justify-content: center;
transform: translateY(-100%);
.refresh-view {
display: flex;
justify-content: center;
.pull-down-animation {
width: 32rpx;
height: 32rpx;
border-width: 4rpx;
border-style: solid;
border-radius: 50%;
&.refreshing {
animation: spin 0.5s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
}
.pull-down-text {
margin-left: 10rpx;
}
}
}
.empty-wrap {
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
position: absolute;
align-items: center;
flex-direction: column;
.empty-view {
// margin: auto;
display: flex;
align-items: center;
margin-bottom: 400rpx;
flex-direction: column;
.empty-image {
width: 600rpx;
height: 600rpx;
}
.empty-text {
color: #606266;
margin-top: 20rpx;
}
}
}
.pull-up-wrap {
display: flex;
align-items: center;
justify-content: center;
.load-view {
padding: 20rpx 0;
display: flex;
align-items: center;
justify-content: center;
.pull-up-animation {
width: 32rpx;
height: 32rpx;
border-width: 4rpx;
border-style: solid;
border-radius: 50%;
animation: spin 0.5s linear infinite;
}
.pull-up-text {
margin-left: 10rpx;
}
}
}
}
}
}
</style>

110
enums/index.js

@ -0,0 +1,110 @@
import env from '@/env/index.js'
const urlEnv = env === 'production' ? '' : `-${env}`
export const XAPPID = '503258978847966413'
// 统一支付接口
export const PAY_URL = `https://api-client-psc${urlEnv}.qniao.cn/payment-settlement-center/pay`
/**
* 上传地址
*/
export const uploadUrl = {
image: `https://api-client-yyt${urlEnv}.qniao.cn/yyt-uec/file-uploading/upload/image`,
file: `https://api-client-yyt${urlEnv}.qniao.cn/yyt-uec/file-uploading/upload/file`,
// video: `https://api-client-yyt${urlEnv}.qniao.cn/yyt-uec/file-uploading/upload/file?type=mp4`
video: `https://api-client-yyt${urlEnv}.qniao.cn/yyt-uec/file-uploading/upload/video/file?type=mp4`,
printFile: `https://api-ops-yyt${urlEnv}.qniao.cn/wukong-fast-print/printing-file/upload/file`
}
/**
* 文件类型 图片1视频2
*/
export const fileType = {
IMG: 1,
VIDEO: 2
}
/**
* 收货地址是否默认 1:默认 0:非默认
*/
export const addressType = {
DEFAULT: true,
NOT_DEFAULT: false
}
/**
* 支付方式 1:微信支付 2:月结支付 4:飞算支付
*/
export const paymentMethodEnum = {
WECHAT_PAY: 1,
MONTHLY_PAY: 2,
FLY_PAY: 4
}
export const paymentMethodMap = {
[paymentMethodEnum.WECHAT_PAY]: '微信支付',
[paymentMethodEnum.MONTHLY_PAY]: '月结支付',
[paymentMethodEnum.FLY_PAY]: '飞算支付'
}
/**
* 订单状态 0:全部 40001:待付款 40002:待确认 40003:生产中 40004:运输中 40005:已完成 40009:待揽收 40006:已取消 40007:退款中
*/
export const orderStatus = {
ALL: 0,
WAIT_PAY: 40001,
WAIT_CONFIRM: 40002,
PRINTING: 40003,
TRANSPORTING: 40004,
COMPLETED: 40005,
WAIT_COLLECT: 40009,
CANCELLED: 40006,
REFUND: 40007,
REFUNDED: 40008
}
/**
* 订单全部状态 40001:待付款 40002:待确认 40003:生产中 40004:运输中 40005:已完成 40007:退款中 40008:已退款 40009:待揽收 40006:已取消
*/
export const orderStatusMap = {
40001: '待付款',
40002: '待确认',
40003: '生产中',
40004: '运输中',
40005: '已完成',
40007: '退款中',
40008: '已退款',
40006: '已取消',
40009: '待发货'
}
/**
* 物料状态 20003:已发货 20004:已完成 20005:已取消
*/
export const suppliesOrderItemStatus = {
TRANSPORTING: 20003,
COMPLETED: 20004,
CANCEL: 20005
}
/**
* 解决oss图片缓存问题
*/
let images = {
'service-bg': `https://qncloud.oss-cn-shenzhen.aliyuncs.com/wukong-printer-wx/service-bg.png`
}
function splicingTimestamps(obj) {
for (let key in obj) {
obj[key] = obj[key] + `?timeStamp=${Date.now()}`
}
return obj
}
export const imgStamp = Object.freeze(splicingTimestamps(images))
/**
* 全局事件key
*/
export const cacheKey = {
ORDER_PARAM: 'orderParam' // 订单列表查询参数参数
}

8
env/index.js

@ -0,0 +1,8 @@
/**
* @description 唯一环境变量
*/
const env = 'test'
// const env = 'dev'
// const env = 'production'
export default env

12
jsconfig.json

@ -0,0 +1,12 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"],
"/*": ["./*"]
},
"target": "ES6"
},
"include": ["./**/*"],
"exclude": ["./uni_modules"]
}

29
main.js

@ -0,0 +1,29 @@
import App from './App'
import store from './store'
import Vue from 'vue'
import { Monitor } from '@/utils/monitor/index'
import { XAPPID } from '@/enums/index.js'
import env from '@/env/index.js'
import vueWxRouter from '@/utils/vueWxRouter'
const urlEnv = env === 'production' ? '' : `-${env}`
// # ifdef MP-WEIXIN
// const monitor = new Monitor({
// url: `https://api-client-yyt${urlEnv}.qniao.cn/wukong-fast-print/vue/error/message`,
// timeout: 5000,
// method: 'POST',
// env,
// header: { 'X-APP-ID': XAPPID }
// })
// monitor.init()
// # endif
Vue.config.productionTip = false
// Vue.prototype.$store = store
App.mpType = 'app'
Vue.use(vueWxRouter)
const app = new Vue({
...App,
store
})
app.$mount()

192
manifest.json

@ -0,0 +1,192 @@
{
"name" : "飞鸟快印",
"appid" : "__UNI__EBBA73E",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : 100,
"transformPx" : false,
"networkTimeout" : {
"request" : 6000
},
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"compatible" : {
"ignoreVersion" : true
},
/* */
"modules" : {
"iBeacon" : {},
"Share" : {},
"Payment" : {}
},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>"
],
"abiFilters" : [ "armeabi-v7a", "x86" ]
},
/* ios */
"ios" : {
"privacyDescription" : {
"NSPhotoLibraryUsageDescription" : "该应用需要读取你的相册,以便为你编辑信息",
"NSPhotoLibraryAddUsageDescription" : "该应用需要读取你的相册,以便为你保存信息",
"NSCameraUsageDescription" : "该应用需要使用你的摄像头,以便为你编辑信息",
"NSLocationWhenInUseUsageDescription" : "该应用需要你的地理位置,以便为你提供当前位置附近印包厂信息",
"NSLocationAlwaysUsageDescription" : "该应用需要你的地理位置,以便为你提供当前位置附近印包厂信息",
"NSLocationAlwaysAndWhenInUseUsageDescription" : "该应用需要你的地理位置,以便为你提供当前位置附近印包厂信息"
},
"idfa" : false
},
/* SDK */
"sdkConfigs" : {
"maps" : {
"amap" : {
"appkey_ios" : "0182ee2a9fdd5fd3ef6a8bd5a2f98325",
"appkey_android" : "877848546f7f3717101a17c33e1d4df3"
}
},
"payment" : {
"weixin" : {
"__platform__" : [ "ios", "android" ],
"appid" : "wx6c66084e2de41575",
"UniversalLinks" : "https://apple-app-yyt-printpackage.qniao.cn/"
}
},
"ad" : {},
"geolocation" : {
"amap" : {
"__platform__" : [ "ios", "android" ],
"appkey_ios" : "0182ee2a9fdd5fd3ef6a8bd5a2f98325",
"appkey_android" : "877848546f7f3717101a17c33e1d4df3"
}
},
"share" : {
"weixin" : {
"appid" : "wx6c66084e2de41575",
"UniversalLinks" : "https://apple-app-yyt-printpackage.qniao.cn/"
}
},
"push" : {
"unipush" : {}
}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
},
"splashscreen" : {
"androidStyle" : "default",
"iosStyle" : "common"
}
},
"uniStatistics" : {
"enable" : true
},
"nativePlugins" : {}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx74a65d2467a4d8ab",
"setting" : {
"urlCheck" : false,
"minified" : true
},
"usingComponents" : true,
"plugins" : {
"materialPlugin" : {
"version" : "1.0.5",
"provider" : "wx4d2deeab3aed6e5a"
},
"live-player-plugin" : {
"version" : "1.3.5",
"provider" : "wx2b03c6e691cd7370"
}
},
"permission" : {},
"requiredPrivateInfos" : [ "chooseAddress" ],
"lazyCodeLoading" : "requiredComponents"
},
"navigateToMiniProgramAppIDList" : [ "wx654ce96a7324e76f" ],
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2",
"h5" : {
"router" : {
"mode" : "history"
},
"devServer" : {
"port" : 9090
}
}
}

12
package-lock.json

@ -0,0 +1,12 @@
{
"name": "canvas 生成海报",
"version": "3.2.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "canvas 生成海报",
"version": "3.2.2"
}
}
}

13
package.json

@ -0,0 +1,13 @@
{
"id": "hch-poster",
"name": "canvas 生成海报",
"version": "3.2.2",
"description": "分享弹窗,生成海报并支持保存,支持多端(H5,微信小程序,支付宝小程序,百度小程序,字节跳动小程序,QQ小程序)",
"keywords": [
"分享",
"海报",
"自定义图片",
"小程序码",
"商城商品分享海报。"
]
}

103
pages.json

@ -0,0 +1,103 @@
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/index",
"style": {
"navigationBarTitleText": "个人中心",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/address/index",
"style": {
"navigationBarTitleText": "我的地址",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/pay/index",
"style": {
"navigationBarTitleText": "支付",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/pay-result/index",
"style": {
"navigationBarTitleText": "支付结果",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/h5-view/index",
"style": {
"navigationBarTitleText": "统一的H5落地页",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/h5-page/index",
"style": {
"navigationBarTitleText": "飞鸟快印",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "登陆",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/page-view/index",
"style": {
"navigationBarTitleText": "飞鸟快印",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"backgroundColorTop": "#FFFFFF"
},
"tabBar": {
"color": "#888",
"selectedColor": "#007AFF",
"borderStyle": "white",
"backgroundColor": "#f9f9f9",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "static/imgs/tabbar/index-gray.png",
"selectedIconPath": "static/imgs/tabbar/index-blue.png",
"text": "首页"
},
{
"pagePath": "pages/mine/index",
"iconPath": "static/imgs/tabbar/mine-gray.png",
"selectedIconPath": "static/imgs/tabbar/mine-blue.png",
"text": "我的"
}
]
}
}

313
pages/address/index.vue

@ -0,0 +1,313 @@
<template>
<view class="content">
<uni-nav-bar left-icon="back" @clickLeft="back" statusBar fixed title="我的地址"></uni-nav-bar>
<view class="flex-col group_5">
<view class="flex-col list" v-if="list.length > 0">
<view class="list-item flex-col" :key="item.id" v-for="item in list">
<view class="top-group flex-col" @click="selectAddress(item)">
<view class="justify-between">
<text class="text_4">{{ item.receiver }} {{ item.receiverMobile }}</text>
<view class="select-button" v-show="showSelectedTip">选择</view>
</view>
<text class="text_6">{{ item.provinceName || '' }}{{ item.cityName || '' }}{{ item.districtName || '' }}{{ item.detail || '' }}</text>
</view>
<view class="bottom-group justify-between">
<view class="left-group flex-row view_4" :class="{ selected: item.isDefault }" @click="setDefault(item)">
<image class="icon" :src="item.isDefault ? '/static/imgs/general/selected-icon.png' : '/static/imgs/general/select-icon.png'"></image>
<text class="text_8">设为默认</text>
</view>
<text class="text_10 text_11" @click="remove(item)">删除</text>
</view>
</view>
</view>
<image v-else :src="imgStamp['empty-file']" class="image_6" />
<view class="flex-col items-center fixed" @click="getAuth">
<text>导入微信收货地址</text>
</view>
</view>
</view>
</template>
<script>
import { go2, back, setCache } from '@/utils/hook.js'
import { getAddressList, changeAddress, deleteAddress } from '@/apis/addressApi'
import { addressType, imgStamp, cacheKey } from '@/enums/index'
export default {
data() {
return {
prePage: 'mine',
list: [],
imgStamp: Object.freeze(imgStamp),
hasAuth: false //
}
},
onShow() {
getAddressList().then((res) => {
this.list = res
})
},
onLoad(options) {
if (options.from) {
this.prePage = options.from
}
uni.getSetting({
success: (res) => {
if (res.authSetting['scope.address']) {
console.log('已授权')
this.hasAuth = true
}
},
fail: (err) => {
console.log(err)
}
})
},
computed: {
showSelectedTip() {
return ['print-pay'].includes(this.prePage)
}
},
methods: {
go2,
back,
selectAddress(item) {
let reg_tel = /^(13\d|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18\d|19[0-35-9])\d{8}$/
if (!reg_tel.test(item.receiverMobile)) {
uni.showModal({
content: '手机号码格式错误',
title: '提示',
duration: 1000
})
return
}
if (this.prePage == 'print-pay') {
setCache(cacheKey.SELECT_ADDRESS, item)
back()
}
},
setDefault(item) {
if (item.isDefault) {
return
}
changeAddress({ ...item, isDefault: addressType.DEFAULT }).then(() => {
getAddressList().then((res) => {
this.list = res
})
})
},
//
getAuth() {
uni.authorize({
scope: 'scope.address',
success: () => {
this.hasAuth = true
this.importAddress()
},
fail: () => {
this.hasAuth = false
uni.showModal({
title: '提示',
content: '您未授权微信地址,无法使用该功能。是否打开授权?',
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: (result) => {
if (result.authSetting['scope.address']) {
this.hasAuth = true
}
}
})
}
}
})
}
})
},
//
importAddress() {
uni.chooseAddress({
success: (res) => {
if (!res.userName || res.userName.trim() == '') {
uni.showModal({
content: '导入的地址收货人名称不能为空',
title: '提示'
})
return
}
if (!res.telNumber || res.telNumber.trim() == '') {
uni.showModal({
content: '导入的地址收货人电话不能为空',
title: '提示'
})
return
}
let reg_tel = /^(13\d|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18\d|19[0-35-9])\d{8}$/
if (!reg_tel.test(res.telNumber)) {
uni.showModal({
content: '手机号码格式错误',
title: '提示',
duration: 1000
})
return
}
let address = {
cityName: res.cityName,
detail: res.detailInfo,
districtName: res.countyName,
isDefault: addressType.DEFAULT,
provinceName: res.provinceName,
receiver: res.userName,
receiverMobile: res.telNumber,
postalCode: res.postalCode
}
changeAddress(address).then(() => {
getAddressList().then((res) => {
this.list = res
if (this.list.length == 1 && this.prePage == 'print-pay') {
setCache(cacheKey.SELECT_ADDRESS, this.list[0])
back()
}
})
})
},
fail: (err) => {
console.error('err', err)
uni.showModal({
title: '提示',
content: '导入地址失败,请同意授权或更新微信后再试'
})
}
})
},
remove(item) {
uni.showModal({
title: '提示',
content: '确定要删除该地址吗?',
success: (res) => {
if (res.confirm) {
deleteAddress({ id: item.id }).then(() => {
const addressObj = {
id: null,
receiver: '',
receiverMobile: '',
provinceName: '',
cityName: '',
districtName: '',
streetName: '',
detail: ''
}
setCache(cacheKey.SELECT_ADDRESS, addressObj)
getAddressList().then((res) => {
this.list = res
})
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
width: 750rpx;
}
.group_5 {
padding: 0 0 84rpx;
height: 100vh;
overflow-y: auto;
position: relative;
.image_6 {
position: absolute;
top: 20%;
left: 70rpx;
right: 70rpx;
width: 609rpx;
height: 453rpx;
}
.list {
margin: 0 32rpx;
.list-item {
padding: 0 24rpx;
background-color: rgb(255, 255, 255);
border-radius: 16rpx;
margin-top: 20rpx;
.top-group {
padding: 27rpx 0 29rpx;
.text_4 {
color: rgb(51, 51, 51);
font-size: 30rpx;
font-weight: 500;
line-height: 42rpx;
white-space: nowrap;
}
.select-button {
width: 100rpx;
height: 42rpx;
padding: 0rpx 8rpx;
text-align: center;
color: white;
font-size: 26rpx;
line-height: 42rpx;
white-space: nowrap;
background-color: #007aff;
border-radius: 6rpx;
}
.text_6 {
margin-right: 31rpx;
margin-top: 16rpx;
color: rgb(51, 51, 51);
font-size: 28rpx;
line-height: 40rpx;
text-align: left;
}
}
.bottom-group {
padding: 20rpx 0;
color: rgb(136, 136, 136);
font-size: 28rpx;
line-height: 40rpx;
white-space: nowrap;
border-top: solid 2rpx rgb(216, 216, 216);
.icon {
margin: 4rpx 0;
border-radius: 50%;
width: 32rpx;
height: 32rpx;
}
.left-group {
font-size: 28rpx;
line-height: 40rpx;
white-space: nowrap;
.text_8 {
margin-left: 12rpx;
}
}
.selected {
color: rgb(0, 122, 255);
}
.text_10 {
color: rgb(136, 136, 136);
font-size: 28rpx;
line-height: 40rpx;
white-space: nowrap;
}
}
}
}
.fixed {
padding: 20rpx 0;
color: rgb(255, 255, 255);
font-size: 32rpx;
line-height: 45rpx;
white-space: nowrap;
background-color: rgb(0, 122, 255);
border-radius: 20rpx;
position: fixed;
left: 32rpx;
right: 32rpx;
bottom: 90rpx;
}
}
</style>

41
pages/h5-page/index.vue

@ -0,0 +1,41 @@
<template>
<view class="content">
<uni-nav-bar
left-icon="back"
@clickLeft="back"
statusBar
fixed
:title="title"
></uni-nav-bar>
<web-view :src="url"></web-view>
</view>
</template>
<script>
import { go2, back } from "@/utils/hook.js";
export default {
data() {
return {
title: "",
url: "",
};
},
onLoad(options) {
this.title = options.title;
this.url = options.url;
},
methods: {
go2,
back,
},
};
</script>
<style lang="scss" scoped>
.content {
width: 750rpx;
}
.img {
width: 750rpx;
}
</style>

35
pages/h5-view/index.vue

@ -0,0 +1,35 @@
<template>
<view class="content">
<uni-nav-bar left-icon="back" @clickLeft="back" statusBar fixed :title="title"></uni-nav-bar>
<image :show-menu-by-longpress="true" :src="url" class="img" mode="widthFix"></image>
</view>
</template>
<script>
import { go2, back } from '@/utils/hook.js'
export default {
data() {
return {
title: '',
url: ''
}
},
onLoad(options) {
this.title = options.title
this.url = options.url
},
methods: {
go2,
back
}
}
</script>
<style lang="scss" scoped>
.content {
width: 750rpx;
}
.img {
width: 750rpx;
}
</style>

25
pages/index/index.vue

@ -0,0 +1,25 @@
<template>
<view class="content">
<uni-nav-bar left-icon="back" @clickLeft="back" statusBar fixed title="首页"></uni-nav-bar>
home
</view>
</template>
<script>
import { go2, back } from '@/utils/hook.js'
export default {
data() {
return {}
},
methods: {
go2,
back
}
}
</script>
<style lang="scss" scoped>
.content {
width: 750rpx;
}
</style>

192
pages/login/index.vue

@ -0,0 +1,192 @@
<template>
<view class="content">
<uni-nav-bar left-icon="back" @clickLeft="back" statusBar fixed title="飞鸟快印"></uni-nav-bar>
<view class="flex-col group_5">
<view class="group_6">
<view class="section_3"><!--*--></view>
<view class="justify-center group_7">
<image src="/static/imgs/general/logo-icon.png" class="image_6" />
<text class="text_4">飞鸟快印</text>
</view>
</view>
<view class="flex-col group_8">
<text class="text_5">手机里的打印店</text>
<view class="justify-center">
<button class="avatar-wrapper" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<image class="avatar" :src="avatarUrl"></image>
</button>
</view>
<view class="nick-form">
<view style="width: 100rpx">昵称:</view>
<input type="nickname" class="weui-input" placeholder="请输入昵称" v-model="nickname" />
</view>
<view class="flex-col items-center button" @tap="signIn"><text class="text_6">注册账号</text></view>
</view>
<view class="section_4"><!--*--></view>
</view>
</view>
</template>
<script>
import { go2, back } from '@/utils/hook.js'
import { changeUserInfo, uploadAvatar } from '@/apis/commonApi'
const defaultAvatarUrl = 'https://qncloud.oss-cn-shenzhen.aliyuncs.com/wukong-printer-wx/default-avatar-add.png'
export default {
data() {
return {
params: {},
target: '',
avatarUrl: defaultAvatarUrl,
nickname: ''
}
},
onLoad(options) {
this.target = options.target
this.params = JSON.parse(options.data || '{}')
},
methods: {
go2,
back,
signIn() {
if (this.avatarUrl == defaultAvatarUrl || !this.avatarUrl) {
uni.showToast({
title: '请选择头像',
icon: 'none'
})
return
}
if (!this.nickname || !this.nickname.trim()) {
uni.showToast({
title: '请输入昵称',
icon: 'none'
})
return
}
uploadAvatar(this.avatarUrl).then((res) => {
if (res) {
res = JSON.parse(res)
}
if (res.data) {
changeUserInfo({ avatar: res.data, nickname: this.nickname }).then(() => {
//
let changeMap = [
{ key: 'avatar', value: res.data },
{ key: 'name', value: this.nickname }
]
this.$store.commit('changeUserInfo', changeMap)
this.nextPage()
})
}
})
},
onChooseAvatar(e) {
const { avatarUrl } = e.detail
this.avatarUrl = avatarUrl
},
nextPage() {
go2(this.target, this.params, true)
}
}
}
</script>
<style lang="scss" scoped>
.content {
width: 750rpx;
}
.group_5 {
padding: 42rpx 0 316rpx;
flex: 1 1 auto;
overflow-y: auto;
overflow-x: hidden;
.group_6 {
width: 750rpx;
.section_3 {
background-image: linear-gradient(149.4deg, #007aff26 0%, #007aff26 2.73%, #ffffff26 98.65%, #ffffff26 100%);
border-radius: 0 50% 50% 0;
width: 288rpx;
height: 288rpx;
position: absolute;
transform: translateX(-50%);
}
.group_7 {
margin-top: 90rpx;
width: 750rpx;
.image_6 {
margin: 10rpx 0 9rpx;
flex-shrink: 0;
width: 75rpx;
height: 75rpx;
}
.text_4 {
margin-left: 21rpx;
color: #000000;
font-size: 80rpx;
font-family: '.AppleSystemUIFont';
line-height: 94rpx;
}
}
}
.group_8 {
margin: 28rpx 0 0;
.text_5 {
align-self: center;
color: #000000;
font-size: 30rpx;
font-family: 'PingFangSC-Regular';
line-height: 42rpx;
letter-spacing: 34rpx;
margin-left: 34rpx;
}
.button {
padding: 23rpx 0 20rpx;
margin: 120rpx 32rpx 0;
background-color: #28c445;
border-radius: 44rpx;
.text_6 {
color: #ffffff;
font-size: 32rpx;
font-family: 'PingFangSC-Medium';
font-weight: 500;
line-height: 45rpx;
}
}
}
.section_4 {
margin-left: 562rpx;
margin-top: 282rpx;
align-self: flex-start;
background-image: linear-gradient(149.4deg, #007aff26 0%, #007aff26 2.73%, #ffffff26 98.65%, #ffffff26 100%);
border-radius: 50%;
width: 288rpx;
height: 288rpx;
}
}
.avatar-wrapper {
width: 150rpx;
height: 150rpx;
margin-top: 140rpx;
border-radius: 50%;
overflow: hidden;
padding: 0;
.avatar {
width: 150rpx;
height: 150rpx;
}
}
.weui-input {
width: 400rpx;
height: 80rpx;
}
.nick-form {
margin-top: 32rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
width: 750rpx;
border-top: 1px solid #e5e5e5;
border-bottom: 1px solid #e5e5e5;
}
</style>

25
pages/mine/index.vue

@ -0,0 +1,25 @@
<template>
<view class="content">
<uni-nav-bar left-icon="back" @clickLeft="back" statusBar fixed title="个人中心"></uni-nav-bar>
mine
</view>
</template>
<script>
import { go2, back } from '@/utils/hook.js'
export default {
data() {
return {}
},
methods: {
go2,
back
}
}
</script>
<style lang="scss" scoped>
.content {
width: 750rpx;
}
</style>

87
pages/page-view/index.vue

@ -0,0 +1,87 @@
<template>
<view>
<web-view :src="url"></web-view>
</view>
</template>
<script>
import { go2, back } from "@/utils/hook.js";
import { makeSocket } from "@/utils/index.js";
export default {
data() {
return {
url: "",
socket: null,
params: null,
socketFlag: false,
};
},
onLoad(option) {
if (option) {
this.url = decodeURIComponent(option.url);
this.params = option.params ? JSON.parse(option.params) : "";
// socket
this.socketFlag = option.socketFlag || false;
} else {
uni.showToast({
title: "参数错误",
icon: "none",
complete: () => {
setTimeout(() => {
back();
}, 1000);
},
});
}
},
onShow() {
if (this.socketFlag) {
this.initSocket();
}
},
onHide() {
console.log("onHide");
this.destroySocket();
},
onUnload() {
console.log("onUnload");
this.destroySocket();
},
methods: {
initSocket() {
makeSocket({ pageInfo: "page-view", retry: true }).then((res) => {
this.destroySocket();
this.socket = res;
this.socket.onMessage(this.getMessage);
});
},
/**
* @param {Object} data {data:{},type:''}
*/
getMessage(data) {
//
if (data.type === "guaranteeSuccess") {
go2("fs-credit", { ...this.params }, true);
}
//
if (data.type == "ybkClientTCSignSuccess") {
go2("order-detail", { orderId: data.data.orderId }, true);
}
//
if (data.type == "signSuccess") {
// go2('order-detail', { id: data.orderId }, true)
}
//
if (data.type == "certificatedSuccess") {
go2("mine");
}
},
destroySocket() {
if (this.socket) {
this.socket.close();
this.socket = null;
}
},
},
};
</script>

114
pages/pay-result/index.vue

@ -0,0 +1,114 @@
<template>
<view class="content">
<uni-nav-bar statusBar fixed title="支付结果"></uni-nav-bar>
<view class="flex-col group_5">
<view class="flex-col section_3">
<view class="flex-col items-center">
<image src="/static/imgs/general/order-success-icon.png" class="image_7" />
</view>
<view class="flex-col items-center group_9">
<text class="text_6">支付成功</text>
<text class="text_7">付款¥ {{ price }}</text>
</view>
<view class="flex-col items-center text-wrapper" @click="jump"
><text class="text_8">查看订单</text></view
>
<view class="flex-col items-center group_10">
<image
v-show="imgUrl"
:show-menu-by-longpress="true"
:src="imgUrl"
class="image_9"
mode="widthFix"
/>
</view>
</view>
</view>
</view>
</template>
<script>
import { go2, back } from "@/utils/hook.js";
import { imgStamp } from "@/enums/index";
export default {
data() {
return {
imgStamp,
type: "success",
imgUrl: "",
price: 0,
};
},
onLoad(options) {
this.type = options.type;
this.imgUrl = options.imgUrl;
this.price = options.price;
},
methods: {
go2,
back,
jump() {
go2("order");
},
},
};
</script>
<style lang="scss" scoped>
.content {
width: 750rpx;
}
.group_5 {
padding: 20rpx 0 786rpx;
flex: 1 1 auto;
overflow-y: auto;
.section_3 {
margin: 0 32rpx;
padding: 48rpx 24rpx 8rpx;
background-color: rgb(255, 255, 255);
border-radius: 10rpx;
.group_9 {
margin-top: 40rpx;
.text_6 {
color: rgb(51, 51, 51);
font-size: 34rpx;
font-family: "PingFangSC-Medium";
font-weight: 500;
line-height: 48rpx;
}
.text_7 {
margin-top: 16rpx;
color: rgb(85, 85, 85);
font-size: 24rpx;
font-family: "PingFangSC-Regular";
line-height: 33rpx;
}
}
.text-wrapper {
margin-top: 47rpx;
padding: 11rpx 0;
align-self: center;
background-color: rgb(255, 255, 255);
border-radius: 32rpx;
width: 196rpx;
border: solid 1rpx rgb(151, 151, 151);
.text_8 {
color: rgb(85, 85, 85);
font-size: 28rpx;
font-family: "PingFangSC-Regular";
line-height: 40rpx;
}
}
.group_10 {
padding: 48rpx 0;
.image_9 {
width: 638rpx;
}
}
.image_7 {
width: 151rpx;
height: 86rpx;
}
}
}
</style>

151
pages/pay/components/FileItem.vue

@ -0,0 +1,151 @@
<template>
<view class="file-info">
<view class="title">商品信息</view>
<view class="file-content">
<view class="justify-between">
<image src="/static/imgs/general/pdf-icon.png" class="image"></image>
<view class="file-content-right">
<view class="flex-row-center-space" style="width: 100%">
<text class="file-title">文件打印</text>
<text class="price">¥{{ fileItem.price || 0 }}</text>
</view>
<view class="tip">{{ fileItem.fileNumber || 0 }}个文档</view>
</view>
</view>
<view class="postage">
<text class="label">快递方式</text>
<view class="flex-col-end-start">
<text class="label">圆通快递</text>
<text class="tip">24小时内发货(15:00前下单当天发货,节假日看公告)</text>
</view>
</view>
<view class="form">
<view class="form-item">
<text class="label">订单备注</text>
<input class="value" v-model="form.remark" placeholder="填写备注" />
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
fileItem: {
type: Object,
default: () => ({})
}
},
data() {
return {
form: {
remark: ''
}
}
},
methods: {
checkForm() {
return true
},
getForm() {
if (!this.checkForm()) {
uni.showToast({
title: '请填写完成信息',
icon: 'none'
})
return {
status: 'fail',
value: null
}
}
return {
status: 'success',
value: this.form
}
}
}
}
</script>
<style scoped lang="scss">
.file-info {
background-color: #fff;
width: 100%;
.title {
padding: 24rpx;
font-size: 30rpx;
color: rgb(0, 0, 0);
text-align: left;
border-bottom: 1px solid rgb(221, 221, 221);
}
.file-content {
padding: 32rpx 24rpx 24rpx;
.file-content-right {
flex: 1;
margin-left: 24rpx;
.tip {
font-size: 24rpx;
color: rgb(136, 136, 136);
margin-top: 16rpx;
text-align: left;
}
}
.image {
margin-left: 28rpx;
width: 60rpx;
height: 68rpx;
}
.file-title {
font-size: 32rpx;
color: rgb(51, 51, 51);
width: 400rpx;
overflow: hidden;
text-overflow: ellipsis;
}
.price {
font-size: 26rpx;
color: rgb(255, 0, 0);
}
.postage {
margin-top: 32rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
.tip {
font-size: 22rpx;
color: rgb(136, 136, 136);
margin-top: 16rpx;
text-align: left;
}
}
.form {
margin-top: 32rpx;
.form-item {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.label {
font-size: 28rpx;
color: rgb(51, 51, 51);
}
.value {
font-size: 28rpx;
color: rgb(153, 153, 153);
text-align: right;
width: 500rpx;
}
}
}
}
}
.label {
font-size: 28rpx;
color: rgb(51, 51, 51);
}
.red {
color: rgb(255, 0, 0);
}
</style>

82
pages/pay/components/OrderInfo.vue

@ -0,0 +1,82 @@
<template>
<view class="order-info">
<view class="title">订单明细</view>
<view class="order-content">
<view class="form">
<text class="label">商品金额</text>
<text class="value">¥ {{ orderInfo.goodPrice || 0 }}</text>
</view>
<view class="form">
<text class="label">运费</text>
<text class="value">¥ {{ orderInfo.postagePrice || 0 }}</text>
</view>
<view class="form" v-for="(item, index) in orderInfo.preferentialItems" :key="index">
<text class="label">{{ item.name }}</text>
<text class="value red">- ¥ {{ item.price }}</text>
</view>
</view>
<view class="total black">
总计:
<text class="red" style="margin-left: 20rpx">¥{{ orderInfo.totalPrice || 0 }}</text>
</view>
</view>
</template>
<script>
export default {
props: {
orderInfo: {
type: Object,
default: () => ({})
}
}
}
</script>
<style lang="scss" scoped>
.order-info {
width: 100%;
background-color: #fff;
.title {
padding: 24rpx;
font-size: 30rpx;
color: rgb(0, 0, 0);
text-align: left;
border-bottom: 1px solid rgb(221, 221, 221);
}
.order-content {
padding: 32rpx 24rpx 0;
.form {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
.label {
font-size: 28rpx;
color: rgb(51, 51, 51);
}
.value {
font-size: 28rpx;
color: rgb(51, 51, 51);
}
.red {
color: rgb(255, 0, 0);
}
}
}
.total {
width: 100%;
padding: 24rpx;
text-align: right;
border-top: 1px solid rgb(238, 238, 238);
font-size: 28rpx;
.black {
color: rgb(51, 51, 51);
}
.red {
color: rgb(255, 0, 0);
}
}
}
</style>

454
pages/pay/components/OtherItem.vue

@ -0,0 +1,454 @@
<template>
<view class="goods-info">
<view class="title">商品信息</view>
<view class="goods-content">
<view v-for="(goods, i) in goodsList" :key="i">
<view class="flex-row group_9">
<image :src="goods.productImgUrl" class="image_7" />
<view class="flex-col items-start group_10">
<view class="flex-col group_11">
<text class="text_12">{{ goods.productName }}</text>
<text class="text_13">¥{{ goods.listUnitPrice }}/{{ goods.skuDesc }}/{{ goods.quantity }}</text>
</view>
<text class="text_14">¥{{ goods.totalAmount }}</text>
</view>
</view>
<view class="remark" v-if="goods.remark">
<text class="remark-label">商品备注</text>
<text class="remark-content">{{ goods.remark || '' }}</text>
</view>
</view>
<view class="postage">
<text class="label">温馨提示</text>
<view class="flex-col-end-start">
<!-- <text class="label">{{ hasArea ? '下单后三天内发货' : '定制商品需要三到五天的制作工期' }}</text> -->
<text class="label">定制商品需要三到五天的制作工期</text>
<text class="tip">详情可资讯客服</text>
</view>
</view>
<view class="form">
<!-- 半天妖的区域选择 -->
<!-- <view v-if="hasArea" class="form-item">
<text class="label">下单区域</text>
<view class="box" @click="showArea">
<text v-show="areaName">{{ areaName }} {{ areaProvince }} {{ areaCity }}</text>
<image src="/static/imgs/general/right-arrow.png" style="width: 32rpx; height: 32rpx" v-show="!areaInfo"></image>
</view>
</view> -->
<view class="form-item">
<text class="label">订单备注</text>
<input class="value" v-model="form.remark" placeholder="填写备注" />
</view>
</view>
</view>
<!-- <uni-popup ref="areaPopup" type="bottom" background-color="#fff">
<view class="popup-content">
<view v-show="areaName">
<view class="title-content">
<text>{{ areaName }}</text>
<text style="margin-left: 32rpx">{{ areaProvince }}</text>
<text style="margin-left: 32rpx">{{ areaCity }}</text>
</view>
</view>
<view v-show="!areaName">
<view class="title-content">
<text>请选择区域</text>
</view>
</view>
<view class="scroll-title">
<view class="left">经理</view>
<view class="center"></view>
<view class="right"></view>
</view>
<view class="scroll-content">
<view class="left">
<view v-for="item in areaList" :key="item.id" class="item" @click="selectName(item.name)">
<text :class="{ selected: item.name === areaName }">{{ item.name }}</text>
</view>
</view>
<view class="center">
<view v-for="item in curProvinceList" :key="item.provinceCode" class="item" @click="selectProvince(item.provinceName)">
<text :class="{ selected: item.provinceName === areaProvince }">{{ item.provinceName }}</text>
</view>
</view>
<view class="right">
<view class="item" v-for="city in curCityList" :key="city.cityCode" @click="selectCity(city.cityName)">
<text :class="{ selected: city.cityName === areaCity }">{{ city.cityName }}</text>
</view>
</view>
</view>
</view>
</uni-popup> -->
</view>
</template>
<script>
import { getBTAreaList } from '@/apis/commonApi.js'
export default {
props: {
goodsList: {
type: Array,
default: () => [
// {
// productImgUrl: 'https://qncloudtest.oss-cn-shenzhen.aliyuncs.com/common/14189212646949759.png',
// productName: '便',
// listUnitPrice: 0.01,
// skuDesc: '/',
// quantity: 100,
// totalAmount: 1,
// remark: ''
// },
// {
// productImgUrl: 'https://qncloudtest.oss-cn-shenzhen.aliyuncs.com/common/14189212646949759.png',
// productName: '便',
// listUnitPrice: 0.01,
// skuDesc: '/',
// quantity: 100,
// totalAmount: 1,
// remark: ''
// }
]
}
},
data() {
return {
form: {
remark: ''
}
// areaList: [],
// curProvinceList: [],
// curCityList: [],
// areaName: '',
// areaProvince: '',
// areaCity: ''
}
},
// computed: {
// hasArea() {
// let target = this.goodsList.find((item) => item.type === 'bty')
// return !!target
// }
// },
// mounted() {
// this.getAreaList()
// },
// watch: {
// hasArea(val) {
// if (val) {
// this.getAreaList()
// }
// },
// //
// areaName(val) {
// this.areaCity = ''
// this.areaProvince = ''
// if (!val) {
// this.curProvinceList = []
// this.curCityList = []
// return
// }
// let target = this.areaList.find((item) => item.name === val)
// if (!target) {
// this.curProvinceList = []
// this.curCityList = []
// return
// }
// this.curProvinceList = target.provinces || []
// },
// areaProvince(val) {
// this.areaCity = ''
// if (!val) {
// this.curCityList = []
// return
// }
// let target = this.curProvinceList.find((item) => item.provinceName === val)
// if (!target) {
// this.curCityList = []
// return
// }
// this.curCityList = target.cities || []
// },
// areaCity(val) {
// if (!val) {
// return
// }
// this.$refs.areaPopup.close()
// }
// },
methods: {
// getAreaList() {
// getBTAreaList().then((res) => {
// this.areaList = res
// })
// },
// getBtyRemark() {
// let target = this.goodsList[0]
// let index = target.productName.lastIndexOf('')
// return target.productName.substring(index + 3) + ''
// },
// selectName(name) {
// if (this.areaName === name) {
// this.areaName = ''
// } else {
// this.areaName = name
// }
// },
// selectProvince(name) {
// if (this.areaProvince === name) {
// this.areaProvince = ''
// } else {
// this.areaProvince = name
// }
// },
// selectCity(name) {
// if (this.areaCity === name) {
// this.areaCity = ''
// return
// }
// this.areaCity = name
// },
// checkForm() {
// if (this.hasArea) {
// if (!this.areaCity) {
// uni.showToast({
// title: '',
// icon: 'none'
// })
// return false
// }
// if (!this.form.remark) {
// uni.showToast({
// title: '' + this.getBtyRemark(),
// icon: 'none'
// })
// return false
// }
// }
// return true
// },
getForm() {
// if (!this.checkForm()) {
// return {
// status: 'fail',
// value: null
// }
// }
// let form = { ...this.form }
// if (this.hasArea) {
// let extraRemark = `:${this.areaName}; ${this.areaProvince}; ${this.areaCity}; :`
// form.remark = extraRemark + form.remark
// }
return {
status: 'success',
value: this.form
}
}
// showArea() {
// this.$refs.areaPopup.open('bottom')
// }
}
}
</script>
<style scoped lang="scss">
.goods-info {
background-color: #fff;
width: 100%;
.title {
padding: 24rpx;
font-size: 30rpx;
color: rgb(0, 0, 0);
text-align: left;
border-bottom: 1px solid rgb(221, 221, 221);
}
.goods-content {
padding: 32rpx 24rpx 24rpx;
.group_9 {
margin-top: 20rpx;
padding: 0rpx 24rpx;
.image_7 {
border-radius: 16rpx;
width: 180rpx;
height: 180rpx;
}
.group_10 {
margin-left: 12rpx;
flex: 1 1 auto;
.group_11 {
width: 420rpx;
.text_12 {
color: #333333;
font-size: 32rpx;
font-family: 'PingFangSC-Medium';
font-weight: 500;
line-height: 45rpx;
text-align: left;
}
.text_13 {
margin-top: 10rpx;
align-self: flex-start;
color: #888888;
font-size: 22rpx;
font-family: 'PingFangSC-Medium';
font-weight: 500;
line-height: 30rpx;
}
}
.text_14 {
margin-top: 13rpx;
color: #ff0000;
font-size: 26rpx;
font-family: 'PingFangSC-Medium';
font-weight: 500;
line-height: 37rpx;
}
}
}
.remark {
display: flex;
margin-top: 16rpx;
line-height: 40rpx;
padding-left: 24rpx;
.remark-label {
display: inline-block;
color: #888888;
font-size: 24rpx;
}
.remark-content {
display: inline-block;
color: #333333;
font-size: 24rpx;
width: 520rpx;
}
}
.image {
margin-left: 28rpx;
width: 60rpx;
height: 68rpx;
}
.postage {
margin-top: 32rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
.tip {
font-size: 22rpx;
color: rgb(136, 136, 136);
margin-top: 16rpx;
text-align: left;
}
}
.form {
margin-top: 32rpx;
.form-item {
margin-top: 32rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.label {
font-size: 28rpx;
color: rgb(51, 51, 51);
}
.box {
font-size: 28rpx;
color: rgb(153, 153, 153);
text-align: right;
width: 500rpx;
display: flex;
align-items: center;
justify-content: flex-end;
}
.value {
font-size: 28rpx;
color: rgb(153, 153, 153);
text-align: right;
width: 500rpx;
}
}
}
}
}
.label {
font-size: 28rpx;
color: rgb(51, 51, 51);
}
.red {
color: rgb(255, 0, 0);
}
.popup-content {
width: 750rpx;
height: 800rpx;
border-radius: 16rpx 16rpx 0 0;
background-color: #fff;
overflow: hidden;
.title-content {
width: 100%;
padding: 0 32rpx;
height: 92rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 32rpx;
color: rgb(51, 51, 51);
}
.scroll-title {
width: 100%;
height: 92rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
color: rgb(51, 51, 51);
.left {
width: 250rpx;
text-align: center;
}
.center {
width: 250rpx;
text-align: center;
}
.right {
width: 250rpx;
text-align: center;
}
}
.scroll-content {
width: 750rpx;
height: 508rpx;
padding-bottom: 32rpx;
border-top: 1px solid rgba(221, 221, 221, 0.5);
display: flex;
align-items: flex-start;
.left {
width: 250rpx;
height: 508rpx;
overflow-y: auto;
}
.center {
width: 250rpx;
height: 508rpx;
overflow-y: auto;
}
.right {
width: 250rpx;
height: 508rpx;
overflow-y: auto;
}
.item {
width: 100%;
font-size: 28rpx;
line-height: 70rpx;
color: rgb(51, 51, 51);
height: 70rpx;
text-align: center;
}
.selected {
color: #007aff;
}
}
}
</style>

77
pages/pay/components/officialAccountPopup.vue

@ -0,0 +1,77 @@
<template>
<view class="off-account-container">
<uni-popup ref="offAccountPopup" >
<view class="content">
<view class="title">扫码领取优惠券</view>
<view class="desc1">
长按扫描二维码关注公众号免费获取优惠券一张<br>仅限首次关注公众号用户
</view>
<image class="ercode-img" show-menu-by-longpress src="https://qncloud.oss-cn-shenzhen.aliyuncs.com/wukong-printer-wx/gzh-ercode.png" alt="">
<view class="desc2">长按扫码二维码关注</view>
</view>
<image @click="close" class="close-img" src="/static/imgs/general/close-icon.png" alt="">
</uni-popup>
</view>
</template>
<script>
import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
export default {
components: { uniPopup },
methods: {
open() {
this.$refs.offAccountPopup.open('bottom')
},
close() {
this.$refs.offAccountPopup.close()
}
}
}
</script>
<style scoped lang="scss">
.off-account-container {
width: 750rpx;
text-align: center;
background-color: #ffffff;
.content {
width: 750rpx;
height: 614rpx;
box-sizing: content-box;
position: relative;
background-color: #ffffff;
border-radius: 20rpx 20rpx 0rpx 0rpx;
color: #333333;
.title {
font-weight: 500;
font-size: 36rpx;
line-height: 50rpx;
margin-top: 32rpx;
display: inline-block;
}
.desc1 {
width: 644rpx;
display: inline-block;
font-size: 28rpx;
margin-top: 31rpx;
line-height: 40rpx;
}
.ercode-img {
width: 272rpx;
height: 272rpx;
margin-top: 49rpx;
}
.desc2 {
margin-top: 24rpx;
font-weight: 500;
font-size: 32rpx;
}
}
.close-img {
width: 24rpx;
height: 24rpx;
position: absolute;
top: 45rpx;
right: 32rpx;
}
}
</style>

24
pages/pay/index.vue

@ -0,0 +1,24 @@
<template>
<view class="content">
<uni-nav-bar left-icon="back" @clickLeft="back" statusBar fixed title="支付"></uni-nav-bar>
</view>
</template>
<script>
import { go2, back } from '@/utils/hook.js'
export default {
data() {
return {}
},
methods: {
go2,
back
}
}
</script>
<style lang="scss" scoped>
.content {
width: 750rpx;
}
</style>

20
prettier.config.js

@ -0,0 +1,20 @@
module.exports = {
printWidth: 160,
semi: false,
vueIndentScriptAndStyle: true,
singleQuote: true,
endOfLine: 'lf',
tabWidth: 2,
useTabs: false,
quoteProps: 'preserve',
bracketSpacing: true,
trailingComma: 'none',
// 解决标签结尾 > 格式化到下一行的问题,htmlWhitespaceSensitivity不能为 strict
jsxBracketSameLine: false,
jsxSingleQuote: false,
arrowParens: 'always',
insertPragma: false,
requirePragma: false,
proseWrap: 'never',
htmlWhitespaceSensitivity: 'ignore'
}

25
static/icon/iconfont.css

@ -0,0 +1,25 @@
@font-face {
font-family: "iconfont"; /* Project id 3120523 */
src: url('/static/icon/iconfont.ttf') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-Less:before {
content: "\e734";
}
.icon-m_dow_arrow:before {
content: "\e600";
}
.icon-required:before {
content: "\e60e";
}

BIN
static/icon/iconfont.ttf

BIN
static/imgs/general/add-icon.png

Before After
Width: 99  |  Height: 99  |  Size: 2.3 KiB

BIN
static/imgs/general/baiduPan-icon.png

Before After
Width: 96  |  Height: 96  |  Size: 4.6 KiB

BIN
static/imgs/general/blue-arrow-down.png

Before After
Width: 112  |  Height: 204  |  Size: 6.8 KiB

BIN
static/imgs/general/blue-plus-icon.png

Before After
Width: 21  |  Height: 21  |  Size: 141 B

BIN
static/imgs/general/camera-icon.png

Before After
Width: 120  |  Height: 102  |  Size: 4.4 KiB

BIN
static/imgs/general/cart-icon.png

Before After
Width: 48  |  Height: 48  |  Size: 828 B

BIN
static/imgs/general/close-circle-icon.png

Before After
Width: 62  |  Height: 62  |  Size: 1.7 KiB

BIN
static/imgs/general/close-icon.png

Before After
Width: 54  |  Height: 54  |  Size: 887 B

BIN
static/imgs/general/coupon-txt-icon.png

Before After
Width: 496  |  Height: 48  |  Size: 4.9 KiB

BIN
static/imgs/general/customer-service-icon.png

Before After
Width: 48  |  Height: 48  |  Size: 1.1 KiB

BIN
static/imgs/general/default-fn-logo.png

Before After
Width: 40  |  Height: 40  |  Size: 765 B

BIN
static/imgs/general/doc-icon.png

Before After
Width: 68  |  Height: 68  |  Size: 1.9 KiB

BIN
static/imgs/general/down-act-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 323 B

BIN
static/imgs/general/down-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 359 B

BIN
static/imgs/general/down.png

Before After
Width: 40  |  Height: 40  |  Size: 461 B

BIN
static/imgs/general/eye-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 634 B

BIN
static/imgs/general/folder-icon.png

Before After
Width: 60  |  Height: 68  |  Size: 1.1 KiB

BIN
static/imgs/general/gesture.png

Before After
Width: 116  |  Height: 70  |  Size: 4.4 KiB

BIN
static/imgs/general/hand-up-icon.gif

Before After
Width: 100  |  Height: 72  |  Size: 5.4 KiB

BIN
static/imgs/general/jinShan-icon.png

Before After
Width: 96  |  Height: 96  |  Size: 5.5 KiB

BIN
static/imgs/general/local-icon.png

Before After
Width: 96  |  Height: 96  |  Size: 3.1 KiB

BIN
static/imgs/general/logo-icon.png

Before After
Width: 150  |  Height: 150  |  Size: 6.5 KiB

BIN
static/imgs/general/not-support-icon.png

Before After
Width: 68  |  Height: 68  |  Size: 1.9 KiB

BIN
static/imgs/general/order-success-icon.png

Before After
Width: 151  |  Height: 86  |  Size: 3.2 KiB

BIN
static/imgs/general/pdf-icon.png

Before After
Width: 68  |  Height: 68  |  Size: 1.4 KiB

BIN
static/imgs/general/plus-icon.png

Before After
Width: 56  |  Height: 56  |  Size: 514 B

BIN
static/imgs/general/ppt-icon.png

Before After
Width: 68  |  Height: 68  |  Size: 1.3 KiB

BIN
static/imgs/general/qn-txt.png

Before After
Width: 480  |  Height: 36  |  Size: 4.6 KiB

BIN
static/imgs/general/question-mask-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 1.3 KiB

BIN
static/imgs/general/reduce-icon.png

Before After
Width: 56  |  Height: 56  |  Size: 415 B

BIN
static/imgs/general/right-arrow-blue.png

Before After
Width: 30  |  Height: 50  |  Size: 1.3 KiB

BIN
static/imgs/general/right-arrow.png

Before After
Width: 64  |  Height: 64  |  Size: 1.2 KiB

BIN
static/imgs/general/select-icon-small.png

Before After
Width: 80  |  Height: 80  |  Size: 2.1 KiB

BIN
static/imgs/general/select-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 894 B

BIN
static/imgs/general/selected-icon-small.png

Before After
Width: 72  |  Height: 72  |  Size: 2.0 KiB

BIN
static/imgs/general/selected-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 984 B

BIN
static/imgs/general/share.png

Before After
Width: 48  |  Height: 48  |  Size: 666 B

BIN
static/imgs/general/tenCent-icon.png

Before After
Width: 96  |  Height: 96  |  Size: 3.7 KiB

BIN
static/imgs/general/top-arrow-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 381 B

BIN
static/imgs/general/txt-bg.png

Before After
Width: 266  |  Height: 66  |  Size: 5.2 KiB

BIN
static/imgs/general/up-act-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 316 B

BIN
static/imgs/general/up-arrow-icon.png

Before After
Width: 64  |  Height: 64  |  Size: 1.2 KiB

BIN
static/imgs/general/up-icon.png

Before After
Width: 32  |  Height: 32  |  Size: 361 B

BIN
static/imgs/general/upload-tip.png

Before After
Width: 96  |  Height: 96  |  Size: 3.4 KiB

BIN
static/imgs/general/uploading.gif

Before After
Width: 40  |  Height: 40  |  Size: 4.9 KiB

BIN
static/imgs/general/wx-icon.png

Before After
Width: 96  |  Height: 96  |  Size: 4.1 KiB

BIN
static/imgs/index/customer-service-icon.png

Before After
Width: 100  |  Height: 100  |  Size: 9.4 KiB

BIN
static/imgs/index/horn-icon.png

Before After
Width: 40  |  Height: 40  |  Size: 997 B

BIN
static/imgs/index/hot-icon.gif

Before After
Width: 40  |  Height: 26  |  Size: 7.0 KiB

BIN
static/imgs/index/index-community-icon.png

Before After
Width: 74  |  Height: 70  |  Size: 6.1 KiB

BIN
static/imgs/index/index-coupon-icon.png

Before After
Width: 64  |  Height: 72  |  Size: 4.2 KiB

BIN
static/imgs/index/index-library-icon.png

Before After
Width: 64  |  Height: 66  |  Size: 2.5 KiB

BIN
static/imgs/index/index-luck-draw-icon.png

Before After
Width: 64  |  Height: 64  |  Size: 5.4 KiB

BIN
static/imgs/index/index-sign-in-icon.png

Before After
Width: 64  |  Height: 68  |  Size: 4.5 KiB

BIN
static/imgs/index/send-icon.gif

Before After
Width: 40  |  Height: 26  |  Size: 6.9 KiB

BIN
static/imgs/tabbar/category-blue.png

Before After
Width: 44  |  Height: 44  |  Size: 1.3 KiB

BIN
static/imgs/tabbar/category-gray.png

Before After
Width: 44  |  Height: 44  |  Size: 1.6 KiB

BIN
static/imgs/tabbar/index-blue.png

Before After
Width: 45  |  Height: 45  |  Size: 1.1 KiB

BIN
static/imgs/tabbar/index-gray.png

Before After
Width: 45  |  Height: 45  |  Size: 1.7 KiB

BIN
static/imgs/tabbar/mine-blue.png

Before After
Width: 45  |  Height: 45  |  Size: 957 B

BIN
static/imgs/tabbar/mine-gray.png

Before After
Width: 44  |  Height: 44  |  Size: 1.5 KiB

BIN
static/imgs/tabbar/order-blue.png

Before After
Width: 44  |  Height: 44  |  Size: 869 B

BIN
static/imgs/tabbar/order-gray.png

Before After
Width: 44  |  Height: 44  |  Size: 1.5 KiB

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

Loading…
Cancel
Save