@ -0,0 +1,12 @@ |
|||||
|
# http://editorconfig.org |
||||
|
root = true |
||||
|
|
||||
|
[*] |
||||
|
indent_style = space |
||||
|
indent_size = 2 |
||||
|
charset = utf-8 |
||||
|
trim_trailing_whitespace = true |
||||
|
insert_final_newline = true |
||||
|
|
||||
|
[*.md] |
||||
|
trim_trailing_whitespace = false |
@ -0,0 +1,2 @@ |
|||||
|
# 配置文档参考 https://taro-docs.jd.com/docs/next/env-mode-config |
||||
|
# TARO_APP_ID="开发环境下的小程序 AppID" |
@ -0,0 +1 @@ |
|||||
|
# TARO_APP_ID="生产环境下的小程序 AppID" |
@ -0,0 +1 @@ |
|||||
|
# TARO_APP_ID="测试环境下的小程序 AppID" |
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"extends": ["taro/react"], |
||||
|
"rules": { |
||||
|
"react/jsx-uses-react": "off", |
||||
|
"react/react-in-jsx-scope": "off" |
||||
|
} |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
dist/ |
||||
|
deploy_versions/ |
||||
|
.temp/ |
||||
|
.rn_temp/ |
||||
|
node_modules/ |
||||
|
.DS_Store |
||||
|
.swc |
||||
|
*.local |
@ -0,0 +1,78 @@ |
|||||
|
# jf_202506 |
||||
|
|
||||
|
#### 介绍 |
||||
|
202506小程序交付 |
||||
|
|
||||
|
#### 软件架构 |
||||
|
taro react |
||||
|
|
||||
|
### 依赖工具 |
||||
|
+ **开发框架**:[tarojs@4.1.2](https://docs.taro.zone/docs/) |
||||
|
+ **基础架构**:[react@18.0](https://reactjs.org/) |
||||
|
+ **ui框架**:[antd-mobile@5.39](https://mobile.ant.design/zh) |
||||
|
|
||||
|
### 项目启动 |
||||
|
1. node > ver.18 |
||||
|
2. 安装yarn@1.22.19,执行`yarn install` |
||||
|
3. 执行`npm run dev:h5`,本地启动 |
||||
|
4. 执行`npm run build:h5`,打包编译 |
||||
|
|
||||
|
### 项目部署 |
||||
|
|
||||
|
1. 本地构建 |
||||
|
|
||||
|
```bash |
||||
|
// 1. git 操作拉取项目,此处省略... |
||||
|
// 2. 进入到项目根目录 |
||||
|
yarn install |
||||
|
// 3. 编译构建 |
||||
|
npm run build:h5 |
||||
|
``` |
||||
|
|
||||
|
2. 登录宝塔平台 |
||||
|
|
||||
|
3. 网站/HTML项目 下 添加HTML项目 |
||||
|
|
||||
|
 |
||||
|
|
||||
|
4. 修改nginx配置文件 |
||||
|
|
||||
|
 |
||||
|
|
||||
|
```nginx |
||||
|
location ^~/api { |
||||
|
proxy_set_header X-Real-IP $remote_addr; |
||||
|
proxy_set_header REMOTE-HOST $remote_addr; |
||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
||||
|
|
||||
|
proxy_http_version 1.1; |
||||
|
proxy_set_header Connection ''; |
||||
|
|
||||
|
proxy_buffering off; |
||||
|
proxy_cache off; |
||||
|
|
||||
|
proxy_read_timeout 86400s; |
||||
|
send_timeout 86400s; |
||||
|
|
||||
|
client_max_body_size 50m; |
||||
|
|
||||
|
# 这里改成 [对应的域名 + /api] |
||||
|
proxy_pass https://he.lehuonianhua.com/api; |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
|
||||
|
5. 上传生产包 |
||||
|
|
||||
|
 |
||||
|
|
||||
|
6. 重启nginx |
||||
|
|
||||
|
 |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## 讨论 |
||||
|
联系人:jinech 13478707150@163.com |
@ -0,0 +1,12 @@ |
|||||
|
// babel-preset-taro 更多选项和默认值:
|
||||
|
// https://docs.taro.zone/docs/next/babel-config
|
||||
|
module.exports = { |
||||
|
presets: [ |
||||
|
['taro', { |
||||
|
framework: 'react', |
||||
|
ts: false, |
||||
|
compiler: 'vite', |
||||
|
useBuiltIns: process.env.TARO_ENV === 'h5' ? 'usage' : false |
||||
|
}] |
||||
|
] |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
|
||||
|
|
||||
|
export default { |
||||
|
|
||||
|
mini: {}, |
||||
|
h5: { |
||||
|
devServer: { |
||||
|
proxy: { |
||||
|
'/api/Open': { |
||||
|
target: 'https://he.lehuonianhua.com', |
||||
|
changeOrigin: true, |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,89 @@ |
|||||
|
import { defineConfig } from '@tarojs/cli' |
||||
|
|
||||
|
import devConfig from './dev' |
||||
|
import prodConfig from './prod' |
||||
|
|
||||
|
// https://taro-docs.jd.com/docs/next/config#defineconfig-辅助函数
|
||||
|
export default defineConfig(async (merge, { command, mode }) => { |
||||
|
const baseConfig = { |
||||
|
projectName: 'jf_20250608', |
||||
|
date: '2025-6-8', |
||||
|
designWidth: 750, |
||||
|
deviceRatio: { |
||||
|
640: 2.34 / 2, |
||||
|
750: 1, |
||||
|
375: 2, |
||||
|
828: 1.81 / 2 |
||||
|
}, |
||||
|
sourceRoot: 'src', |
||||
|
outputRoot: 'dist', |
||||
|
plugins: [], |
||||
|
defineConstants: { |
||||
|
}, |
||||
|
copy: { |
||||
|
patterns: [ |
||||
|
], |
||||
|
options: { |
||||
|
} |
||||
|
}, |
||||
|
framework: 'react', |
||||
|
compiler: 'vite', |
||||
|
mini: { |
||||
|
postcss: { |
||||
|
pxtransform: { |
||||
|
enable: true, |
||||
|
config: { |
||||
|
|
||||
|
} |
||||
|
}, |
||||
|
cssModules: { |
||||
|
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
|
||||
|
config: { |
||||
|
namingPattern: 'module', // 转换模式,取值为 global/module
|
||||
|
generateScopedName: '[name]__[local]___[hash:base64:5]' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
h5: { |
||||
|
publicPath: '/', |
||||
|
staticDirectory: 'static', |
||||
|
|
||||
|
miniCssExtractPluginOption: { |
||||
|
ignoreOrder: true, |
||||
|
filename: 'css/[name].[hash].css', |
||||
|
chunkFilename: 'css/[name].[chunkhash].css' |
||||
|
}, |
||||
|
postcss: { |
||||
|
autoprefixer: { |
||||
|
enable: true, |
||||
|
config: {} |
||||
|
}, |
||||
|
cssModules: { |
||||
|
enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
|
||||
|
config: { |
||||
|
namingPattern: 'module', // 转换模式,取值为 global/module
|
||||
|
generateScopedName: '[name]__[local]___[hash:base64:5]' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
rn: { |
||||
|
appName: 'taroDemo', |
||||
|
postcss: { |
||||
|
cssModules: { |
||||
|
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
process.env.BROWSERSLIST_ENV = process.env.NODE_ENV |
||||
|
|
||||
|
if (process.env.NODE_ENV === 'development') { |
||||
|
// 本地开发构建配置(不混淆压缩)
|
||||
|
return merge({}, baseConfig, devConfig) |
||||
|
} |
||||
|
// 生产构建配置(默认开启压缩混淆等)
|
||||
|
return merge({}, baseConfig, prodConfig) |
||||
|
}) |
@ -0,0 +1,37 @@ |
|||||
|
|
||||
|
|
||||
|
export default { |
||||
|
mini: {}, |
||||
|
h5: { |
||||
|
// publicPath: '/ryc/',
|
||||
|
// staticDirectory: './ryc/static'
|
||||
|
// 确保产物为 es5
|
||||
|
// legacy: true,
|
||||
|
/** |
||||
|
* WebpackChain 插件配置 |
||||
|
* @docs https://github.com/neutrinojs/webpack-chain
|
||||
|
*/ |
||||
|
// webpackChain (chain) {
|
||||
|
// /**
|
||||
|
// * 如果 h5 端编译后体积过大,可以使用 webpack-bundle-analyzer 插件对打包体积进行分析。
|
||||
|
// * @docs https://github.com/webpack-contrib/webpack-bundle-analyzer
|
||||
|
// */
|
||||
|
// chain.plugin('analyzer')
|
||||
|
// .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
|
||||
|
// /**
|
||||
|
// * 如果 h5 端首屏加载时间过长,可以使用 prerender-spa-plugin 插件预加载首页。
|
||||
|
// * @docs https://github.com/chrisvfritz/prerender-spa-plugin
|
||||
|
// */
|
||||
|
// const path = require('path')
|
||||
|
// const Prerender = require('prerender-spa-plugin')
|
||||
|
// const staticDir = path.join(__dirname, '..', 'dist')
|
||||
|
// chain
|
||||
|
// .plugin('prerender')
|
||||
|
// .use(new Prerender({
|
||||
|
// staticDir,
|
||||
|
// routes: [ '/pages/index/index' ],
|
||||
|
// postProcess: (context) => ({ ...context, outputPath: path.join(staticDir, 'index.html') })
|
||||
|
// }))
|
||||
|
// }
|
||||
|
} |
||||
|
} |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 202 KiB |
After Width: | Height: | Size: 74 KiB |
@ -0,0 +1,93 @@ |
|||||
|
{ |
||||
|
"name": "jf_20250608", |
||||
|
"version": "1.0.0", |
||||
|
"private": true, |
||||
|
"description": "", |
||||
|
"templateInfo": { |
||||
|
"name": "default", |
||||
|
"typescript": false, |
||||
|
"css": "Less", |
||||
|
"framework": "React" |
||||
|
}, |
||||
|
"scripts": { |
||||
|
"build:weapp": "taro build --type weapp", |
||||
|
"build:swan": "taro build --type swan", |
||||
|
"build:alipay": "taro build --type alipay", |
||||
|
"build:tt": "taro build --type tt", |
||||
|
"build:h5": "taro build --type h5", |
||||
|
"build:rn": "taro build --type rn", |
||||
|
"build:qq": "taro build --type qq", |
||||
|
"build:jd": "taro build --type jd", |
||||
|
"build:harmony-hybrid": "taro build --type harmony-hybrid", |
||||
|
"dev:weapp": "npm run build:weapp -- --watch", |
||||
|
"dev:swan": "npm run build:swan -- --watch", |
||||
|
"dev:alipay": "npm run build:alipay -- --watch", |
||||
|
"dev:tt": "npm run build:tt -- --watch", |
||||
|
"dev:h5": "npm run build:h5 -- --watch", |
||||
|
"dev:rn": "npm run build:rn -- --watch", |
||||
|
"dev:qq": "npm run build:qq -- --watch", |
||||
|
"dev:jd": "npm run build:jd -- --watch", |
||||
|
"dev:harmony-hybrid": "npm run build:harmony-hybrid -- --watch" |
||||
|
}, |
||||
|
"browserslist": { |
||||
|
"development": [ |
||||
|
"defaults and fully supports es6-module", |
||||
|
"maintained node versions" |
||||
|
], |
||||
|
"production": [ |
||||
|
"last 3 versions", |
||||
|
"Android >= 4.1", |
||||
|
"ios >= 8" |
||||
|
] |
||||
|
}, |
||||
|
"author": "", |
||||
|
"dependencies": { |
||||
|
"@babel/runtime": "^7.24.4", |
||||
|
"@tarojs/components": "4.1.2", |
||||
|
"@tarojs/helper": "4.1.2", |
||||
|
"@tarojs/plugin-framework-react": "4.1.2", |
||||
|
"@tarojs/plugin-platform-alipay": "4.1.2", |
||||
|
"@tarojs/plugin-platform-h5": "4.1.2", |
||||
|
"@tarojs/plugin-platform-harmony-hybrid": "4.1.2", |
||||
|
"@tarojs/plugin-platform-jd": "4.1.2", |
||||
|
"@tarojs/plugin-platform-qq": "4.1.2", |
||||
|
"@tarojs/plugin-platform-swan": "4.1.2", |
||||
|
"@tarojs/plugin-platform-tt": "4.1.2", |
||||
|
"@tarojs/plugin-platform-weapp": "4.1.2", |
||||
|
"@tarojs/react": "4.1.2", |
||||
|
"@tarojs/runtime": "4.1.2", |
||||
|
"@tarojs/shared": "4.1.2", |
||||
|
"@tarojs/taro": "4.1.2", |
||||
|
"ahooks": "^3.8.5", |
||||
|
"antd-mobile": "^5.39.0", |
||||
|
"axios": "^1.10.0", |
||||
|
"classnames": "^2.5.1", |
||||
|
"lodash": "^4.17.21", |
||||
|
"md5": "^2.3.0", |
||||
|
"qrcode.react": "^4.2.0", |
||||
|
"react": "^18.0.0", |
||||
|
"react-copy-to-clipboard": "^5.1.0", |
||||
|
"react-dom": "^18.0.0" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"@babel/core": "^7.24.4", |
||||
|
"@babel/helper-compilation-targets": "^7.27.2", |
||||
|
"@babel/plugin-transform-class-properties": "7.25.9", |
||||
|
"@babel/preset-react": "^7.24.1", |
||||
|
"@tarojs/cli": "4.1.2", |
||||
|
"@tarojs/vite-runner": "4.1.2", |
||||
|
"@types/react": "^18.0.0", |
||||
|
"@vitejs/plugin-react": "^4.3.0", |
||||
|
"babel-preset-taro": "4.1.2", |
||||
|
"eslint": "^8.57.0", |
||||
|
"eslint-config-taro": "4.1.2", |
||||
|
"eslint-plugin-react": "^7.34.1", |
||||
|
"eslint-plugin-react-hooks": "^4.4.0", |
||||
|
"less": "^4.2.0", |
||||
|
"postcss": "^8.4.38", |
||||
|
"react-refresh": "^0.14.0", |
||||
|
"stylelint": "^16.4.0", |
||||
|
"terser": "^5.30.4", |
||||
|
"vite": "^4.2.0" |
||||
|
} |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
{ |
||||
|
"miniprogramRoot": "./dist", |
||||
|
"projectname": "jf_20250608", |
||||
|
"description": "", |
||||
|
"appid": "touristappid", |
||||
|
"setting": { |
||||
|
"urlCheck": true, |
||||
|
"es6": false, |
||||
|
"enhance": false, |
||||
|
"compileHotReLoad": false, |
||||
|
"postcss": false, |
||||
|
"minified": false |
||||
|
}, |
||||
|
"compileType": "miniprogram" |
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
export default defineAppConfig({ |
||||
|
pages: [ |
||||
|
'pages/index/index', |
||||
|
'pages/dataset/index', |
||||
|
'pages/mine/index', |
||||
|
'pages/login/index', |
||||
|
'pages/forget/index', |
||||
|
'pages/payforget/index', |
||||
|
'pages/register/index', |
||||
|
'pages/shopinfo/index', |
||||
|
'pages/team/index', |
||||
|
'pages/invite/index', |
||||
|
'pages/paymentmethod/index', |
||||
|
'pages/funds/index', |
||||
|
'pages/safe/index', |
||||
|
'pages/feedback/index', |
||||
|
'pages/myfeedback/index', |
||||
|
'pages/notice/index', |
||||
|
'pages/notice-detail/index', |
||||
|
'pages/viplevelup/index', |
||||
|
'pages/sitemessage/index', |
||||
|
'pages/payconfirm/index', |
||||
|
'pages/feeconfirm/index', |
||||
|
], |
||||
|
window: { |
||||
|
backgroundTextStyle: 'light', |
||||
|
navigationBarBackgroundColor: '#fff', |
||||
|
navigationBarTitleText: 'WeChat', |
||||
|
navigationBarTextStyle: 'black' |
||||
|
}, |
||||
|
tabBar: { |
||||
|
color: '#7A7E83', |
||||
|
selectedColor: '#007AFF', |
||||
|
backgroundColor: '#FAFAFA', |
||||
|
list: [ |
||||
|
{ |
||||
|
pagePath: 'pages/index/index', |
||||
|
text: '首页', |
||||
|
iconPath: 'assets/icons/home.png', |
||||
|
selectedIconPath: 'assets/icons/home-active.png' |
||||
|
}, |
||||
|
{ |
||||
|
pagePath: 'pages/dataset/index', |
||||
|
text: '数据优化', |
||||
|
iconPath: 'assets/icons/dataset.png', |
||||
|
selectedIconPath: 'assets/icons/dataset-active.png' |
||||
|
}, |
||||
|
{ |
||||
|
pagePath: 'pages/mine/index', |
||||
|
text: '我的', |
||||
|
iconPath: 'assets/icons/mine.png', |
||||
|
selectedIconPath: 'assets/icons/mine-active.png' |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}) |
@ -0,0 +1,15 @@ |
|||||
|
|
||||
|
import { useLaunch } from '@tarojs/taro'; |
||||
|
|
||||
|
import './app.less'; |
||||
|
|
||||
|
function App({ children }) { |
||||
|
useLaunch(() => { |
||||
|
console.log('App launched.') |
||||
|
}); |
||||
|
|
||||
|
// children 是将要会渲染的页面
|
||||
|
return children; |
||||
|
} |
||||
|
|
||||
|
export default App; |
@ -0,0 +1,3 @@ |
|||||
|
:root { |
||||
|
--color-primary: #007AFF; |
||||
|
} |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 172 KiB |
@ -0,0 +1,71 @@ |
|||||
|
|
||||
|
import cls from 'classnames'; |
||||
|
import styles from './index.module.less'; |
||||
|
import { Image, ImageViewer } from 'antd-mobile'; |
||||
|
import { CameraOutline } from 'antd-mobile-icons'; |
||||
|
import { View } from '@tarojs/components'; |
||||
|
import { uploadImage64Action } from '../../request/actions'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
import React, { useState } from 'react'; |
||||
|
|
||||
|
const FormImage = ({ value, className, onChange, readonly, ...props }) => { |
||||
|
const prefix = cls(styles.img, className); |
||||
|
const [visible, updateVisible] = useState(false); |
||||
|
|
||||
|
const handleClick = () => { |
||||
|
// TODO |
||||
|
if (readonly || value) { |
||||
|
updateVisible(true); |
||||
|
return; |
||||
|
} |
||||
|
const input = document.createElement('input'); |
||||
|
input.type = 'file'; |
||||
|
input.accept = 'image/*'; |
||||
|
input.onchange = (event) => { |
||||
|
const file = event.target.files[0]; |
||||
|
if (file) { |
||||
|
const reader = new FileReader(); |
||||
|
reader.onload = async () => { |
||||
|
const imageBase64 = reader.result; |
||||
|
const res = await uploadImage64Action({ imageBase64 }); |
||||
|
onChange(res?.logo); |
||||
|
}; |
||||
|
reader.readAsDataURL(file); // 将文件读取为 Base64 |
||||
|
} |
||||
|
}; |
||||
|
input.click(); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
if (!value) { |
||||
|
if (readonly) { |
||||
|
return ( |
||||
|
<Image src={value} className={prefix} fit='fill' {...props} /> |
||||
|
); |
||||
|
} |
||||
|
return ( |
||||
|
<View className={styles.empty} onClick={handleClick} {...props}> |
||||
|
<CameraOutline /> |
||||
|
</View> |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<React.Fragment> |
||||
|
<Image src={value} className={prefix} fit='fill' onClick={handleClick} {...props} /> |
||||
|
<ImageViewer |
||||
|
classNames={{ |
||||
|
mask: 'customize-mask', |
||||
|
body: 'customize-body', |
||||
|
}} |
||||
|
image={value} |
||||
|
visible={visible} |
||||
|
onClose={() => { |
||||
|
updateVisible(false) |
||||
|
}} |
||||
|
/> |
||||
|
</React.Fragment> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default FormImage; |
@ -0,0 +1,15 @@ |
|||||
|
|
||||
|
.img { |
||||
|
width: 72px; |
||||
|
height: 72px; |
||||
|
} |
||||
|
|
||||
|
.empty { |
||||
|
width: 72px; |
||||
|
height: 72px; |
||||
|
border-radius: 6px; |
||||
|
background-color: #f4f5f7; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
|
||||
|
const FormLabel = ({ value, render, ...props }) => { |
||||
|
|
||||
|
return <span {...props} >{render ? render(value) : value}</span>; |
||||
|
}; |
||||
|
|
||||
|
export default FormLabel; |
@ -0,0 +1,96 @@ |
|||||
|
import { useEffect, useRef, useState } from 'react'; |
||||
|
|
||||
|
import { AxiosRequestConfig } from 'axios'; |
||||
|
import { Toast } from 'antd-mobile'; |
||||
|
|
||||
|
type Request<T, U> = (params: T, options?: any) => Promise<U>; |
||||
|
|
||||
|
interface UseRequestListProps<P, R> { |
||||
|
action: Request<P, R>; |
||||
|
immediate?: boolean; |
||||
|
onOk?: () => void | boolean; |
||||
|
initFilterParams?: Partial<P>; |
||||
|
showMsg?: boolean; |
||||
|
options?: AxiosRequestConfig; |
||||
|
loop?: boolean; |
||||
|
interval?: number; |
||||
|
onLoop?: (data: any) => boolean; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
function useRequestList<P, R>({ |
||||
|
action, |
||||
|
immediate = true, |
||||
|
onOk, |
||||
|
initFilterParams, |
||||
|
showMsg = false, |
||||
|
options = {}, |
||||
|
loop = false, |
||||
|
interval = 2000, |
||||
|
onLoop |
||||
|
}: UseRequestListProps<P, R>) { |
||||
|
const [loading, updateLoading] = useState(false); |
||||
|
const filterParamsRef = useRef(initFilterParams); |
||||
|
const [data, updateData] = useState<R>(); |
||||
|
|
||||
|
const timer = useRef<any>(null); |
||||
|
|
||||
|
const abortLoop = () => { |
||||
|
if (timer.current) { |
||||
|
clearInterval(timer.current); |
||||
|
timer.current = null; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const getDataTask = async (params: P, loading = true) => { |
||||
|
try { |
||||
|
loading && updateLoading(true); |
||||
|
const filterParams = filterParamsRef.current; |
||||
|
const queryParams = { ...filterParams, ...params }; |
||||
|
const res = await action(queryParams, options); |
||||
|
filterParamsRef.current = queryParams; |
||||
|
updateData(res); |
||||
|
if (loop && onLoop?.(res)) { |
||||
|
timer.current = setTimeout(() => { |
||||
|
getDataTask(queryParams, loading); |
||||
|
}, interval); |
||||
|
} |
||||
|
else { |
||||
|
loading && updateLoading(false); |
||||
|
onOk?.(); |
||||
|
return res; |
||||
|
} |
||||
|
} |
||||
|
catch (err) { |
||||
|
abortLoop(); |
||||
|
showMsg && Toast.show({ |
||||
|
icon: 'error', |
||||
|
content: `${err}` |
||||
|
}); |
||||
|
} |
||||
|
finally { |
||||
|
loading && !loop && updateLoading(false); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
useEffect(() => { |
||||
|
return abortLoop; |
||||
|
}, []); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (!immediate) { |
||||
|
return; |
||||
|
} |
||||
|
getDataTask({} as P); |
||||
|
}, []); |
||||
|
|
||||
|
return { |
||||
|
getDataTask, |
||||
|
loading, |
||||
|
data, |
||||
|
filterParams: filterParamsRef.current, |
||||
|
abortLoop |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default useRequestList; |
@ -0,0 +1,50 @@ |
|||||
|
/* |
||||
|
* @Author: WIN-J7OL7MK489U\EDY 13478707150@163.com |
||||
|
* @Date: 2023-06-28 16:45:43 |
||||
|
* @LastEditors: BJ-HPC3\13478 13478707150@163.com |
||||
|
* @LastEditTime: 2025-02-21 17:15:40 |
||||
|
* @FilePath: \jsure_zdbg_web_react\src\hooks\useRequest\index.ts |
||||
|
* @Description: 通用请求 |
||||
|
*/ |
||||
|
|
||||
|
import { useState } from 'react'; |
||||
|
|
||||
|
import type { Request } from '@/request/utils'; |
||||
|
|
||||
|
interface UseRequestListProps<P, R> { |
||||
|
action?: Request<P, R>; |
||||
|
onOk?: () => void; |
||||
|
}; |
||||
|
|
||||
|
function useRequestSubmit<P, R>({ |
||||
|
action, |
||||
|
onOk, |
||||
|
}: UseRequestListProps<P, R>) { |
||||
|
const [loading, updateLoading] = useState(false); |
||||
|
const [data, updateData] = useState<R>(null); |
||||
|
|
||||
|
const actionTask = async (params: P, loading = true) => { |
||||
|
try { |
||||
|
loading && updateLoading(true); |
||||
|
const res = await action(params); |
||||
|
updateData(res); |
||||
|
onOk?.(); |
||||
|
return res; |
||||
|
} |
||||
|
catch (err) { |
||||
|
console.log('[request submit err]: ', err); |
||||
|
return Promise.reject(err); |
||||
|
} |
||||
|
finally { |
||||
|
loading && updateLoading(false); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return { |
||||
|
actionTask, |
||||
|
loading, |
||||
|
data |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default useRequestSubmit; |
@ -0,0 +1,17 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"> |
||||
|
<meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport"> |
||||
|
<meta name="apple-mobile-web-app-capable" content="yes"> |
||||
|
<meta name="apple-touch-fullscreen" content="yes"> |
||||
|
<meta name="format-detection" content="telephone=no,address=no"> |
||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="white"> |
||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" > |
||||
|
<title>jf_20250608</title> |
||||
|
<script><%= htmlWebpackPlugin.options.script %></script> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div id="app"></div> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,111 @@ |
|||||
|
import React, { useEffect, useState } from 'react'; |
||||
|
import { PullToRefresh, List, Empty, Button, Modal, Toast } from 'antd-mobile'; |
||||
|
import { View, Text, ScrollView } from '@tarojs/components'; |
||||
|
import { getOrderListLoopAction, orderConfirmAction } from '../../../../request/actions'; |
||||
|
import { OrderStatusEnum } from '../../constants'; |
||||
|
import Taro, { useDidShow } from '@tarojs/taro'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
const fetchDataRecursively = async (times, params, datasource) => { |
||||
|
if (times <= 0 || (datasource && datasource?.length < 10)) { |
||||
|
return []; |
||||
|
} |
||||
|
const lastOrderId = datasource?.[datasource?.length - 1]?.orderId; |
||||
|
const result = await getOrderListLoopAction({ ...params, lastOrderId }); |
||||
|
const nextResults = await fetchDataRecursively(times - 1, params, result?.dataList); |
||||
|
return [...result?.dataList, ...nextResults]; |
||||
|
}; |
||||
|
|
||||
|
const DataList = ({ orderStatus }) => { |
||||
|
const [data, setData] = useState([]); |
||||
|
|
||||
|
const initData = async () => { |
||||
|
const dataSource = await fetchDataRecursively(1, { orderStatus }); |
||||
|
setData(dataSource); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
const handleScrollToLower = async () => { |
||||
|
const lastLogId = data?.[data?.length - 1]?.orderId; |
||||
|
const result = await getOrderListLoopAction({ lastLogId }); |
||||
|
const newDataSource = result?.dataList; |
||||
|
setData([...data, ...newDataSource]); |
||||
|
}; |
||||
|
|
||||
|
const handleJump = item => { |
||||
|
// 去支付 |
||||
|
if (orderStatus === OrderStatusEnum.waittingForPay.value) { |
||||
|
Taro.navigateTo({ |
||||
|
url: `/pages/payconfirm/index?orderId=${item.orderId}` |
||||
|
}); |
||||
|
} |
||||
|
// 确认订单 |
||||
|
if (orderStatus === OrderStatusEnum.waittingForConfirm.value) { |
||||
|
// Modal.confirm({ |
||||
|
// title: '是否确认收款?', |
||||
|
// onConfirm: async () => { |
||||
|
// try { |
||||
|
// const orderId = item.orderId; |
||||
|
// await orderConfirmAction({ orderId }); |
||||
|
// initData(); |
||||
|
// Toast.show({ |
||||
|
// icon: 'success', |
||||
|
// content: '已成功确认收款信息' |
||||
|
// }); |
||||
|
// } |
||||
|
// catch (err) { |
||||
|
// console.log('err: ', err); |
||||
|
// } |
||||
|
// } |
||||
|
// }) |
||||
|
Taro.navigateTo({ |
||||
|
url: `/pages/feeconfirm/index?orderId=${item.orderId}` |
||||
|
}); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
useDidShow(initData); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
initData(); |
||||
|
}, [orderStatus]); |
||||
|
|
||||
|
return ( |
||||
|
<PullToRefresh |
||||
|
onRefresh={initData} |
||||
|
> |
||||
|
{data.length > 0 ? ( |
||||
|
<ScrollView |
||||
|
scrollY |
||||
|
onScrollToLower={handleScrollToLower} |
||||
|
lowerThreshold={50} |
||||
|
> |
||||
|
<List className={styles.list}> |
||||
|
{data.map((item, index) => ( |
||||
|
<List.Item key={index} onClick={() => handleJump(item)} arrowIcon={false}> |
||||
|
<View className={styles.row}> |
||||
|
<Text>订单编号: {item.orderId}</Text> |
||||
|
<Text>订单日期: {item.orderDate || '-'}</Text> |
||||
|
</View> |
||||
|
<View className={styles.row}> |
||||
|
<Text>订单金额: {item.orderPrice}</Text> |
||||
|
</View> |
||||
|
{orderStatus !== OrderStatusEnum.done.value && ( |
||||
|
<Button className={styles.btn}>{item.buttonText}</Button> |
||||
|
)} |
||||
|
</List.Item> |
||||
|
))} |
||||
|
</List> |
||||
|
</ScrollView> |
||||
|
) : ( |
||||
|
<Empty |
||||
|
style={{ padding: '64px 0' }} |
||||
|
description='暂无数据' |
||||
|
/> |
||||
|
)} |
||||
|
</PullToRefresh > |
||||
|
) |
||||
|
}; |
||||
|
|
||||
|
export default DataList; |
@ -0,0 +1,12 @@ |
|||||
|
.row { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
font-size: 28px; |
||||
|
line-height: 2; |
||||
|
} |
||||
|
.btn { |
||||
|
width: 100%; |
||||
|
} |
||||
|
.list { |
||||
|
height: calc(100vh - 92px - 120px); |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
|
||||
|
export const OrderStatusEnum = { |
||||
|
waittingForPay: { |
||||
|
label: '待付款', |
||||
|
value: '0' |
||||
|
}, |
||||
|
waittingForConfirm: { |
||||
|
label: '待确认', |
||||
|
value: '1' |
||||
|
}, |
||||
|
done: { |
||||
|
label: '已完成', |
||||
|
value: '9' |
||||
|
} |
||||
|
}; |
@ -0,0 +1,4 @@ |
|||||
|
export default definePageConfig({ |
||||
|
navigationBarTitleText: '数据优化', |
||||
|
usingComponents: {}, |
||||
|
}) |
@ -0,0 +1,25 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Tabs } from 'antd-mobile'; |
||||
|
|
||||
|
import DataList from './components/DataList'; |
||||
|
import { OrderStatusEnum } from './constants'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Dataset() { |
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Tabs className={styles.tabs} defaultActiveKey={OrderStatusEnum.waittingForPay.value}> |
||||
|
<Tabs.Tab title='待支付' key={OrderStatusEnum.waittingForPay.value}> |
||||
|
<DataList orderStatus={OrderStatusEnum.waittingForPay.value} /> |
||||
|
</Tabs.Tab> |
||||
|
<Tabs.Tab title='待确认' key={OrderStatusEnum.waittingForConfirm.value}> |
||||
|
<DataList orderStatus={OrderStatusEnum.waittingForConfirm.value} /> |
||||
|
</Tabs.Tab> |
||||
|
<Tabs.Tab title='已完成' key={OrderStatusEnum.done.value}> |
||||
|
<DataList orderStatus={OrderStatusEnum.done.value} /> |
||||
|
</Tabs.Tab> |
||||
|
</Tabs> |
||||
|
</View> |
||||
|
) |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
.container { |
||||
|
position: relative; |
||||
|
|
||||
|
.tabs { |
||||
|
height: 82px; |
||||
|
position: sticky; |
||||
|
top: 0; |
||||
|
z-index: 9; |
||||
|
background-color: #fff; |
||||
|
} |
||||
|
:global { |
||||
|
.adm-list-body { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Form } from 'antd-mobile'; |
||||
|
import FormLabel from '/components/FormLabel'; |
||||
|
import FormImage from '/components/FormImage'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Alipay({ namePrefix }) { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form.Item |
||||
|
name={`${namePrefix}-alipay`} |
||||
|
label='支付宝账号' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name={`${namePrefix}-alipayName`} |
||||
|
label='支付宝姓名' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name={`${namePrefix}-alipayImage`} |
||||
|
label='收款码' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormImage readonly width={72} height={72} /> |
||||
|
</Form.Item> */} |
||||
|
{/* <Form.Item |
||||
|
name='password' |
||||
|
label='支付密码' |
||||
|
rules={[{ required: true, message: '请输入支付密码' }]} |
||||
|
> |
||||
|
<Input type='password' placeholder='请输入支付密码' /> |
||||
|
</Form.Item> */} |
||||
|
</View > |
||||
|
) |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
.container { |
||||
|
|
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Form } from 'antd-mobile'; |
||||
|
import FormLabel from '/components/FormLabel'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function BankPay({ namePrefix }) { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form.Item |
||||
|
name={`${namePrefix}-payeeBank`} |
||||
|
label='开户行' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name={`${namePrefix}-payeeAccount`} |
||||
|
label='银行卡号' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name={`${namePrefix}-payeeName`} |
||||
|
label='开户人' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name='password' |
||||
|
label='支付密码' |
||||
|
rules={[{ required: true, message: '请输入支付密码' }]} |
||||
|
> |
||||
|
<Input type='password' placeholder='请输入支付密码' /> |
||||
|
</Form.Item> */} |
||||
|
</View > |
||||
|
) |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
.container { |
||||
|
} |
@ -0,0 +1,179 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Button, CapsuleTabs, Form, Modal, Toast } from 'antd-mobile'; |
||||
|
|
||||
|
import FormImage from '/components/FormImage'; |
||||
|
import FormLabel from '/components/FormLabel'; |
||||
|
import React, { useEffect, useMemo, useState } from 'react'; |
||||
|
import { getOrderInfoAction } from '/request/actions'; |
||||
|
import { getUrlParam } from '/utils'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
|
||||
|
// import Alipay from '../Alipay'; |
||||
|
// import Wxpay from '../Wxpay'; |
||||
|
// import BankPay from '../BankPay'; |
||||
|
|
||||
|
// import aliSrc from '/assets/icons/ali.svg'; |
||||
|
// import wxSrc from '/assets/icons/wx.svg'; |
||||
|
// import bankSrc from '/assets/icons/bank.svg'; |
||||
|
import { orderConfirmAction } from '../../../../request/actions'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
// const TabItem = ({ src, text }) => ( |
||||
|
// <View className={styles['tabitem']}> |
||||
|
// <img src={src} /> |
||||
|
// {text} |
||||
|
// </View> |
||||
|
// ); |
||||
|
|
||||
|
export default function FormBar() { |
||||
|
const [form] = Form.useForm(); |
||||
|
// const [showFee, updateShowFee] = useState(false); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
getOrderInfoAction({ |
||||
|
orderId: getUrlParam('orderId') |
||||
|
}).then(res => { |
||||
|
const orderShopInfo = res.orderShopInfo || {}; |
||||
|
const feeShopInfo = res.feeShopInfo || {}; |
||||
|
const _orderShopInfo = Object.keys(orderShopInfo).reduce((res, key) => { |
||||
|
return { |
||||
|
...res, |
||||
|
[`pay-${key}`]: orderShopInfo[key] |
||||
|
} |
||||
|
}, {}); |
||||
|
const _feeShopInfo = Object.keys(orderShopInfo).reduce((res, key) => { |
||||
|
return { |
||||
|
...res, |
||||
|
[`fee-${key}`]: feeShopInfo[key] |
||||
|
} |
||||
|
}, {}); |
||||
|
form.setFieldsValue({ |
||||
|
...res, |
||||
|
..._orderShopInfo, |
||||
|
..._feeShopInfo |
||||
|
}); |
||||
|
|
||||
|
// updateShowFee(res.feePrice || res.feeImage || res.feeShopInfo) |
||||
|
}); |
||||
|
}, []); |
||||
|
|
||||
|
const handleSubmit = () => { |
||||
|
Modal.confirm({ |
||||
|
title: '是否确认收款?', |
||||
|
onConfirm: async () => { |
||||
|
try { |
||||
|
const orderId = getUrlParam('orderId'); |
||||
|
await orderConfirmAction({ orderId }); |
||||
|
Toast.show({ |
||||
|
icon: 'success', |
||||
|
content: '已成功确认收款信息' |
||||
|
}); |
||||
|
Taro.navigateTo({ |
||||
|
url: '/pages/dataset/index' |
||||
|
}); |
||||
|
} |
||||
|
catch (err) { |
||||
|
console.log('err: ', err); |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
}; |
||||
|
|
||||
|
// const way = Form.useWatch('way', form); |
||||
|
// const feeway = Form.useWatch('feeway', form); |
||||
|
|
||||
|
// const detailRenderer = useMemo(() => { |
||||
|
// return { |
||||
|
// alipay: <Alipay namePrefix='pay' />, |
||||
|
// wx: <Wxpay namePrefix='pay' />, |
||||
|
// bank: <BankPay namePrefix='pay' /> |
||||
|
// }[way]; |
||||
|
// }, [way]); |
||||
|
|
||||
|
// const feeDetailRenderer = useMemo(() => { |
||||
|
// return { |
||||
|
// alipay: <Alipay namePrefix='fee' />, |
||||
|
// wx: <Wxpay namePrefix='fee' />, |
||||
|
// bank: <BankPay namePrefix='fee' /> |
||||
|
// }[feeway]; |
||||
|
// }, [feeway]); |
||||
|
|
||||
|
const payImage = Form.useWatch('payImage', form); |
||||
|
const feeImage = Form.useWatch('feeImage', form); |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form form={form} className={styles.form} layout='horizontal' > |
||||
|
<View className={styles.title}> |
||||
|
收款信息 |
||||
|
</View> |
||||
|
<Form.Item name='orderId' label='订单编号' childElementPosition='right'> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name='orderDate' label='订单日期' childElementPosition='right'> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name='orderPrice' label='订单金额' childElementPosition='right'> |
||||
|
<FormLabel render={val => `¥${val || 0}`} /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name='feePrice' label='服务费金额' childElementPosition='right'> |
||||
|
<FormLabel render={val => `¥${val || 0}`} /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name='payUserTelephone' label='付款账号' childElementPosition='right'> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item style={!payImage ? { display: 'none' } : {}} name='payImage' label='付款凭证' childElementPosition='right'> |
||||
|
<FormImage readonly /> |
||||
|
</Form.Item> |
||||
|
<Form.Item style={!feeImage ? { display: 'none' } : {}} name='feeImage' label='服务费凭证' childElementPosition='right'> |
||||
|
<FormImage readonly /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name='way' |
||||
|
label='提现方式' |
||||
|
valuePropName='activeKey' |
||||
|
initialValue='alipay' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<CapsuleTabs style={{ padding: 0 }}> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='支付宝' src={aliSrc} />} key='alipay' /> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='微信' src={wxSrc} />} key='wx' /> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='银行卡' src={bankSrc} />} key='bank' /> |
||||
|
</CapsuleTabs> |
||||
|
</Form.Item> |
||||
|
{detailRenderer} |
||||
|
{showFee && ( |
||||
|
<React.Fragment> |
||||
|
<View className={styles.title}> |
||||
|
服务费收款信息 |
||||
|
</View> |
||||
|
<Form.Item name='feePrice' label='服务费' childElementPosition='right'> |
||||
|
<FormLabel render={val => `¥${val || 0}`} /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name='feeImage' label='服务费付款凭证' childElementPosition='right'> |
||||
|
<FormImage readonly /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name='feeway' |
||||
|
label='提现方式' |
||||
|
valuePropName='activeKey' |
||||
|
initialValue='alipay' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<CapsuleTabs style={{ padding: 0 }}> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='支付宝' src={aliSrc} />} key='alipay' /> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='微信' src={wxSrc} />} key='wx' /> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='银行卡' src={bankSrc} />} key='bank' /> |
||||
|
</CapsuleTabs> |
||||
|
</Form.Item> |
||||
|
{feeDetailRenderer} |
||||
|
</React.Fragment> |
||||
|
)} */} |
||||
|
</Form > |
||||
|
<Button color='primary' shape='rounded' className={styles.submit} onClick={handleSubmit}> |
||||
|
确认收款 |
||||
|
</Button> |
||||
|
</View> |
||||
|
) |
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
.container { |
||||
|
background-color: #fff; |
||||
|
border-radius: 18px; |
||||
|
padding: 32px 32px 48px 32px; |
||||
|
|
||||
|
.tabitem { |
||||
|
font-size: 24px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
img { |
||||
|
width: 28px; |
||||
|
margin-right: 8px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
width: 100%; |
||||
|
margin-top: 24px; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
font-size: 28px; |
||||
|
font-weight: 600; |
||||
|
margin: 24px 0; |
||||
|
} |
||||
|
|
||||
|
.margin { |
||||
|
margin-top: 32px; |
||||
|
} |
||||
|
|
||||
|
.submit { |
||||
|
width: 100%; |
||||
|
margin-top: 72px; |
||||
|
} |
||||
|
|
||||
|
:global { |
||||
|
.adm-capsule-tabs-header { |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.adm-list-item-content-prefix { |
||||
|
width: 168px; |
||||
|
} |
||||
|
|
||||
|
.adm-capsule-tabs-tab { |
||||
|
padding: 8px; |
||||
|
border-radius: 6px; |
||||
|
border: 1px solid transparent; |
||||
|
transition: all .2s ease-in-out; |
||||
|
} |
||||
|
|
||||
|
.adm-capsule-tabs-tab-active { |
||||
|
color: var(--color-primary); |
||||
|
background-color: #f0f9ff; |
||||
|
border-color: var(--color-primary); |
||||
|
} |
||||
|
|
||||
|
.adm-list-body { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
|
||||
|
.adm-list-item { |
||||
|
padding-left: 0; |
||||
|
} |
||||
|
|
||||
|
.adm-list-item-content { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Form } from 'antd-mobile'; |
||||
|
import FormLabel from '/components/FormLabel'; |
||||
|
import FormImage from '/components/FormImage'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Wxpay({ namePrefix }) { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form.Item |
||||
|
name={`${namePrefix}-weixin`} |
||||
|
label='微信账号' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name={`${namePrefix}-weixinName`} |
||||
|
label='微信姓名' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name={`${namePrefix}-weixinImage`} |
||||
|
label='收款码' |
||||
|
childElementPosition='right' |
||||
|
> |
||||
|
<FormImage readonly width={72} height={72} /> |
||||
|
</Form.Item> */} |
||||
|
{/* <Form.Item |
||||
|
name='password' |
||||
|
label='支付密码' |
||||
|
rules={[{ required: true, message: '请输入支付密码' }]} |
||||
|
> |
||||
|
<Input type='password' placeholder='请输入支付密码' /> |
||||
|
</Form.Item> */} |
||||
|
</View > |
||||
|
) |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
.container { |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
export default definePageConfig({ |
||||
|
navigationBarTitleText: '确认收款', |
||||
|
usingComponents: {}, |
||||
|
}) |
@ -0,0 +1,25 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
|
||||
|
import FormBar from './components/FormBar'; |
||||
|
import { NavBar } from 'antd-mobile'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function ShopInfo() { |
||||
|
|
||||
|
const handleBack = () => { |
||||
|
Taro.navigateTo({ |
||||
|
url: '/pages/dataset/index' |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<NavBar onBack={handleBack} style={{ padding: 0 }}>确认收款</NavBar> |
||||
|
<View className={styles.wrapper}> |
||||
|
<FormBar /> |
||||
|
</View> |
||||
|
</View> |
||||
|
) |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
.container { |
||||
|
background: linear-gradient(180deg, #d7ebfa, #f5f5f5 30vh); |
||||
|
height: 100%; |
||||
|
overflow-y: auto; |
||||
|
|
||||
|
.wrapper { |
||||
|
box-sizing: border-box; |
||||
|
padding: 42px; |
||||
|
} |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
export default definePageConfig({ |
||||
|
navigationBarTitleText: '反馈', |
||||
|
usingComponents: {}, |
||||
|
}) |
@ -0,0 +1,45 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
|
||||
|
import { Button, Form, NavBar, TextArea } from 'antd-mobile'; |
||||
|
import { feedbackAction } from '../../request/actions'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Feedback() { |
||||
|
const [form] = Form.useForm(); |
||||
|
|
||||
|
const handleBack = () => { |
||||
|
Taro.navigateTo({ |
||||
|
url: '/pages/mine/index' |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const handleVery = async () => { |
||||
|
try { |
||||
|
const values = await form.validateFields(); |
||||
|
console.log('values: ', values); |
||||
|
await feedbackAction(values); |
||||
|
handleBack(); |
||||
|
} |
||||
|
catch (err) { |
||||
|
console.log('err: ', err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<NavBar onBack={handleBack} style={{ padding: 0 }}> |
||||
|
反馈 |
||||
|
</NavBar> |
||||
|
<Form form={form} className={styles.form} layout='horizontal'> |
||||
|
<Form.Item name='contents' rules={[{ required: true, message: '请填写反馈内容' }]}> |
||||
|
<TextArea placeholder='请输入反馈' autoFocus autoSize={{ minRows: 12 }} /> |
||||
|
</Form.Item> |
||||
|
<Button color='primary' shape='rounded' className={styles.submit} onClick={handleVery}> |
||||
|
提交 |
||||
|
</Button> |
||||
|
</Form > |
||||
|
</View> |
||||
|
); |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
.container { |
||||
|
background: linear-gradient(180deg, #d7ebfa, #f5f5f5 30vh); |
||||
|
height: 100%; |
||||
|
|
||||
|
.form { |
||||
|
background-color: #fff; |
||||
|
border-radius: 18px; |
||||
|
padding: 32px 32px 48px 32px; |
||||
|
width: 620px; |
||||
|
margin: 0 auto; |
||||
|
margin-top: 72px; |
||||
|
|
||||
|
:global { |
||||
|
.adm-list-body { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
|
||||
|
.adm-list-item { |
||||
|
padding-left: 0; |
||||
|
} |
||||
|
} |
||||
|
.submit { |
||||
|
width: 100%; |
||||
|
margin-top: 72px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Button, Form, Input, Toast } from 'antd-mobile'; |
||||
|
import { useState } from 'react'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
import { editPasswordAction } from '../../../../request/actions'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function FormBar() { |
||||
|
const [form] = Form.useForm(); |
||||
|
|
||||
|
const [countdown, setCountdown] = useState(60); |
||||
|
const [isCounting, setIsCounting] = useState(false); |
||||
|
|
||||
|
const sendVerificationCode = () => { |
||||
|
if (isCounting) { |
||||
|
return; |
||||
|
} |
||||
|
setIsCounting(true); |
||||
|
// Simulate sending verification code |
||||
|
console.log('Sending verification code...'); |
||||
|
const interval = setInterval(() => { |
||||
|
setCountdown(prev => { |
||||
|
if (prev <= 1) { |
||||
|
clearInterval(interval); |
||||
|
setIsCounting(false); |
||||
|
return 60; // Reset countdown |
||||
|
} |
||||
|
return prev - 1; |
||||
|
}); |
||||
|
}, 1000); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
const handleReset = async () => { |
||||
|
try { |
||||
|
const values = await form.validateFields(); |
||||
|
await editPasswordAction(values); |
||||
|
Toast.show({ |
||||
|
icon: 'success', |
||||
|
content: '密码修改成功' |
||||
|
}); |
||||
|
Taro.navigateBack(); |
||||
|
} |
||||
|
catch (err) { |
||||
|
console.log('err: ', err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form form={form} className={styles.form}> |
||||
|
<Form.Item |
||||
|
name='newPassword' |
||||
|
label='新密码' |
||||
|
rules={[ |
||||
|
{ required: true, message: '请输入密码' }, |
||||
|
{ whitespace: true, message: '请输入有效的密码' } |
||||
|
]} |
||||
|
> |
||||
|
<Input placeholder='请输入密码' /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name='repassword' |
||||
|
label='确认密码' |
||||
|
rules={[ |
||||
|
{ required: true, message: '请确认密码' }, |
||||
|
{ whitespace: true, message: '请输入有效的密码' } |
||||
|
]} |
||||
|
> |
||||
|
<Input type='password' placeholder='请确认密码' /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name='veryCode' |
||||
|
label='验证码' |
||||
|
rules={[{ required: true, message: '请输入新密码' }]} |
||||
|
extra={ |
||||
|
<View className={styles.extra} onClick={sendVerificationCode}> |
||||
|
<a>{isCounting ? `(${countdown}秒后重新获取)` : '发送验证码'}</a> |
||||
|
</View> |
||||
|
} |
||||
|
> |
||||
|
<Input |
||||
|
placeholder='请输入验证码' |
||||
|
style={{ '--text-align': 'left' }} |
||||
|
clearable |
||||
|
/> |
||||
|
</Form.Item> */} |
||||
|
</Form > |
||||
|
<Button color='primary' className={styles.submit} onClick={handleReset}>确认修改</Button> |
||||
|
</View > |
||||
|
) |
||||
|
} |
@ -0,0 +1,46 @@ |
|||||
|
.container { |
||||
|
background-color: #fff; |
||||
|
border-radius: 18px; |
||||
|
margin-top: 72px; |
||||
|
padding: 32px; |
||||
|
|
||||
|
.form { |
||||
|
:global { |
||||
|
.adm-list-body { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
|
||||
|
.adm-list-item { |
||||
|
padding-left: 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.extra { |
||||
|
color: #007AFF; |
||||
|
position: relative; |
||||
|
font-size: 24px; |
||||
|
top: 24px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.bar { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
padding: 24px 72px; |
||||
|
|
||||
|
.btn { |
||||
|
font-size: 24px; |
||||
|
flex: 1; |
||||
|
text-align: center; |
||||
|
|
||||
|
&:first-child { |
||||
|
border-right: 1px solid #eee; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.submit { |
||||
|
width: 100%; |
||||
|
margin-top: 72px; |
||||
|
} |
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { useLoad } from '@tarojs/taro'; |
||||
|
import logoSrc from '/assets/icons/logo.png'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function HeaderBar() { |
||||
|
|
||||
|
useLoad(() => { |
||||
|
console.log('Page loaded.') |
||||
|
}); |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<View className={styles.row}> |
||||
|
<View className={styles.title}> |
||||
|
Hi Weaith |
||||
|
</View> |
||||
|
<View className={styles.subtitle}> |
||||
|
欢迎您来到融易诚 |
||||
|
</View> |
||||
|
</View> |
||||
|
<View className={styles.row2}> |
||||
|
<View className={styles.item}> |
||||
|
<img src={logoSrc} className={styles.logo} alt='logo' /> |
||||
|
<View className={styles.title}> |
||||
|
融易诚 |
||||
|
</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
) |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
.container { |
||||
|
.row { |
||||
|
.title { |
||||
|
font-weight: normal; |
||||
|
overflow-wrap: normal; |
||||
|
font-size: 42px; |
||||
|
color: rgb(48, 49, 51); |
||||
|
} |
||||
|
|
||||
|
.subtitle { |
||||
|
font-weight: normal; |
||||
|
overflow-wrap: normal; |
||||
|
font-size: 32px; |
||||
|
color: rgb(48, 49, 51); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.row2 { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
|
||||
|
.item { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
margin-right: 42px; |
||||
|
|
||||
|
.title { |
||||
|
font-weight: normal; |
||||
|
overflow-wrap: normal; |
||||
|
font-size: 32px; |
||||
|
color: rgb(48, 49, 51); |
||||
|
text-align: center; |
||||
|
} |
||||
|
.logo { |
||||
|
width: 120px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
export default definePageConfig({ |
||||
|
navigationBarTitleText: '忘记密码', |
||||
|
usingComponents: {}, |
||||
|
}) |
@ -0,0 +1,34 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import Taro, { useLoad } from '@tarojs/taro'; |
||||
|
|
||||
|
import HeaderBar from './components/HeaderBar'; |
||||
|
import FormBar from './components/FormBar'; |
||||
|
import { NavBar } from 'antd-mobile'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Forget() { |
||||
|
const query = Taro.getCurrentInstance()?.router?.params; |
||||
|
|
||||
|
useLoad(() => { |
||||
|
console.log('Page loaded.') |
||||
|
}); |
||||
|
|
||||
|
const handleBack = () => { |
||||
|
Taro.navigateBack(); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
{query?.hasBack && ( |
||||
|
<NavBar onBack={handleBack} style={{ padding: 0 }}> |
||||
|
忘记密码 |
||||
|
</NavBar> |
||||
|
)} |
||||
|
<View className={styles.wrapper}> |
||||
|
<HeaderBar /> |
||||
|
<FormBar /> |
||||
|
</View> |
||||
|
</View> |
||||
|
); |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
.container { |
||||
|
background: linear-gradient(180deg, #d7ebfa, #f5f5f5 30vh); |
||||
|
height: 100%; |
||||
|
} |
||||
|
|
||||
|
.wrapper { |
||||
|
box-sizing: border-box; |
||||
|
padding: 120px 42px; |
||||
|
|
||||
|
.row { |
||||
|
.title { |
||||
|
font-weight: normal; |
||||
|
overflow-wrap: normal; |
||||
|
font-size: 42px; |
||||
|
color: rgb(48, 49, 51); |
||||
|
} |
||||
|
|
||||
|
.subtitle { |
||||
|
font-weight: normal; |
||||
|
overflow-wrap: normal; |
||||
|
font-size: 32px; |
||||
|
color: rgb(48, 49, 51); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.row2 { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
|
||||
|
.item { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
margin-right: 42px; |
||||
|
|
||||
|
.title { |
||||
|
font-weight: normal; |
||||
|
overflow-wrap: normal; |
||||
|
font-size: 32px; |
||||
|
color: rgb(48, 49, 51); |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.logo { |
||||
|
width: 120px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Form } from 'antd-mobile'; |
||||
|
import FormLabel from '/components/FormLabel'; |
||||
|
import FormImage from '/components/FormImage'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Alipay() { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form.Item |
||||
|
name='alipay' |
||||
|
label='支付宝账号' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name='alipayName' |
||||
|
label='支付宝姓名' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name='alipayImage' |
||||
|
label='收款码' |
||||
|
rules={[{ required: true, message: '请选择请码' }]} |
||||
|
> |
||||
|
<FormImage readonly width={72} height={72} /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name='password' |
||||
|
label='支付密码' |
||||
|
rules={[{ required: true, message: '请输入支付密码' }]} |
||||
|
> |
||||
|
<Input type='password' placeholder='请输入支付密码' /> |
||||
|
</Form.Item> */} |
||||
|
</View > |
||||
|
) |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
.container { |
||||
|
|
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Form } from 'antd-mobile'; |
||||
|
import FormLabel from '/components/FormLabel'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function BankPay() { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form.Item |
||||
|
name='payeeBank' |
||||
|
label='开户行' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name='payeeAccount' |
||||
|
label='银行卡号' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name='payeeName' |
||||
|
label='开户人' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name='password' |
||||
|
label='支付密码' |
||||
|
rules={[{ required: true, message: '请输入支付密码' }]} |
||||
|
> |
||||
|
<Input type='password' placeholder='请输入支付密码' /> |
||||
|
</Form.Item> */} |
||||
|
</View > |
||||
|
) |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
.container { |
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Form } from 'antd-mobile'; |
||||
|
import FormLabel from '/components/FormLabel'; |
||||
|
import FormImage from '/components/FormImage'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Wxpay() { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form.Item |
||||
|
name='weixin' |
||||
|
label='微信账号' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name='weixinName' |
||||
|
label='微信姓名' |
||||
|
> |
||||
|
<FormLabel /> |
||||
|
</Form.Item> |
||||
|
<Form.Item |
||||
|
name='weixinImage' |
||||
|
label='收款码' |
||||
|
> |
||||
|
<FormImage readonly width={72} height={72} /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name='password' |
||||
|
label='支付密码' |
||||
|
rules={[{ required: true, message: '请输入支付密码' }]} |
||||
|
> |
||||
|
<Input type='password' placeholder='请输入支付密码' /> |
||||
|
</Form.Item> */} |
||||
|
</View > |
||||
|
) |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
.container { |
||||
|
} |
@ -0,0 +1,123 @@ |
|||||
|
import { useState } from 'react'; |
||||
|
import cls from 'classnames'; |
||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Button, Form, Input, Popup, Toast } from 'antd-mobile'; |
||||
|
|
||||
|
// import Alipay from './Alipay'; |
||||
|
// import Wxpay from './Wxpay'; |
||||
|
// import BankPay from './BankPay'; |
||||
|
|
||||
|
// import aliSrc from '/assets/icons/ali.svg'; |
||||
|
// import wxSrc from '/assets/icons/wx.svg'; |
||||
|
// import bankSrc from '/assets/icons/bank.svg'; |
||||
|
|
||||
|
import FormLabel from '/components/FormLabel'; |
||||
|
|
||||
|
import { getShopInfoAction, userWithdrawalAction } from '../../../../request/actions'; |
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
// const TabItem = ({ src, text }) => ( |
||||
|
// <View className={styles['tabitem']}> |
||||
|
// <img src={src} /> |
||||
|
// {text} |
||||
|
// </View> |
||||
|
// ); |
||||
|
|
||||
|
const Balance = ({ balanceData, className, onAfterClose }) => { |
||||
|
const prefix = cls(styles.container, className); |
||||
|
const [visible, setVisible] = useState(false); |
||||
|
const [form] = Form.useForm(); |
||||
|
|
||||
|
const onShow = () => { |
||||
|
setVisible(true); |
||||
|
// 商铺收款信息 |
||||
|
getShopInfoAction().then(res => { |
||||
|
form.setFieldsValue(res); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const onClose = () => { |
||||
|
setVisible(false); |
||||
|
onAfterClose(); |
||||
|
setTimeout(() => { |
||||
|
form.resetFields(); |
||||
|
}, 200); |
||||
|
}; |
||||
|
|
||||
|
const handleWithdrawal = async () => { |
||||
|
try { |
||||
|
const values = await form.validateFields(); |
||||
|
const cash = values.cash; |
||||
|
await userWithdrawalAction({ cash }); |
||||
|
Toast.show({ |
||||
|
content: '您已提现成功' |
||||
|
}); |
||||
|
onClose(); |
||||
|
} |
||||
|
catch (err) { |
||||
|
console.log('err: ', err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// const way = Form.useWatch('way', form); |
||||
|
|
||||
|
// const detailRenderer = useMemo(() => { |
||||
|
// return { |
||||
|
// alipay: <Alipay />, |
||||
|
// wx: <Wxpay />, |
||||
|
// bank: <BankPay /> |
||||
|
// }[way]; |
||||
|
// }, [way]); |
||||
|
|
||||
|
const balance = balanceData?.balance || '0.00'; |
||||
|
|
||||
|
return ( |
||||
|
<View className={prefix}> |
||||
|
<View className={styles.title}>账户余额</View> |
||||
|
<View className={styles.subtitle}>¥{balance}</View> |
||||
|
<Button color='primary' className={styles.btn} onClick={onShow}>提现</Button> |
||||
|
<Popup |
||||
|
visible={visible} |
||||
|
onMaskClick={onClose} |
||||
|
bodyClassName={styles['popup-wrapper']} |
||||
|
> |
||||
|
<Form form={form} className={styles.popup} layout='horizontal'> |
||||
|
<View className={styles.balance}> |
||||
|
<FormLabel value={balance} render={val => `当前可用提现余额¥${val}`} /> |
||||
|
</View> |
||||
|
<Form.Item |
||||
|
name='cash' |
||||
|
label='提现金额' |
||||
|
// extra={`当前可用提现余额¥${balance}`} |
||||
|
rules={[{ required: true, message: '请输入提现金额' }]} |
||||
|
> |
||||
|
<Input className={styles.cash} type='number' min={0} max={9999999999} placeholder='请输入提现金额' /> |
||||
|
</Form.Item> |
||||
|
{/* <Form.Item |
||||
|
name='way' |
||||
|
label='提现方式' |
||||
|
valuePropName='activeKey' |
||||
|
initialValue='alipay' |
||||
|
> |
||||
|
<CapsuleTabs style={{ padding: 0 }}> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='支付宝' src={aliSrc} />} key='alipay' /> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='微信' src={wxSrc} />} key='wx' /> |
||||
|
<CapsuleTabs.Tab title={<TabItem text='银行卡' src={bankSrc} />} key='bank' /> |
||||
|
</CapsuleTabs> |
||||
|
</Form.Item> |
||||
|
{detailRenderer} */} |
||||
|
<Button |
||||
|
className={styles.btn} |
||||
|
color='primary' |
||||
|
shape='rounded' |
||||
|
onClick={handleWithdrawal} |
||||
|
> |
||||
|
确认提现 |
||||
|
</Button> |
||||
|
</Form> |
||||
|
</Popup> |
||||
|
</View> |
||||
|
) |
||||
|
}; |
||||
|
|
||||
|
export default Balance; |
@ -0,0 +1,98 @@ |
|||||
|
.container { |
||||
|
background-color: #fff; |
||||
|
border-radius: 18px; |
||||
|
padding: 32px; |
||||
|
|
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
|
||||
|
.title { |
||||
|
font-size: 28px; |
||||
|
font-weight: 600; |
||||
|
margin-bottom: 24px; |
||||
|
} |
||||
|
|
||||
|
.subtitle { |
||||
|
font-size: 42px; |
||||
|
font-weight: 600; |
||||
|
margin-bottom: 24px; |
||||
|
color: var(--color-primary); |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
width: 380px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.popup-wrapper { |
||||
|
height: 480px; |
||||
|
} |
||||
|
|
||||
|
.balance { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
margin: 48px 0 24px; |
||||
|
} |
||||
|
|
||||
|
.popup { |
||||
|
padding: 24px; |
||||
|
|
||||
|
.tabitem { |
||||
|
font-size: 24px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
img { |
||||
|
width: 28px; |
||||
|
margin-right: 8px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
width: 100%; |
||||
|
margin-top: 24px; |
||||
|
} |
||||
|
|
||||
|
:global { |
||||
|
.adm-capsule-tabs-header { |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.adm-capsule-tabs-tab { |
||||
|
padding: 8px 20px; |
||||
|
border-radius: 6px; |
||||
|
border: 1px solid transparent; |
||||
|
transition: all .2s ease-in-out; |
||||
|
} |
||||
|
|
||||
|
.adm-capsule-tabs-tab-active { |
||||
|
color: var(--color-primary); |
||||
|
background-color: #f0f9ff; |
||||
|
border-color: var(--color-primary); |
||||
|
} |
||||
|
|
||||
|
.adm-list-item { |
||||
|
padding: 32px 0; |
||||
|
} |
||||
|
|
||||
|
.adm-form-item-label { |
||||
|
font-size: 28px; |
||||
|
position: relative; |
||||
|
top: 12px; |
||||
|
} |
||||
|
.adm-input-element { |
||||
|
font-size: 42px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
:global { |
||||
|
.adm-list-default .adm-list-body { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
.adm-list-item-content { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
import React from 'react'; |
||||
|
import { List, Empty, Tag } from 'antd-mobile'; |
||||
|
import { Text, View } from '@tarojs/components'; |
||||
|
import cls from 'classnames'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
const DataList = ({ dataSource = [], className }) => { |
||||
|
const prefix = cls(styles.container, className); |
||||
|
|
||||
|
return ( |
||||
|
<View className={prefix}> |
||||
|
<View className={styles.title}>交易记录</View> |
||||
|
{dataSource.length > 0 ? ( |
||||
|
<List> |
||||
|
{dataSource.map((item, index) => ( |
||||
|
<List.Item key={index}> |
||||
|
<View className={styles.row}> |
||||
|
<View className={styles.left}> |
||||
|
<Tag className={styles.status} color={item.isIn ? 'primary' : 'warning'}>{item.isIn ? '入账' : '出账'}</Tag> |
||||
|
{item.cash} |
||||
|
</View> |
||||
|
<Text className={styles.tag} color='default'>{item.remark}</Text> |
||||
|
</View> |
||||
|
</List.Item> |
||||
|
))} |
||||
|
</List> |
||||
|
) : ( |
||||
|
<Empty |
||||
|
style={{ padding: '64px 0' }} |
||||
|
description='暂无数据' |
||||
|
/> |
||||
|
)} |
||||
|
</View> |
||||
|
) |
||||
|
}; |
||||
|
|
||||
|
export default DataList; |
@ -0,0 +1,44 @@ |
|||||
|
.container { |
||||
|
background-color: #fff; |
||||
|
border-radius: 18px; |
||||
|
padding: 32px; |
||||
|
margin-top: 24px; |
||||
|
|
||||
|
.title { |
||||
|
font-size: 28px; |
||||
|
font-weight: 600; |
||||
|
margin-bottom: 24px; |
||||
|
} |
||||
|
|
||||
|
.row { |
||||
|
width: 100%; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
|
||||
|
.left { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
font-size: 24px; |
||||
|
|
||||
|
.status { |
||||
|
margin-right: 12px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tag { |
||||
|
font-size: 24px; |
||||
|
} |
||||
|
|
||||
|
&:not(:last-child) { |
||||
|
border-bottom: 1px solid #eee; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
:global { |
||||
|
.adm-list-default .adm-list-body { |
||||
|
border: unset; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
export default definePageConfig({ |
||||
|
navigationBarTitleText: '资产管理', |
||||
|
usingComponents: {}, |
||||
|
}) |
@ -0,0 +1,77 @@ |
|||||
|
import { useState } from 'react'; |
||||
|
import { View, ScrollView } from '@tarojs/components'; |
||||
|
import Taro, { useLoad } from '@tarojs/taro'; |
||||
|
import { NavBar, PullToRefresh } from 'antd-mobile'; |
||||
|
|
||||
|
import DataList from './components/DataList'; |
||||
|
import Balance from './components/Balance'; |
||||
|
import { myBalanceAction, userWalletLogListLoopAction } from '../../request/actions'; |
||||
|
import useRequestList from '../../hooks/useRequestList'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
const fetchDataRecursively = async (times, datasource) => { |
||||
|
if (times <= 0 || (datasource && datasource?.length < 10)) { |
||||
|
return []; |
||||
|
} |
||||
|
const lastLogId = datasource?.[datasource?.length - 1]?.logId; |
||||
|
const result = await userWalletLogListLoopAction({ lastLogId }); |
||||
|
const nextResults = await fetchDataRecursively(times - 1, result?.dataList); |
||||
|
return [...result?.dataList, ...nextResults]; |
||||
|
}; |
||||
|
|
||||
|
export default function Funds() { |
||||
|
const [data, setData] = useState([]); |
||||
|
|
||||
|
// 银行卡余额 |
||||
|
const { data: balanceData, getDataTask: getBananceData } = useRequestList({ |
||||
|
immediate: false, |
||||
|
showMsg: false, |
||||
|
action: myBalanceAction |
||||
|
}); |
||||
|
|
||||
|
const handleInitData = async () => { |
||||
|
getBananceData(); |
||||
|
const dataSource = await fetchDataRecursively(2); |
||||
|
setData(dataSource); |
||||
|
}; |
||||
|
|
||||
|
useLoad(() => { |
||||
|
handleInitData(); |
||||
|
}); |
||||
|
|
||||
|
const handleBack = () => { |
||||
|
Taro.navigateTo({ |
||||
|
url: '/pages/mine/index' |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const handleScrollToLower = async () => { |
||||
|
const lastLogId = data?.[data?.length - 1]?.logId; |
||||
|
const result = await userWalletLogListLoopAction({ lastLogId }); |
||||
|
const newDataSource = result?.dataList; |
||||
|
setData([...data, ...newDataSource]); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<NavBar onBack={handleBack} style={{ padding: 0 }}> |
||||
|
资金管理 |
||||
|
</NavBar> |
||||
|
<PullToRefresh |
||||
|
onRefresh={handleInitData} |
||||
|
> |
||||
|
<ScrollView |
||||
|
scrollY |
||||
|
onScrollToLower={handleScrollToLower} |
||||
|
lowerThreshold={50} |
||||
|
> |
||||
|
<View className={styles.wrapper}> |
||||
|
<Balance balanceData={balanceData} onAfterClose={handleInitData} /> |
||||
|
<DataList className={styles.list} dataSource={data} /> |
||||
|
</View> |
||||
|
</ScrollView> |
||||
|
</PullToRefresh> |
||||
|
</View> |
||||
|
) |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
.container { |
||||
|
background: linear-gradient(180deg, #d7ebfa, #f5f5f5 30vh); |
||||
|
height: 100%; |
||||
|
|
||||
|
.wrapper { |
||||
|
box-sizing: border-box; |
||||
|
padding: 42px; |
||||
|
height: calc(100vh - 82px); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
|
||||
|
import { View, Swiper, SwiperItem, Image } from '@tarojs/components'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Banner({ |
||||
|
swiperList = [] |
||||
|
}) { |
||||
|
if (swiperList.length === 0) { |
||||
|
return <View className={styles.container} style={{ background: '#eee' }}></View> |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<Swiper |
||||
|
className={styles.container} |
||||
|
indicatorColor='#999' |
||||
|
indicatorActiveColor='#007AFF' |
||||
|
circular |
||||
|
indicatorDots |
||||
|
autoplay |
||||
|
> |
||||
|
{swiperList.map((bannerSrc, index) => ( |
||||
|
<SwiperItem key={index}> |
||||
|
<Image style={{ width: '100%' }} src={bannerSrc} mode='aspectFit' /> |
||||
|
</SwiperItem> |
||||
|
))} |
||||
|
</Swiper> |
||||
|
) |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
|
||||
|
.container { |
||||
|
margin-top: 36px; |
||||
|
height: 328px; |
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { NoticeBar } from 'antd-mobile'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
|
||||
|
import logoSrc from '/assets/icons/logo.png'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Header({ |
||||
|
noticeTitle |
||||
|
}) { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.header}> |
||||
|
<View className={styles.left}> |
||||
|
<img src={logoSrc} className={styles.logo} alt='logo' /> |
||||
|
<View className={styles.title}> |
||||
|
融易诚 |
||||
|
</View> |
||||
|
</View> |
||||
|
{noticeTitle && ( |
||||
|
<NoticeBar |
||||
|
content={noticeTitle} |
||||
|
color='alert' |
||||
|
style={{ width: 206, height: 32, padding: '0 8px', color: 'red', background: '#f5f5f5' }} |
||||
|
shape='rounded' |
||||
|
bordered={false} |
||||
|
onClick={() => Taro.navigateTo({ url: '/pages/notice/index' })} |
||||
|
/> |
||||
|
)} |
||||
|
</View> |
||||
|
); |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
.header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
|
||||
|
.left { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.logo { |
||||
|
width: 68px; |
||||
|
margin-right: 12px; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
font-size: 28px; |
||||
|
font-weight: 500; |
||||
|
color: #333; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
|
||||
|
import { ExclamationCircleFill } from 'antd-mobile-icons' |
||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Button } from 'antd-mobile'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
import logoSrc from '/assets/icons/logo.png'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
const MyShop = () => { |
||||
|
|
||||
|
const handleVery = () => { |
||||
|
Taro.navigateTo({ |
||||
|
url: '/pages/shopinfo/index' |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<View className={styles.title}> |
||||
|
<img src={logoSrc} className={styles.logo} alt='logo' /> |
||||
|
<View className={styles.title}> |
||||
|
我的小店 |
||||
|
</View> |
||||
|
</View> |
||||
|
<View className={styles.card}> |
||||
|
<View className={styles.title}> |
||||
|
完成考试 帮您开启成功之路 |
||||
|
</View> |
||||
|
<View className={styles.info}> |
||||
|
<View className={styles.left}> |
||||
|
<ExclamationCircleFill className={styles.icon} /> |
||||
|
<View> |
||||
|
<View className={styles.title}>店铺认证</View> |
||||
|
<View className={styles.subtitle}>请完成店铺认证以开启完整功能</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
<Button |
||||
|
className={styles.btn} |
||||
|
color='primary' |
||||
|
shape='rounded' |
||||
|
size='small' |
||||
|
onClick={handleVery} |
||||
|
> |
||||
|
立即认证 |
||||
|
</Button> |
||||
|
</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default MyShop; |
@ -0,0 +1,70 @@ |
|||||
|
.container { |
||||
|
background: linear-gradient(180deg, #1677ff, #fff 30vh); |
||||
|
padding: 24px; |
||||
|
border-radius: 12px; |
||||
|
margin-top: 32px; |
||||
|
|
||||
|
.title { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.logo { |
||||
|
width: 98px; |
||||
|
margin-right: 12px; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
font-size: 28px; |
||||
|
font-weight: 500; |
||||
|
color: #fff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.card { |
||||
|
padding: 18px 24px; |
||||
|
border-radius: 12px; |
||||
|
background-color: #fff; |
||||
|
margin-top: 18px; |
||||
|
|
||||
|
.title { |
||||
|
font-size: 28px; |
||||
|
font-weight: 500; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.info { |
||||
|
margin-top: 18px; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
|
||||
|
.left { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.icon { |
||||
|
color: rgb(255, 0, 0); |
||||
|
font-size: 42px; |
||||
|
margin-right: 18px; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
font-size: 24px; |
||||
|
color: #333; |
||||
|
font-weight: bolder; |
||||
|
} |
||||
|
.subtitle { |
||||
|
font-size: 22px; |
||||
|
color: #999; |
||||
|
margin-top: 4px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
font-size: 24px; |
||||
|
padding: 0px 18px; |
||||
|
height: 48px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
|
||||
|
import { View, Text } from '@tarojs/components'; |
||||
|
import { List } from 'antd-mobile'; |
||||
|
import { FileOutline } from 'antd-mobile-icons'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
const TodoList = () => { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<View className={styles.title}> |
||||
|
<Text className={styles.text}>今日任务</Text> |
||||
|
</View> |
||||
|
<List className={styles.list}> |
||||
|
<List.Item prefix={<FileOutline />} onClick={() => { }}> |
||||
|
1、完成店铺认证 |
||||
|
</List.Item> |
||||
|
<List.Item prefix={<FileOutline />} onClick={() => { }}> |
||||
|
2、完成信用优化 |
||||
|
</List.Item> |
||||
|
<List.Item prefix={<FileOutline />} onClick={() => { }}> |
||||
|
3、完成店铺认证 |
||||
|
</List.Item> |
||||
|
</List> |
||||
|
</View> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default TodoList; |
@ -0,0 +1,30 @@ |
|||||
|
.container { |
||||
|
padding: 24px; |
||||
|
border-radius: 12px; |
||||
|
background-color: #fff; |
||||
|
margin-top: 24px; |
||||
|
|
||||
|
.title { |
||||
|
.text { |
||||
|
font-size: 28px; |
||||
|
font-weight: 500; |
||||
|
color: #333; |
||||
|
padding: 12px 0; |
||||
|
border-bottom: 4px solid #007AFF; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.list { |
||||
|
margin-top: 18px; |
||||
|
|
||||
|
>* { |
||||
|
font-size: 28px !important; |
||||
|
} |
||||
|
|
||||
|
:global { |
||||
|
.adm-list-item { |
||||
|
// padding-left: unset; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
|
||||
|
import { ExclamationCircleFill } from 'antd-mobile-icons' |
||||
|
import { View, Text } from '@tarojs/components'; |
||||
|
import styles from './index.module.less'; |
||||
|
import { Button } from 'antd-mobile'; |
||||
|
|
||||
|
import { AddCircleOutline, TeamFill, RedoOutline } from 'antd-mobile-icons'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
|
||||
|
const Toolbar = () => { |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<View className={styles.card} onClick={() => Taro.navigateTo({ url: '/pages/dataset/index' })}> |
||||
|
<AddCircleOutline className={styles.icon} style={{ color: '#007AFF' }} /> |
||||
|
<View>数据优化</View> |
||||
|
</View> |
||||
|
<View className={styles.card} onClick={() => Taro.navigateTo({ url: '/pages/team/index' })}> |
||||
|
<TeamFill className={styles.icon} style={{ color: 'rgb(114, 46, 209)' }} /> |
||||
|
<View>团队矩阵</View> |
||||
|
</View> |
||||
|
<View className={styles.card} onClick={() => Taro.navigateTo({ url: '/pages/invite/index' })}> |
||||
|
<RedoOutline className={styles.icon} style={{ color: 'rgb(82, 196, 26)' }} /> |
||||
|
<View>邀请商户</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default Toolbar; |
@ -0,0 +1,29 @@ |
|||||
|
.container { |
||||
|
padding: 8px 24px; |
||||
|
border-radius: 12px; |
||||
|
background-color: #fff; |
||||
|
margin-top: 24px; |
||||
|
|
||||
|
display: flex; |
||||
|
justify-content: space-around; |
||||
|
|
||||
|
.card { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
padding: 12px; |
||||
|
|
||||
|
transition: all .2s ease-in-out; |
||||
|
|
||||
|
&:active { |
||||
|
background-color: #fafafa; |
||||
|
border-radius: 12px; |
||||
|
} |
||||
|
|
||||
|
.icon { |
||||
|
font-size: 48px; |
||||
|
margin-bottom: 12px; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
export default definePageConfig({ |
||||
|
navigationBarTitleText: '首页', |
||||
|
usingComponents: {}, |
||||
|
}) |
@ -0,0 +1,58 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import Header from './components/Header'; |
||||
|
import Banner from './components/Banner'; |
||||
|
import MyShop from './components/MyShop'; |
||||
|
import Toolbar from './components/Toolbar'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
|
||||
|
import TodoList from './components/TodoList'; |
||||
|
import useRequestList from '../../hooks/useRequestList'; |
||||
|
import { getIndexPageAction } from '../../request/actions'; |
||||
|
import { useEffect } from 'react'; |
||||
|
import { Modal } from 'antd-mobile'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Index() { |
||||
|
const { data } = useRequestList({ |
||||
|
action: getIndexPageAction |
||||
|
}); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (!data) { |
||||
|
return; |
||||
|
} |
||||
|
if (data?.systemMessage && data?.systemMessage?.messageId !== localStorage.getItem('messageId')) { |
||||
|
let handler = null; |
||||
|
handler = Modal.show({ |
||||
|
title: '有新的站内新,点击查看详情', |
||||
|
showCloseButton: false, |
||||
|
actions: [ |
||||
|
{ |
||||
|
key: 'view', |
||||
|
text: '查看站内信', |
||||
|
}, |
||||
|
], |
||||
|
onAction: action => { |
||||
|
if (action.key === 'view') { |
||||
|
Taro.navigateTo({ |
||||
|
url: '/pages/sitemessage/index' |
||||
|
}); |
||||
|
localStorage.setItem('messageId', data.systemMessage?.messageId); |
||||
|
handler.close(); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}, [data]); |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Header {...data} /> |
||||
|
<Banner {...data} /> |
||||
|
<MyShop {...data} /> |
||||
|
<Toolbar {...data} /> |
||||
|
<TodoList {...data} /> |
||||
|
</View> |
||||
|
) |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
|
||||
|
.container { |
||||
|
background: linear-gradient(180deg, #d7ebfa, #f5f5f5 30vh); |
||||
|
height: 100%; |
||||
|
box-sizing: border-box; |
||||
|
padding: 24px 24px; |
||||
|
} |
@ -0,0 +1,88 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Button, Divider, Form } from 'antd-mobile'; |
||||
|
|
||||
|
import { useEffect, useRef } from 'react'; |
||||
|
import { QRCodeCanvas } from 'qrcode.react'; |
||||
|
import { CopyToClipboard } from 'react-copy-to-clipboard'; |
||||
|
import { useLocalStorageState } from 'ahooks'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
const FormUser = ({ value }) => ( |
||||
|
<View className={styles.user}> |
||||
|
<View className={styles.logo}> |
||||
|
1 |
||||
|
</View> |
||||
|
<View className={styles.phone}> |
||||
|
{value} |
||||
|
</View> |
||||
|
</View> |
||||
|
); |
||||
|
|
||||
|
const FormCopyText = ({ value }) => ( |
||||
|
<View className={styles.copy}> |
||||
|
<View className={styles.text}>{value}</View> |
||||
|
<CopyToClipboard text={value}><a>复制</a></CopyToClipboard> |
||||
|
</View> |
||||
|
); |
||||
|
|
||||
|
const QRCode = ({ value }) => { |
||||
|
const ref = useRef(); |
||||
|
|
||||
|
const handleDownload = () => { |
||||
|
const canvas = ref.current; |
||||
|
if (canvas) { |
||||
|
const imageURL = canvas.toDataURL('image/png'); // 转换为图片数据 |
||||
|
const link = document.createElement('a'); |
||||
|
link.href = imageURL; |
||||
|
link.download = '邀请码.png'; |
||||
|
link.click(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.qrcode}> |
||||
|
<QRCodeCanvas value={value} ref={ref} /> |
||||
|
<Button className={styles.btn} color='primary' shape='default' onClick={handleDownload}> |
||||
|
下载 |
||||
|
</Button> |
||||
|
</View> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default function FormBar() { |
||||
|
const [form] = Form.useForm(); |
||||
|
const [storage] = useLocalStorageState('userInfo'); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
const origin = window.location.origin; |
||||
|
const invite_code = storage?.shareCode; |
||||
|
const invite_url = `${origin}/#/pages/register/index?shareCode=${invite_code}`; |
||||
|
form.setFieldsValue({ |
||||
|
user_info: storage?.telephone, |
||||
|
qrcode: invite_url, |
||||
|
invite_code, |
||||
|
invite_url |
||||
|
}); |
||||
|
}, []); |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form form={form} className={styles.form} layout='vertical'> |
||||
|
<Form.Item name='user_info'> |
||||
|
<FormUser /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name='qrcode' style={{ display: 'flex', justifyContent: 'center' }}> |
||||
|
<QRCode /> |
||||
|
</Form.Item> |
||||
|
<Divider /> |
||||
|
<Form.Item name='invite_code' label='我的邀请码'> |
||||
|
<FormCopyText /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name='invite_url' label='邀请链接'> |
||||
|
<FormCopyText /> |
||||
|
</Form.Item> |
||||
|
</Form > |
||||
|
</View> |
||||
|
) |
||||
|
} |
@ -0,0 +1,80 @@ |
|||||
|
.container { |
||||
|
background-color: #fff; |
||||
|
border-radius: 18px; |
||||
|
margin-top: 72px; |
||||
|
padding: 32px 32px 48px 32px; |
||||
|
|
||||
|
.form { |
||||
|
:global { |
||||
|
.adm-list-body { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
|
||||
|
.adm-list-item { |
||||
|
padding-left: 0; |
||||
|
} |
||||
|
|
||||
|
.adm-list-item-content { |
||||
|
border: unset; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.user { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.logo { |
||||
|
width: 72px; |
||||
|
height: 72px; |
||||
|
border-radius: 50%; |
||||
|
background-color: pink; |
||||
|
font-size: 42px; |
||||
|
color: #fff; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
margin-right: 18px; |
||||
|
} |
||||
|
|
||||
|
.phone { |
||||
|
font-weight: 700; |
||||
|
font-size: 32px; |
||||
|
margin-bottom: 4px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.qrcode { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
|
||||
|
.btn { |
||||
|
width: 100%; |
||||
|
margin-top: 24px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.copy { |
||||
|
display: flex; |
||||
|
background-color: #f8f8f8; |
||||
|
padding: 12px; |
||||
|
border-radius: 2px; |
||||
|
font-size: 24px; |
||||
|
|
||||
|
.text { |
||||
|
flex: 1; |
||||
|
word-break: break-all; |
||||
|
margin-right: 24px; |
||||
|
} |
||||
|
|
||||
|
a { |
||||
|
flex-basis: 72px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.submit { |
||||
|
width: 100%; |
||||
|
margin-top: 72px; |
||||
|
} |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
export default definePageConfig({ |
||||
|
navigationBarTitleText: '店铺信息', |
||||
|
usingComponents: {}, |
||||
|
}) |
@ -0,0 +1,31 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import Taro, { useLoad } from '@tarojs/taro'; |
||||
|
|
||||
|
import FormBar from './components/FormBar'; |
||||
|
import { NavBar } from 'antd-mobile'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function Invite() { |
||||
|
|
||||
|
useLoad(() => { |
||||
|
console.log('Page loaded.') |
||||
|
}); |
||||
|
|
||||
|
const handleBack = () => { |
||||
|
Taro.navigateTo({ |
||||
|
url: '/pages/index/index' |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<NavBar onBack={handleBack} style={{ padding: 0 }}> |
||||
|
邀请商户 |
||||
|
</NavBar> |
||||
|
<View className={styles.wrapper}> |
||||
|
<FormBar /> |
||||
|
</View> |
||||
|
</View> |
||||
|
); |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
.container { |
||||
|
background: linear-gradient(180deg, #d7ebfa, #f5f5f5 30vh); |
||||
|
height: 100%; |
||||
|
|
||||
|
.wrapper { |
||||
|
box-sizing: border-box; |
||||
|
padding: 42px; |
||||
|
} |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { Button, Form, Input } from 'antd-mobile'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
import { loginAction } from '../../../../request/actions'; |
||||
|
import { useLocalStorageState } from 'ahooks'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function FormBar() { |
||||
|
const [form] = Form.useForm(); |
||||
|
const [, updateStorage] = useLocalStorageState('userInfo', {defaultValue: null}); |
||||
|
|
||||
|
const handleLogin = async () => { |
||||
|
try { |
||||
|
const values = await form.validateFields(); |
||||
|
const data = await loginAction(values); |
||||
|
updateStorage(data); |
||||
|
Taro.navigateTo({ url: '/pages/index/index' }); |
||||
|
} |
||||
|
catch (err) { |
||||
|
console.log('err: ', err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<Form form={form} className={styles.form}> |
||||
|
<Form.Item name='telephone' label='账号' rules={[{ required: true, message: '请输入手机号或电子邮箱' }]}> |
||||
|
<Input placeholder='请输入手机号或电子邮箱' /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name='password' label='密码' rules={[{ required: true, message: '请输入密码' }]}> |
||||
|
<Input type='password' placeholder='请输入密码' /> |
||||
|
</Form.Item> |
||||
|
</Form> |
||||
|
<Button color='primary' className={styles.submit} onClick={handleLogin}>登录</Button> |
||||
|
<View className={styles.bar}> |
||||
|
<View className={styles.btn} onClick={() => Taro.navigateTo({ url: '/pages/register/index' })}>注册</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
) |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
.container { |
||||
|
background-color: #fff; |
||||
|
border-radius: 18px; |
||||
|
margin-top: 72px; |
||||
|
padding: 32px 32px 0 32px; |
||||
|
|
||||
|
.form { |
||||
|
:global { |
||||
|
.adm-list-body { |
||||
|
border-top: unset; |
||||
|
} |
||||
|
.adm-list-item { |
||||
|
padding-left: 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.bar { |
||||
|
display: flex; |
||||
|
justify-content: space-around; |
||||
|
padding: 24px 72px; |
||||
|
|
||||
|
.btn { |
||||
|
font-size: 24px; |
||||
|
flex: 1; |
||||
|
text-align: center; |
||||
|
|
||||
|
&:first-child { |
||||
|
border-right: 1px solid #eee; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.submit { |
||||
|
width: 100%; |
||||
|
margin-top: 72px; |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
import { View } from '@tarojs/components'; |
||||
|
import { useLoad } from '@tarojs/taro'; |
||||
|
|
||||
|
import logoSrc from '/assets/icons/logo.png'; |
||||
|
|
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
export default function HeaderBar() { |
||||
|
|
||||
|
useLoad(() => { |
||||
|
console.log('Page loaded.') |
||||
|
}); |
||||
|
|
||||
|
return ( |
||||
|
<View className={styles.container}> |
||||
|
<View className={styles.row}> |
||||
|
<View className={styles.title}> |
||||
|
Hi Weaith |
||||
|
</View> |
||||
|
<View className={styles.subtitle}> |
||||
|
欢迎您来到融易诚 |
||||
|
</View> |
||||
|
</View> |
||||
|
<View className={styles.row2}> |
||||
|
<View className={styles.item}> |
||||
|
<img src={logoSrc} className={styles.logo} alt='logo' /> |
||||
|
<View className={styles.title}> |
||||
|
融易诚 |
||||
|
</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
) |
||||
|
} |