first commit

This commit is contained in:
编码猿
2024-09-27 01:32:49 +08:00
commit 28ebe05a64
7399 changed files with 1174529 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

19
滴滴淘/admin/.gitignore vendored Normal file
View File

@@ -0,0 +1,19 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json
# production
/dist
# misc
.DS_Store
# umi
/src/.umi/
/.env.local
.idea/

View File

@@ -0,0 +1,8 @@
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test

View File

@@ -0,0 +1,11 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}

1
滴滴淘/admin/.pydio Normal file
View File

@@ -0,0 +1 @@
88784dfd-cc7d-4b7a-b129-d513c5f0288f

74
滴滴淘/admin/.umirc.ts Normal file
View File

@@ -0,0 +1,74 @@
import path from 'path';
import { defineConfig } from 'umi';
import routes from './src/routes/index';
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
// 开启分包
// dynamicImport: {
// loading: resolve('src/components/loading/loading.tsx'),
// },
publicPath: './',
history: { type: 'hash' },
// 启动自定义配置
runtimePublicPath: true,
// 开启dva模式
dva: {},
routes: routes,
// 目录别名方便引入
alias: {
'@service': resolve('src/core/service/imp'),
'@assets': resolve('src/assets'),
'@components': resolve('src/components'),
'@page': resolve('src/assets/less/page'),
'@annotation': resolve('src/core/annotation'),
'@Ioc': resolve('src/core/Ioc'),
},
// 额外的css
styles: [`.selectOption .ant-select-item-option-content { word-wrap: break-word; white-space: normal;}`],
// 需要兼容的最低版本
targets: { chrome: 49, firefox: 64, safari: 10, edge: 13, ios: 10 },
// proxy: {
// "/api": {
// "target": "https://pvp.qq.com",
// "changeOrigin": true,
// "pathRewrite": { "^/api": "" }
// }
// }
plugins: ['@alitajs/hd'],
// 开启rem配置参考https://github.com/alitajs/alita/tree/master/packages/hd#readme或者看声明文件中的参数
// hd: {
// rootValue: 75,
// propBlackList: [], //不需要转换的属性
// selectorBlackList: [], //以包含***的class不需要转换
// },
extraPostCSSPlugins: [],
// 提取公共依赖
// chainWebpack: function (config, { webpack }) {
// config.merge({
// optimization: {
// minimize: true,
// splitChunks: {
// chunks: 'all',
// minSize: 30000,
// minChunks: 3,
// automaticNameDelimiter: '.',
// cacheGroups: {
// vendor: {
// name: 'vendors',
// test({ resource }) {
// return /[\\/]node_modules[\\/]/.test(resource);
// },
// priority: 10,
// },
// },
// },
// }
// });
// },
});
function resolve(dir: string) {
return path.join(__dirname, dir);
}

14
滴滴淘/admin/README.md Normal file
View File

@@ -0,0 +1,14 @@
#shop-pc
总任务佣金 = 任务基础佣金 + 附加项
附加项 = 输入百分比 * 任务总数[计划单数相加之和] * 佣金 6个相加
1单*10%*10=0.3元
1单 = 买家入口单数总和
参与此行为人数为10人 = 总单数 * 输入百分比
财务管理: 资金流水finance/recordList提现记录申请体现

View File

View File

@@ -0,0 +1 @@
456a5e35-674f-47ee-954f-33d84698065d

View File

@@ -0,0 +1,9 @@
export default {
// 支持值为 Object 和 Array
'GET /api/getUser': { users: [1, 2] },
// GET 可忽略
'/api/users/1': { id: 1 },
// GET 可忽略
'GET /api/login': { token: 'asdadadasddddddddddasdad' },
};

View File

@@ -0,0 +1,35 @@
{
"private": true,
"scripts": {
"start": "umi dev",
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
]
},
"dependencies": {
"@alitajs/hd": "^2.3.9",
"copy-to-clipboard": "^3.3.1",
"@umijs/preset-react": "1.x",
"@umijs/test": "^3.1.0",
"axios": "^0.19.2",
"lint-staged": "^10.0.7",
"prettier": "^1.19.1",
"react": "16.13.1",
"react-dom": "16.13.1",
"umi": "^3.1.0",
"yorkie": "^2.0.0"
}
}

View File

@@ -0,0 +1 @@
b9b0e441-f28a-4b9a-97e8-c3039d8aa213

View File

@@ -0,0 +1,8 @@
import { history } from 'umi';
import { Utils } from '@/core/utils/utils';
import 'antd/dist/antd.css';
// 没有登录
if (localStorage.getItem("token") == null ) {
history.push('/login');
}

View File

@@ -0,0 +1 @@
0b2a8c51-ddfc-426d-9e4f-33ad6b7e23ad

View File

@@ -0,0 +1 @@
2b5614b9-b1f3-4c18-8568-1904fa08c3dc

View File

@@ -0,0 +1 @@
69cf1b8a-0c54-458f-bfbb-bb49697d6a4d

View File

@@ -0,0 +1,10 @@
.title {
width: 100%;
height: 50px;
padding-left: 20px;
font-size: 16px;
font-weight: bold;
line-height: 50px;
background: #fff;
margin-bottom: 17px;
}

View File

@@ -0,0 +1,2 @@
@import './public/font.less';
@import './public/index.less';

View File

@@ -0,0 +1 @@
eb794daf-d95e-46d2-b1d6-8776e8f6432c

View File

@@ -0,0 +1,31 @@
@import "../public/index";
.TeamManagement {
}
.info {
overflow: hidden;
.item {
width: 33%;
float: left;
padding-left: 4%;
&:first-child {
padding-left: 0;
}
.title {
font-size: 12px;
color: rgb(136, 136, 136);
margin-bottom: 20px;
}
.tNumber {
font-size: 36px;
color: #FF7800;
}
}
.line {
float: left;
width: 1px;
height: 94px;
background: #e5e5e5;
}
}

View File

@@ -0,0 +1,58 @@
@import '../public/color.less';
@import '../public/mixins.less';
.home {
height: 100%;
.marginAuto(@w: 100%, @c: @BackgroundColor, @p: 0px);
.header{
padding: 20px;
background-color: @white;
border-radius: 2px;
.header_l{
.title{
font-size: 18px;
color: @color1;
font-weight: bold;
line-height: 18px;
}
p{
color: @color3;
}
}
.header_r{
.title{
font-size: 16px;
color: @color2;
line-height: 18px;
}
span{
cursor: pointer;
color: @color3;
&:hover{
color: @color1;
}
}
}
}
.col{
text-align: center;
cursor: pointer;
.text{
margin-top: 5px;
.badge{
display: inline-block;
padding: 0 6px;
font-size: 12px;
text-align: center;
background-color: @danger1;
color: #fff;
border-radius: 2px;
}
}
}
.cardTitleSpan{
color: @color3;
font-size: 12px;
margin-left: 5px;
}
}

View File

@@ -0,0 +1,14 @@
@import '../public/color.less';
@import '../public/mixins.less';
.ant-layout-header {
padding: 0px 26px;
}
.logo {
color: #fff;
float: left;
}
.UserInfo {
float: right;
color: #fff;
}

View File

@@ -0,0 +1,42 @@
.login {
padding-top: 120px;
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: #f2f2f2;
.form {
width: 4rem;
height: 100%;
margin: 0 auto;
h2,
h5 {
text-align: center;
}
h2 {
margin-bottom: 10px;
font-weight: 300;
font-size: 30px;
color: #000;
}
h5 {
font-weight: 300;
color: #999;
}
form {
width: 400px;
margin: 40px auto 0;
}
}
.footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
padding: 30px 0;
text-align: center;
color: rgba(0, 0, 0, 0.5);
}
}

View File

@@ -0,0 +1 @@
a5026f01-d6b8-4700-8c5c-7d69ef696c16

View File

@@ -0,0 +1,48 @@
// 主题颜色
// 产品品牌色,多用于主按钮。重要图标,重要入口
@c1: #1890ff;
@c2: #d9ecff;
@c3: #ecf5ff;
// 辅助色 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)
@success1: #67c23a;
@success2: #e1f3d8;
@success3: #f0f9eb;
@warning1: #e6a23c;
@warning2: #faecd8;
@warning3: #fdf6ec;
@danger1: #f56c6c;
@danger2: #fde2e2;
@danger3: #fef0f0;
@info1: #909399;
@info2: #e9e9eb;
@info3: #f4f4f5;
// 点缀色 主要用于提示作用,多用于标签,角标,小按钮等
@emb1: #67C23A;
@emb2: #F56C6C;
// 文字主题色
// 多用于标题文字,重要文字
@color1: #303133;
@color2: #606266;
@color3: #909399;
@color4: #c0c4cc;
// 常规颜色
@white: #fff;
@black: #000;
// 线条颜色
@BorderBase: #DCDFE6;
// 阴影颜色
@shadow: #8fa8bf59;
// 背景色
@BackgroundColor: #f2f2f2;
@NavbarColor: #20222a;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,68 @@
@import './color.less';
html {
background-color: @BackgroundColor;
min-width: 1200px;
}
.center {
background-color: @white;
}
.ml10{
margin-left: 10px !important;
}
.ml130{
margin-left: 130px;
}
.mr10{
margin-right: 10px;
}
.mb5{
margin-bottom: 5px;
}
.mb10{
margin-bottom: 10px;
}
.mb20{
margin-bottom: 20px;
}
.mb25{
margin-bottom: 25px;
}
.pr10{
padding-right: 10px;
}
.pd7{
padding: 7.5px;
}
.pd20{
padding: 20px;
}
.lineHegith{
line-height: 32px;
}
.flex{
display: flex;
}
.flex1{
flex: 1;
}
.flex3{
flex: 3;
}
.align{
align-items: center;
}
.between{
justify-content: space-between;
}
.dottedLine{
border: 1px dashed @BorderBase;
padding: 10px 0;
text-align: center;
cursor: pointer;
&:hover{
border-color: @c1;
color: @c1;
}
}

View File

@@ -0,0 +1,39 @@
@import './color.less';
.scroll() {
&::-webkit-scrollbar {
/*滚动条整体样式*/
height: 4px;
}
&::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 10px;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #535353;
}
&::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
border-radius: 10px;
background: #ededed;
}
}
.shadow() {
box-shadow: 0 0px 20px @shadow;
}
.marginAuto(@w: 990px, @c: #ffffff, @p: 20px) {
width: @w;
margin: 0px auto;
padding: @p;
background-color: @c;
height: 100%;
// box-sizing: border-box;
}
.hiddenText(@a: 1) {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: @a;
-webkit-box-orient: vertical;
}

View File

@@ -0,0 +1 @@
776886bd-bdd6-44a0-85c8-40470c4509d2

View File

@@ -0,0 +1,17 @@
import React, { Component } from 'react';
import style from '@/assets/less/components/NavTitle.less';
interface Props {
title: string
}
export default class NavTitle extends Component<Props> {
render() {
return (
<div className={style.title}>
{this.props.title}
</div>
);
}
}

View File

@@ -0,0 +1 @@
becb9213-f68e-41ae-88ba-9a1b65406d59

View File

@@ -0,0 +1,62 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import './progress.less'
import { Spin } from 'antd';
import { SyncOutlined } from '@ant-design/icons';
class Progress extends Component {
state: {
show: boolean,
time: NodeJS.Timeout | null
} = {
show: false,
time: null
}
start() { // 开始显示
this.setState({
show: true
})
this.state.time = setTimeout(() => {
this.setState({
show: false
})
clearTimeout(this.state.time as NodeJS.Timeout)
}, 10000)
}
done() { // 结束隐藏
this.setState({
show: false
})
clearTimeout(this.state.time as NodeJS.Timeout)
}
render() {
return (
<div className="myprogress" style={this.state.show ? { display: 'block' } : { display: 'none' }}>
<div className="progress">
<div style={{ textAlign: 'center' }}>
<SyncOutlined spin style={{ fontSize: 28, color: '#409eff' }} />
<p style={{ fontSize: 18, color: '#409eff' }}></p>
</div>
</div>
</div>
)
}
}
// 创建元素追加到body
let div = document.createElement('div');
let props = {
};
document.body.appendChild(div);
let AxiosLoading = ReactDOM.render(React.createElement(
Progress,
props
), div);
export default AxiosLoading;

View File

@@ -0,0 +1,19 @@
@themecolor:#ffc900;
.myprogress {
position: fixed;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.7);
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1001;
.progress{
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}

View File

@@ -0,0 +1 @@
e4fb0dd0-423d-48e4-a5ec-076253272ff9

View File

@@ -0,0 +1,22 @@
import React, { Component } from 'react';
import { Spin } from 'antd';
const style = {
height: '100%',
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
};
class Loading extends Component {
render() {
return (
<div style={style}>
<Spin size="large" />
</div>
);
}
}
export default Loading;

View File

@@ -0,0 +1 @@
b651e9b6-23f8-4b77-ac62-e92dc604348b

View File

@@ -0,0 +1 @@
d4266e10-2e14-4d8c-baf6-29b0b2c350f1

View File

@@ -0,0 +1,14 @@
import React, { Component } from 'react';
interface utlisType {
[k: string]: Function;
}
export class IocComponent<P = {}, S = {}> extends Component<P, S> {
/**
* 挂载全局方法
*/
protected globalMethod: utlisType = {};
}
export default React;

View File

@@ -0,0 +1 @@
70e97028-e521-4c48-955f-dc8251ee8642

View File

@@ -0,0 +1,16 @@
import { PublicServiceImp } from '@service/publicServiceImp'
import UserModel from '@/models/user';
import { Utils } from '@/core/utils/utils'
const publicService: PublicServiceImp = new PublicServiceImp()
/**
* 如果页面刷新则重新发送ajax来获取路由配置
* 从路由配置中获取当前组件的等级
* @param params 组件名
*/
export function access(params: string) {
return function (target: any) {
let lv: number = Utils.valueOnArror(UserModel.state.routerConfig, params)
target.access = lv > 0 ? lv : 0
}
}

View File

@@ -0,0 +1,75 @@
import { Axios } from "@/core/dao/index";
import Loading from '@components/axiosLoading/axiosLoading'
const axios = new Axios()
interface requestOption {
url?: string
str?: string
loading?: boolean
}
/**
* 获取方法名作为请求url
* 获取入参作为请求参数
*/
export function get(option?: requestOption) {
return function (target: any, attr: string, descriptor: PropertyDescriptor) {
let url: string;
if (option && option.url) {
url = option.url
} else if (option && option.str) {
url = `${option.str}/${attr}`
}
descriptor.value = async function (data: any) {
if (option?.loading) {
Loading.start()
}
let res = await axios.get({
url: url,
data: data
})
Loading.done()
return res
}
}
}
export function post(option?: requestOption) {
return function (target: any, attr: string, descriptor: PropertyDescriptor) {
let url: string;
if (option && option.url) {
url = option.url
} else if (option && option.str) {
url = `${option.str}/${attr}`
}
descriptor.value = async function (data: any) {
if (option?.loading) {
Loading.start()
}
let res = await axios.post({
url: !!url ? url : attr,
data: data
})
Loading.done()
return res
}
}
}
export function put(option?: requestOption) {
return function (target: any, attr: string, descriptor: PropertyDescriptor) {
let url: string;
if (option && option.url) {
url = option.url
} else if (option && option.str) {
url = `${option.str}/${attr}`
}
descriptor.value = async function (data: any) {
return await axios.put({
url: !!url ? url : attr,
data: data
})
}
}
}

View File

@@ -0,0 +1,3 @@
export * from './operationalComponent';
export * from './ajaxType';
export * from './access';

View File

@@ -0,0 +1,70 @@
import { dynamic, history } from 'umi';
import { Component } from 'react';
import UeroModel from '@/models/user';
// import LimitedAuthority from '@/components/limitedAuthority/limitedAuthority'
function listen() {
return new Promise((resolve, reject) => {
history.listen(res => {
resolve(res)
})
})
}
/**
* 对外导出2种用法
* 函数用法和装饰器用法
*/
export class OperationalComponent {
/**
* 在正常对外高阶组件中必须调用此方法
* 并使用此方法返回的组件进行再处理
* 接收一个组件并返回处理后的组件
* @param model 组件
*/
private static componentHoc<T extends typeof Component>(model: T): T {
return model;
}
/**
* 页面权限控制
* @param model
*/
public static routerHoc<T extends typeof Component>(model: T): T {
let hoc: T = this.componentHoc(model);
let router = JSON.stringify(UeroModel.state.routerConfig)
let hashname: string = window.location.hash.slice(1)
// if (router.indexOf(hashname) < 0) {
// // @ts-ignore
// let el: T = LimitedAuthority;
// return el;
// }
return hoc
}
/**
* 组件加载动画
* @param el
*/
public static LoadDemand<T>(el: T): React.ComponentClass<{}, T> | T {
return dynamic({
loader: async () => {
// 需要等待的时间
await new Promise(resolve => {
setTimeout(resolve, 500);
});
return el;
},
// 动画组件必须使用require动态加载模块
loading: require('../../components/loading/loading.tsx').default,
});
}
}
export function routerHoc(target: any) {
return (target = OperationalComponent.routerHoc(target));
}
export function LoadDemand(target: any) {
return (target = OperationalComponent.LoadDemand(target));
}

View File

@@ -0,0 +1 @@
75291b01-8026-4fda-b31e-60bf7c23b5b2

View File

@@ -0,0 +1,37 @@
export class Config {
/**
* ajax 基础配置信息
*/
public static AjaxConfig = {
// 开发环境api基地址
devBaseUrl: 'http://www.refer.test',
// 正式环境api基地址
proBaseUrl: 'http://www.refer.test',
ApiList: {
login: '/login', // 登录
reg: '/reg', // 注册
uploadFile: '/uploadFile', // 图片上传
addRefer: '/team/addRefer', // 添加下级推广
details: '/team/details', // 团队信息展示
getSmsCode: '/getSmsCode', // 发送验证码
userInfo: '/userInfo', // 获取用户详情
people: '/team/people', // 团队成员
logo: '/team/logo', // 获取团队logo
addTeam: '/team/add', // 创建团队
recordList: '/finance/recordList', // 资金列表
buyerBankList: '/buyerBankList', // 获取银行卡列表
cashOut: '/finance/cashOut', // 提现申请
cashOutList: '/finance/cashOutList', // 提现申请列表
buyerList: '/relate/buyerList', // 买家用户
sellerList: '/relate/sellerList', // 商家用户
codeList: '/invite/codeList', // 邀请码列表
channelList: '/invite/channelList', // 推广渠道列表
addCode: '/invite/addCode', // 添加邀请码
modifyCode: '/invite/modifyCode', // 修改邀请码
setPassword: '/setPassword', // 修改密码
},
};
public static prefix: string = '';
}

View File

@@ -0,0 +1 @@
fa9faff4-87c9-4b96-b5a6-cdc87edcac24

View File

@@ -0,0 +1,163 @@
import { Utils } from '../utils/utils';
import axios, { AxiosInstance } from 'axios';
import { Modal, Button } from 'antd';
/**
* 将提示变为Promise可以操作点击确定后再进行下一步
* @param msg
*/
function awaitSuccess(msg: string) {
return new Promise((resolve, reject) => {
Modal.success({
title: '提示',
content: msg,
onOk: () => {
resolve();
},
});
});
}
export class Axios {
private instance: AxiosInstance;
constructor() {
this.instance = axios.create({
baseURL: Utils.CheckAjaxUrl(),
timeout: 10000,
});
this.ResponseInterceptor();
this.RequestInterceptor();
}
/**
* Get 请求
* 请求参数请参考接口RequestParams
* @param params
*/
public async get(params: {
url: string;
data: Object;
header?: Object;
}): Promise<Object> {
try {
return await this.instance.get(params.url, {
params: Object.assign(params.data, { fdslkjklshdfiunkjgnjs: '10088' }),
headers: Object.assign(
{
// token: localStorage.getItem("token") == null ? '' : localStorage.getItem("token")
// fdslkjklshdfiunkjgnjs: '10083',
},
params.header,
),
});
} catch (e) {
return e.message;
}
}
/**
* Post 请求
* 请求参数请参考接口RequestParams
* @param params
*/
public async post(params: {
url: string;
data: Object;
header?: Object;
}): Promise<Object> {
try {
return await this.instance.post(params.url, Object.assign(params.data, { fdslkjklshdfiunkjgnjs: '10088' }), {
headers: Object.assign(
{
// fdslkjklshdfiunkjgnjs: '10083',
},
params.header,
),
});
} catch (e) {
return e.message;
}
}
/**
* Put 请求
* 请求参数请参考接口RequestParams
* @param params
*/
public async put(params: { url: string; data: Object }): Promise<Object> {
try {
return await this.instance.put(params.url, params.data);
} catch (e) {
return e.message;
}
}
/**
* delete 请求
* 请求参数请参考接口RequestParams
* @param params
*/
public async delete(params: { url: string; data: Object }): Promise<Object> {
try {
return await this.instance.delete(params.url, { params: params.data });
} catch (e) {
return e.message;
}
}
/**
* 添加响应拦截器
* @constructor
*/
public async ResponseInterceptor(): Promise<any> {
this.instance.interceptors.response.use(
async (response: any) => {
this.CloseLoadingData();
switch (response.data.status) {
case 1:
if (response.data.msg == null) return response.data.data;
await awaitSuccess(response.data.msg);
return response.data.data;
default:
Modal.error({
title: `[${response.data.code}]${response.data.msg}`,
content: response.data.msg,
});
return "error"
break;
}
},
function(error: any) {
return Promise.reject(error);
},
);
}
/**
* 添加请求拦截器
* @constructor
*/
public async RequestInterceptor(): Promise<any> {
this.OpenLoadingData();
this.instance.interceptors.request.use(
config => {
return config;
},
function(error) {
return Promise.reject(error);
},
);
}
/**
* 显示加载进度
* @constructor
*/
private OpenLoadingData(): void {}
/**
* 清除加载进度条
*/
private CloseLoadingData(): void {}
}

View File

@@ -0,0 +1 @@
60ad22f5-d089-4209-a0df-491dfc97dffe

View File

@@ -0,0 +1 @@
338725e3-854a-4edf-9646-7be4d1908de9

View File

@@ -0,0 +1,7 @@
import { get, post } from '@/core/annotation/ajaxType';
import { Config } from '@/core/config/config';
export class PublicServiceImp {
@post({ url: Config.AjaxConfig.ApiList.uploadFile })
public static async uploadFile(params: object): Promise<any> { }
}

View File

@@ -0,0 +1,64 @@
import { get, post } from '@/core/annotation/ajaxType';
import { Config } from '@/core/config/config';
export class UserServiceImp{
@post({ url: Config.AjaxConfig.ApiList.login })
public static async login(params: object): Promise<any> { }
@post({ url: Config.AjaxConfig.ApiList.reg })
public static async reg(params: object): Promise<any> { }
@post({ url: Config.AjaxConfig.ApiList.addRefer })
public static async addRefer(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.details })
public static async details(params: object): Promise<any> { }
@post({ url: Config.AjaxConfig.ApiList.getSmsCode })
public static async getSmsCode(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.userInfo })
public static async userInfo(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.people })
public static async people(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.logo })
public static async logo(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.recordList })
public static async recordList(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.buyerBankList })
public static async buyerBankList(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.cashOut })
public static async cashOut(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.cashOutList })
public static async cashOutList(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.buyerList })
public static async buyerList(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.sellerList })
public static async sellerList(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.codeList })
public static async codeList(params: object): Promise<any> { }
@get({ url: Config.AjaxConfig.ApiList.channelList })
public static async channelList(params: object): Promise<any> { }
@post({ url: Config.AjaxConfig.ApiList.addTeam })
public static async addTeam(params: object): Promise<any> { }
@post({ url: Config.AjaxConfig.ApiList.setPassword })
public static async setPassword(params: object): Promise<any> { }
@post({ url: Config.AjaxConfig.ApiList.addCode })
public static async addCode(params: object): Promise<any> { }
@post({ url: Config.AjaxConfig.ApiList.modifyCode })
public static async modifyCode(params: object): Promise<any> { }
}

View File

@@ -0,0 +1,4 @@
export interface PublicService {
getRoutesConfig(): Promise<any>;
getList(params: object): Promise<any>;
}

View File

@@ -0,0 +1,3 @@
export interface UserService {
login(data: object): Promise<Object> | any;
}

View File

@@ -0,0 +1 @@
895b2753-68de-45ca-aca3-97f45bac33ef

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,240 @@
import { Config } from '../config/config';
import DefaultCity from './defaultCity';
import Login from '@/pages/login';
export class Utils {
/**
* 判断当前环境返回api地址
*/
public CheckAjaxUrl(): string {
return process.env.NODE_ENV == 'production'
? Config.AjaxConfig.proBaseUrl
: Config.AjaxConfig.devBaseUrl;
}
public static CheckAjaxUrl(): string {
return process.env.NODE_ENV == 'production'
? Config.AjaxConfig.proBaseUrl
: Config.AjaxConfig.devBaseUrl;
}
/**
* 判断路由中是否有传入value相对的obj[key]
* @param obj
* @param value
*/
public static valueOnObj(obj: any, value: string): number {
if (obj.hasOwnProperty('name') && obj['name'] == value) {
return obj['access'];
}
if (obj.hasOwnProperty('routes')) {
return this.valueOnArror(obj['routes'], value);
}
return -1;
}
/**
* 时间戳转正常时间
* @param data
* @returns {string}
*/
public static formatDate(data: any) {
let now = new Date(data * 1000);
let year = now.getFullYear();
let month = now.getMonth() + 1;
let date = now.getDate();
let hour = now.getHours();
let minute = now.getMinutes();
let second = now.getSeconds();
return (
year + '-' + month + '-' + date + ' ' + hour + ':' + minute + ':' + second
);
}
/**
* 判断数组中是否存在某值
* @param arr
* @param value
*/
public static valueOnArror(arr: any[], value: string): number {
for (let i = 0; i < arr.length; i++) {
if (this.valueOnObj(arr[i], value)) {
return this.valueOnObj(arr[i], value);
}
}
return -1;
}
/**
* 获取本地Storage中存放的数据
* @param name
*/
public static getStorage(name: string): string {
try {
let data: string | null = localStorage.getItem(
`${Config.prefix}_${name}`,
);
if (!!data) {
return JSON.parse(data);
}
return 'no';
} catch (error) {
throw `获取storage时出错:${error}`;
}
}
/**
* 存储数据到本地
* @param name
* @param data
*/
public static setStorage(name: string, data: any): boolean {
try {
localStorage.setItem(`${Config.prefix}_${name}`, JSON.stringify(data));
return true;
} catch (error) {
throw `插入storage时出错:${error}`;
}
}
/**
* 去除数组中的空值并返回新数组
* @param data
*/
public emptyArray(data: any[]): any[] {
let newArr: any[] = [];
data.forEach((v, i) => {
if (!this.isEmpty(v)) {
newArr.push(v);
}
});
return newArr;
}
/**
* 判断当前传入的值是否是空值, 下方是测试用例
* isEmpty() //true
* isEmpty([]) //true
* isEmpty({}) //true
* isEmpty(0) //true
* isEmpty(Number("abc")) //true
* isEmpty("") //true
* isEmpty(" ") //true
* isEmpty(false) //true
* isEmpty(null) //true
* isEmpty(undefined) //true
* @param v
*/
public isEmpty(v: any): boolean {
switch (typeof v) {
case 'undefined':
return true;
case 'string':
if (v.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0)
return true;
break;
case 'boolean':
if (!v) return true;
break;
case 'number':
if (0 === v || isNaN(v)) return true;
break;
case 'object':
if (null === v || v.length === 0) return true;
for (var i in v) {
return false;
}
return true;
}
return false;
}
public static getUserInfo(): any {
// @ts-ignore
return JSON.parse(localStorage.getItem("token"))
}
/**
* 用于把 单位为分 转换成 单位为元
* @param m 后端返回被处理成 单位为分 的钱
*/
public static conversionMoney(m: number): number {
return Number((m / 10 / 10).toFixed(2));
}
public static FullCityName(areasCode: string) {
// 34 01 02
let provinces = areasCode.slice(0, 2) + '0000';
let cities = areasCode.slice(2, 4);
let areas = areasCode.slice(4, 6);
// console.log("provinces: ", provinces);
let provincesData: any = DefaultCity.filter((val: any, index: number) => {
return val.id == provinces;
});
return [
provincesData[0].full_name,
provincesData[0]['sub'][cities].full_name,
provincesData[0]['sub'][cities]['sub'][areas].full_name,
];
// console.log("provincesData: ", provincesData);
// console.log("provincesData: ", provincesData[0].full_name);
// console.log("provincesData: ", provincesData[0]['sub'][cities].full_name);
// console.log("provincesData: ", provincesData[0]['sub'][cities]['sub'][areas].full_name);
}
/**
* 判断是否是对象
* @param obj
*/
public static isObj(obj: any): boolean {
return Object.prototype.toString.call(obj) === '[object Object]'
}
/**
* 判断是否是对象
* @param obj
*/
public static isArr(arr: any): boolean {
return Object.prototype.toString.call(arr) === '[object Array]'
}
/**
* 获取YYYY-MM-DD HH:MM:SS 时间
*/
public static getTimes() {
var thisDay = new Date();
var year = thisDay.getFullYear(); //年
var month = thisDay.getMonth() + 1; //月
var day = thisDay.getDate(); //日
var hh = thisDay.getHours(); //时
var mm = thisDay.getMinutes(); //分
var ss = thisDay.getSeconds(); //秒
var timer = year + "-";
if (month < 10)
timer += "0";
timer += month + "-";
if (day < 10)
timer += "0";
timer += day + " ";
if (hh < 10)
timer += "0";
timer += hh + ":";
if (mm < 10)
timer += '0';
timer += mm + ":";
if (ss < 10)
timer += '0';
timer += ss;
return (timer);
}
}

View File

@@ -0,0 +1,43 @@
// @import './assets/less/index.less';
#root {
height: 100%;
width: 100%;
}
.items {
margin-left: 20px;
background: #fff;
padding: 20px;
box-sizing: border-box;
margin-bottom: 25px;
}
.cTitle {
color: #000;
margin-bottom: 25px;
font-size: 15px;
}
.rtitle {
display: flex !important;
align-items: center;
justify-content: center;
}
.ant-layout-sider-trigger {
background-color: #333 !important;
}
.ant-layout-sider {
position: fixed !important;
left: 0;
top: 50px;
height: 100%;
z-index: 999;
}
.ant-layout-content {
padding-left: 200px !important;
}
.ant-layout-header {
height: 50px !important;
line-height: 50px !important;
}
.ant-menu-dark .ant-menu-inline.ant-menu-sub {
background: #252525 !important;
}

View File

@@ -0,0 +1 @@
2829169d-8acd-41d7-8da8-82452d0ab4a1

View File

@@ -0,0 +1,175 @@
import React, { IocComponent } from '@Ioc/index';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import style from '@/assets/less/page/index.less';
import { Layout, Menu, Breadcrumb, Dropdown, Modal, ConfigProvider } from 'antd';
import zhCN from 'antd/es/locale/zh_CN';
import {
LogoutOutlined,
AppstoreOutlined,
DownOutlined,
TeamOutlined,
AuditOutlined,
ApartmentOutlined,
PayCircleOutlined,
UserAddOutlined,
SettingOutlined,
ShopOutlined,
ShoppingCartOutlined,
RiseOutlined,
OrderedListOutlined,
KeyOutlined,
FileDoneOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
interface PageProps extends ConnectProps {
user: UserModelState;
}
@LoadDemand
class Index extends IocComponent<PageProps> {
private userServiceImp: UserServiceImp = new UserServiceImp();
rootSubmenuKeys = ['2', '3', '4'];
state = {
openKeys: [ localStorage.getItem("currentIndex") ],
selectedKeys: [],
collapsed: false,
leftMenu: [
{ text: '推广首页', path: '/home', icon: <AppstoreOutlined /> },
{ text: '推广效果', path: '/PromotionEffect', icon: <AuditOutlined />},
{ text: '推广物料', path: '/', icon: <ApartmentOutlined />,
childen: [
{ text: '邀请码管理', path: '/InvitationCode', icon: <KeyOutlined /> },
]
},
{ text: '关联用户', path: '/', icon: <TeamOutlined />,
childen: [
{ text: '商家用户', path: '/AssociatedUsers?type=s', icon: <ShopOutlined /> },
{ text: '买家用户', path: '/AssociatedUsers?type=m', icon: <ShoppingCartOutlined /> }
]
},
{ text: '财务管理', path: '/', icon: <PayCircleOutlined />,
childen: [
{ text: '资金流水', path: '/Financial', icon: <RiseOutlined /> },
{ text: '提现管理', path: '/Withdrawal', icon: <FileDoneOutlined /> }
]
},
{ text: '团队管理', path: '/TeamManagement', icon: <UserAddOutlined />},
{ text: '个人资料', path: '/PersonalData', icon: <SettingOutlined />},
],
// @ts-ignore
UserInfo: Utils.getUserInfo()
}
onCollapse = (collapsed:any) => {
this.setState({ collapsed });
};
componentDidMount() {
// 刷新的时候,重新激活与路由地址匹配的路由
const pathname = this.props.location.pathname;
this.setState({ selectedKeys: [pathname] });
}
TextItem(item: any) {
return (
<Menu.Item style={{ marginTop: 0 }} icon={item.icon} key={item.path} onClick={({ key }:any) => {
// 激活样式跟随
this.setState({ selectedKeys: [key] })
this.props.history.push(key)
}}>{item.text}
</Menu.Item>
)
}
render() {
return (
<ConfigProvider locale={zhCN}>
<Layout style={{ minHeight: '100vh' }}>
<Header className="header" style={{ position: 'fixed', zIndex: 1, width: '100%', padding: '0 26px',backgroundColor: '#262F3E' }}>
<div className={style.logo} >广</div>
<div className={style.UserInfo}>
<Dropdown overlay={() => {
return (
<Menu>
<Menu.Item key="1" icon={<LogoutOutlined />} onClick={() => {
Modal.confirm({
title: '温馨提示',
content: '确认现在退出登录吗?',
okText: '退出',
cancelText: '取消',
onOk() {
localStorage.removeItem("token")
location.href = "#/login"
}
})
}}>
退
</Menu.Item>
</Menu>
)}}>
<span style={{ cursor: 'pointer' }}>{this.state.UserInfo ? this.state.UserInfo.true_name : ''} <DownOutlined /></span>
</Dropdown>
</div>
</Header>
<Layout className="site-layout" style={{ paddingTop: 50 }}>
<Sider style={{backgroundColor: '#333'}}>
<Menu
style={{backgroundColor: '#333'}}
theme="dark"
onClick={({ item, key, keyPath, domEvent })=>{
// 如果点击的是一级标题,那么收缩所有二级下拉菜单,并删除默认本地缓存
if (keyPath.length == 1) {this.setState({ openKeys: [] });localStorage.removeItem("currentIndex")}
}}
// @ts-ignore
openKeys={this.state.openKeys}
selectedKeys={this.state.selectedKeys}
onOpenChange={(openKeys) => {
// 存储,以便刷新时候能继续保持二级的展开状态
localStorage.setItem("currentIndex", openKeys[openKeys.length - 1])
// 获取最新被展开的二级菜单
const latestOpenKey = openKeys[openKeys.length - 1]
// 收缩非当前项二级菜单
this.rootSubmenuKeys.indexOf(latestOpenKey) === -1
? this.setState({ openKeys })
: this.setState({ openKeys: latestOpenKey ? [latestOpenKey] : [] });
}}
forceSubMenuRender={true}
mode="inline">
{
this.state.leftMenu.map((val: any,index)=>{
return (val.hasOwnProperty("childen")
? (<SubMenu key={index} icon={val.icon} title={val.text}>
{ val.childen.map((i:any, d: number)=> { return this.TextItem(i) }) }
</SubMenu>)
: (this.TextItem(val)))
})
}
</Menu>
</Sider>
<Content style={{ padding: '0 ' }}>
{this.props.children}
</Content>
</Layout>
</Layout>
</ConfigProvider>
);
}
}
function mapStateToProps(hero: UserModelState) {
return hero;
}
export default connect(mapStateToProps)(Index);

View File

@@ -0,0 +1 @@
985e67e9-b68a-46fa-8f12-2edc45ee16aa

View File

@@ -0,0 +1,2 @@
# 国际化
- 如果需要国际化则在此定义国际化文字描述

View File

@@ -0,0 +1 @@
701dffd1-218e-4b6e-8372-3b48814fa41d

View File

@@ -0,0 +1,25 @@
const MyPlanListModel = {
//命名空间名字
namespace: 'MyPlanListModel',
//初始化数据
state: {
shopId: 0,
bodyId: 0,
releasePlan: [
{
searchType: 0,
keyword: '',
releaseTime: [
{
time: new Date(),
minute: 0,
single: 0,
totlSingle: 0,
},
],
},
],
},
};
export default MyPlanListModel;

View File

@@ -0,0 +1,514 @@
import { Effect } from 'dva';
import { Utils } from '@/core/utils/utils'
import { notification } from 'antd';
type releaseTimeType = {
// 选择的时间
time: string
// 每隔多少分钟
minute: number
// 每分钟放的单数
single: number
// 一共需要放的单数
totlSingle: number
}
type releasePlanType = {
// 买家入口
searchType: number
keyword: string
//
releaseTime: releaseTimeType[]
}
type couponType = {
/**
* 领取位置id首页、详情
*/
location: number
/**
* 优惠卷类型(满减、折扣)
*/
typeId: number
/**
* 优惠卷金额
*/
amount: number
/**
* 优惠卷名称
*/
name: string
}
type multipleChoice = {
title: string
num: number
} | any
export interface FirstTaskState {
// 任务全部数据
taskData: {
/**任务类型 */
taskType: number
/**店铺id */
shopId: number
/**
* 选中的店铺信息
*/
shopInfo: any
/**宝贝id */
bodyId: number
/**
* 宝贝信息
*/
bodyInfo: any
/**选择的模板类型 */
temType: number
/**选中的模板id */
temId: number
/**宝贝规格id */
bodySkuId: number
/**选中的宝贝规格数据 */
skuInfo: {
id: number
price: number
sku_name: string
sku_stock: string
label: string
}
/**宝贝单价 */
bodyPrice: number
/**下单数量 */
orderNum: number
/**选中的副宝贝id */
accBody: number[]
/**选中的副宝贝信息 */
accBodyall: any[]
/**
* 选中的副宝贝下标用于回显table的复选框
*/
selectBodyRowKeys: number[]
/**其他费用 选中的id */
otherId: number
/**
* 其他费用的详细说明
*/
otherText: string
/**发布计划 */
releasePlan: releasePlanType[]
/**优惠卷 */
coupon: couponType[]
/**
* 辅助信息
*/
// 搜索价格
searchPrice: number
// 收货/付款人数
peoples: number
// 搜索排序
sort: number
// 商品所在地
location: string
// 价格区间
priceStart: number
priceEnd: number
/**第三步全部信息 */
thirdStep: {
/**货比三家 */
compare_price: multipleChoice
/**旺旺聊天 */
purchase_chat: multipleChoice
/**买号等级 */
buyer_level: multipleChoice
/**买号性别 */
buyer_gender: multipleChoice
/**买号年龄 */
buyer_ages: multipleChoice
/**店铺关注 */
shop_fellow: multipleChoice
/**问答 */
detail_check: multipleChoice
/**淘气值 */
buyer_point: multipleChoice
// 付款方式
buyer_payment: multipleChoice
// 审号方式
buyer_check: multipleChoice
// 收货时间
receive_limit: multipleChoice
// 双收藏
buyer_favorite: multipleChoice
// 任务评价
buyer_comment: multipleChoice
// 指定任务评价的列表
appointCommentList: any[]
[key: string]: any
}
// 问答列表
qaList: {
// 问题
problem: string
// 答案
answer: string
}[]
// 全部订单总数
totalOrder: number
// 基础佣金列表
basicCommissionList: any[]
// 第三步附加佣金配置
optionCommissionList: any
// 通过宝贝价格计算得来基础佣金
basicCommission: number
// 垫付总额
totalAdvances: number
// 佣金总额
totalCommission: number[]
// 附加佣金的总额
totalAdditional: {
total: number
table: any[]
}
}
}
export interface FirstTask {
namespace: 'firstTask';
state: FirstTaskState;
reducers: CoverModelReducers<FirstTaskState>;
effects: {
put: Effect;
setCommission: Effect;
setThirdStep: Effect;
};
}
const FirstTaskModel: FirstTask = {
//命名空间名字
namespace: 'firstTask',
//初始化数据
state: {
taskData: {
taskType: 0,
shopId: 0,
shopInfo: {},
bodyId: 0,
bodyInfo: {},
temType: 0,
temId: 0,
bodySkuId: 0,
skuInfo: {
id: 0,
price: 0,
sku_name: '',
sku_stock: '',
label: ''
},
bodyPrice: 0,
orderNum: 1,
accBody: [],
otherId: 0,
otherText: '',
releasePlan: [],
accBodyall: [],
selectBodyRowKeys: [],
coupon: [],
searchPrice: 0,
peoples: 0,
sort: 0,
location: '',
priceStart: 0,
priceEnd: 0,
thirdStep: {
compare_price: {},
purchase_chat: {},
buyer_level: {},
buyer_gender: {},
buyer_ages: {},
shop_fellow: {},
detail_check: {},
buyer_point: {},
buyer_payment: {},
buyer_check: {},
receive_limit: {},
buyer_favorite: {},
buyer_comment: {},
appointCommentList: [],
},
qaList: [],
totalOrder: 0,
basicCommissionList: [],
optionCommissionList: {},
basicCommission: 0,
totalAdvances: 0,
totalCommission: [],
totalAdditional: {
total: 0,
table: []
}
},
},
// 同步方法
reducers: {
updataData(state, { payload }) {
let obj: any = {}
for (const key in payload) {
if (!!payload[key]) {
obj[key] = payload[key]
}
}
Object.assign(state.taskData, obj)
//
if (!!payload['releasePlan']) {
state.taskData.totalOrder = countReleasePlan(payload['releasePlan'])
}
// 选中主宝贝规格时判断所在
if (!!payload['skuInfo']) {
state.taskData.bodyPrice = payload['skuInfo'].price
}
state.taskData.totalAdvances = advancePayment(state)
state.taskData.totalCommission = commission(state)
return state
},
commission(state, { payload }) {
state.taskData.basicCommissionList = payload
return state
},
thirdStep(state, { payload }) {
Object.assign(state.taskData.thirdStep, isObj(payload))
state.taskData.totalAdditional = additional(state.taskData.thirdStep)
return state
},
},
// 异步方法
effects: {
*put({ payload }, { put }) {
yield put({ type: 'updataData', payload });
},
*setCommission({ payload }, { put }) {
yield put({ type: 'commission', payload });
},
*setThirdStep({ payload }, { put }) {
yield put({ type: 'thirdStep', payload });
},
}
};
// 统计一共有多少订单
function countReleasePlan(data: releasePlanType[]): number {
let num = 0
data.forEach((v, i) => {
v.releaseTime.forEach((n, m) => {
num += n.totlSingle
})
})
return num
}
function judgeMoney(arr: FirstTaskState['taskData']['basicCommissionList'], m: number) {
let num = 0
for (let i = 0; i < arr.length; i++) {
if (i === arr.length - 1) {
if (m <= arr[i].price) {
num = arr[i].amount
}
break;
}
if (arr[i].price > m && m >= arr[i + 1].price && (i !== arr.length - 1)) {
num = arr[i + 1].amount
break;
}
}
if (num <= 0) {
// notification.open({
// message: '价格过高',
// description: '当前选择的规格所需价格过高,请自行前往淘宝店修改',
// onClick: () => {
// },
// });
return 500
}
return num
}
// 垫付总额 = 总单数 totalOrder * sku价格 * orderNum 主宝贝的垫付总额
// // 副宝贝垫付总额 = ((副宝贝*单数)+ (主宝*单数)) 后端给的数组中的一项
// count(副宝贝垫付总额)
// 付加佣金 副宝贝总数*1
// 计算 垫付总额
function advancePayment(data: FirstTaskState) {
// 主宝贝垫付总额
let mian = data.taskData.totalOrder * data.taskData.bodyPrice * data.taskData.orderNum
let accAll = 0
data.taskData.accBodyall.forEach((v, i) => {
accAll += (v.num * v.sku.price)
})
return mian + accAll
}
// 计算 基础佣金
function commission(data: FirstTaskState): number[] {
let res = data.taskData
// 副宝贝数据
let accAll: number[] = [],
// 主宝贝数据
mainAll: number[] = [],
n: number = 0;
res.accBodyall.forEach((v, i) => {
for (let i = 0; i < v.num; i++) {
accAll.push(v.sku.price)
}
})
for (let i = 0; i < res.totalOrder; i++) {
mainAll.push(res.bodyPrice * res.orderNum)
}
accAll.sort((a, b) => {
return b - a
})
if (res.totalOrder <= 0) return [];
let newAccAll: number[][] = [[]]
accAll.forEach((v, i) => {
if (newAccAll[n].length >= res.totalOrder) {
++n;
newAccAll[n] = []
}
newAccAll[n].push(v)
})
newAccAll.forEach((v, i) => {
v.forEach((n, m) => {
mainAll[m] += n
})
})
let r: number[] = []
mainAll.forEach((v, i) => {
let c = judgeMoney(FirstTaskModel.state.taskData.basicCommissionList, v)
r[i] = c
})
return r
}
// 计算附加钱
function additional(data: FirstTaskState['taskData']['thirdStep']) {
let count: number = 0,
table: any[] = []
for (const key in data) {
if (Utils.isObj(data[key])) {
count += countMerge(data[key].sub)
table.push({
key: key,
name: data[key].option_title,
price: countMerge(data[key].sub)
})
}
if (Utils.isArr(data[key]) && Utils.isObj(data[key][0])) {
let price = 0
data[key].forEach((v: any, i: any) => {
price += v.image_path.length > 0 ? 200 : 100
});
count += price
table.push({
key: key,
name: '指定评论',
price: price
})
}
}
return {
total: count,
table: table
}
}
/**
* 从配置中获取对应参数amount*对应的数量num累加这些值
*/
function countMerge(m: any[]) {
if (m.length <= 0) return 0;
let count: number = 0
m.forEach((v: any, i: number) => {
count += (v.amount * v.num)
});
return count
}
/**
* 去除对象空值
*/
function isObj(payload: any) {
let obj: any = {}
for (const key in payload) {
if (!!payload[key]) {
obj[key] = payload[key]
}
}
return obj
}
export default FirstTaskModel;

View File

@@ -0,0 +1,108 @@
import { Effect, SubscriptionsMapObject } from 'dva';
import { Utils } from '@/core/utils/utils';
import { history } from 'umi';
const util: Utils = new Utils();
type routerOption = {
name: string;
path: string;
};
export interface GlobalModelState {
router: routerOption[];
// 当前所在的路由信息
routerIndex: routerOption;
}
export interface HeroModelType {
namespace: 'global';
state: GlobalModelState;
reducers: CoverModelReducers<GlobalModelState>;
effects: {
setRouter: Effect;
delRouter: Effect;
};
subscriptions: SubscriptionsMapObject;
}
const HeroModel: HeroModelType = {
//命名空间名字
namespace: 'global',
//初始化数据
state: {
router: [],
routerIndex: {
name: '',
path: '',
},
},
// 同步方法
reducers: {
addRoute(state, { payload }) {
state.routerIndex = payload;
if (payload instanceof Array) {
state.router = payload;
return state;
}
if (
state.router.filter((v, i) => {
return v.path == payload?.path;
}).length <= 0
) {
state.router.push(payload);
Utils.setStorage('routes', state.router);
}
return state;
},
/**
* 删除历史路由
* 支持 number 和 数组 用法
* @param state
* @param param1
*/
delRoute(state, { payload }) {
if (state.router.length <= 0) return state;
if (typeof payload === 'number') {
delete state.router[payload];
} else if (typeof payload === 'object' && payload instanceof Array) {
payload.forEach((v, i) => {
delete state.router[v];
});
}
state.router = util.emptyArray(state.router);
Utils.setStorage('routes', state.router);
if (state.router.length >= 1) {
history.push(state.router[state.router.length - 1].path);
} else {
history.push('/home');
}
return state;
},
},
// 异步方法
effects: {
*setRouter({ payload }, { put }) {
yield put({ type: 'addRoute', payload });
},
*delRouter({ payload }, { put }) {
yield put({ type: 'delRoute', payload });
},
},
subscriptions: {
setupHistory({ dispatch, history }) {
dispatch({
type: 'setRouter',
payload: Utils.getStorage('routes'),
});
},
},
};
export default HeroModel;

View File

@@ -0,0 +1,6 @@
/**
* 该类型表示模块中同步方法的类型
*/
declare interface CoverModelReducers<T> {
[key:string]: (state: T, payload: any) => T
}

View File

@@ -0,0 +1,60 @@
import { Effect } from 'dva';
export interface UserModelState {
// 用户级别
userLevel: number
// 获取路由配置
routerConfig: any[]
}
export interface UserModelType {
namespace: 'user';
state: UserModelState;
reducers: CoverModelReducers<UserModelState>;
effects: {
put: Effect;
};
}
const UserModel: UserModelType = {
//命名空间名字
namespace: 'user',
//初始化数据
state: {
userLevel: 5,
routerConfig: [ {
path: '/',
component: '@/pages/index',
name: 'Index',
access: 2,
routes: [
{
path: '/',
component: '@/layouts/index',
name: 'Test',
access: 3,
}
]
}, {
path: '/home',
component: '@/pages/home',
name: 'Home',
access: 1
}]
},
// 同步方法
reducers: {
updataUser(state, { payload }) {
return state
},
},
// 异步方法
effects: {
*put({ payload }, { put }) {
yield put({ type: 'updataUser', payload });
},
}
};
export default UserModel;

View File

@@ -0,0 +1 @@
83ce0102-d743-4655-85ca-22375c1e16da

View File

@@ -0,0 +1,33 @@
import React, { Component } from 'react';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import { Layout, Menu, Modal, Rate, Row, Col, Select, Input, DatePicker, Button, Table, Cascader } from 'antd';
import NavTitle from "@/components/NavTitle";
import { DesktopOutlined,
PieChartOutlined,
FileOutlined,
TeamOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
import CityData from '../core/utils/city';
const { TextArea } = Input;
const { RangePicker } = DatePicker;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
const { Option } = Select;
@LoadDemand
export default class Error extends Component {
render() {
return (
<div>
<h2></h2>
<a onClick={()=>{
history.back()
}}></a>
</div>
)
}
}

View File

@@ -0,0 +1,114 @@
import React, { Component } from 'react';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import style from '@/assets/less/page/TeamManagement.less';
import { Layout, Menu, Breadcrumb, Rate, Row, Col, Select, Input, DatePicker, Button, Table } from 'antd';
import NavTitle from "@/components/NavTitle";
import { DesktopOutlined,
PieChartOutlined,
FileOutlined,
TeamOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
const { RangePicker } = DatePicker;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
const { Option } = Select;
/**
* 财务管理 - 资金流水
*/
@LoadDemand
export default class AssociatedUsers extends Component {
state = {
pageType: '',
TableCol: [
{
title: '手机号',
dataIndex: 'cellphone',
key: 'cellphone',
},
{
title: '注册时间',
dataIndex: 'create_time',
key: 'create_time',
},
{
title: '昨日完成数',
dataIndex: 'yesterdayStat',
key: 'yesterdayStat',
},
{
title: '近7日完成数',
dataIndex: 'sevenDayStat',
key: 'sevenDayStat',
},
{
title: '总完成数',
dataIndex: 'allStat',
key: 'allStat',
},
{
title: '最后登录地址',
dataIndex: 'last_login_address',
render: (res: any, record: any) => {
return <div>{
record.last_login_address == null
? '暂无'
: record.last_login_address.province + record.last_login_address.country}
</div>;
},
},
{
title: '最后登录时间',
dataIndex: 'last_login_time',
key: 'last_login_time',
},
],
ListData: [], // 保存买家商家用户list数据
total: {
count: 0,
totalStat: 0
}, // 保存 总数
loading: false
}
async componentDidMount() {
this.setState({ loading: true })
let res = null
if (history.location.query.type == 's') {
res = await UserServiceImp.sellerList({
limit: 100,
page: 1
})
} else if (history.location.query.type == 'm') {
res = await UserServiceImp.buyerList({
limit: 100,
page: 1
})
}
this.setState({ loading: false })
if (res != undefined && res.hasOwnProperty("list")) {
this.setState({ ListData: res.list });
this.state.total.count = res.count
this.state.total.totalStat = res.totalStat
}
}
render() {
return (
<div className="AssociatedUsers">
<NavTitle title={history.location.query.type == 's' ? '商家用户' : '买家用户'}></NavTitle>
<div className="items">
<p className='cTitle'></p>
<p>广{history.location.query.type == 's' ? '商家' : '买家'}{this.state.total.count}
{history.location.query.type == 's' ? '商家' : '买家'}{this.state.total.totalStat} </p>
<Table rowKey="id" loading={this.state.loading} dataSource={this.state.ListData} columns={this.state.TableCol} />
</div>
</div>
)
}
}

View File

@@ -0,0 +1,314 @@
import React, { Component } from 'react';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import style from '@/assets/less/page/TeamManagement.less';
import { Layout, Menu, Breadcrumb, Rate, Row, Col, Select, Input, DatePicker, Button, Table } from 'antd';
import NavTitle from "@/components/NavTitle";
import { DesktopOutlined,
PieChartOutlined,
FileOutlined,
TeamOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
const { RangePicker } = DatePicker;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
const { Option } = Select;
/**
* 财务管理 - 资金流水
*/
@LoadDemand
export default class FinancialManagement extends Component {
state = {
disabledType: false,
params: {
text_field: '', // 精确搜索的select
text_value: '', // 精确搜索的input值
model_type: '', // 一级
sub_type: '', // 二级subtype的数组为空时查询所有
date_field: 'create_time', // 时间字段
date_range: '', // 时间段
limit: 10, // 每页显示数量
page: 1, // 页码
},
options: [
{
value: 'task',
label: '任务',
children: [
{
value: '1',
label: '任务本金',
},
{
value: '2',
label: '任务佣金',
},
{
value: '3',
label: '评价佣金',
},
{
value: '4',
label: '推广收益',
},
{
value: '5',
label: '押款本金',
},
{
value: '6',
label: '押款佣金',
},
{
value: '7',
label: '押款评价佣金',
},
{
value: '8',
label: '快递',
},
],
},
{
value: 'charge',
label: '充值',
children: [
{
value: '1',
label: '银行卡',
},
],
},
],
tableCol: [
{
title: '流水号',
dataIndex: 'model_id',
key: 'model_id',
},
{
title: '发生金额',
dataIndex: 'amount',
key: 'amount',
},
{
title: '变化前',
dataIndex: 'before_balance',
key: 'before_balance',
},
{
title: '变化后',
dataIndex: 'after_balance',
key: 'after_balance',
},
{
title: '发生时间',
dataIndex: 'create_time',
key: 'create_time',
},
{
title: '是由',
dataIndex: 'sub_type_text',
key: 'sub_type_text',
},
{
title: '备注',
dataIndex: 'remark',
key: 'remark',
},
],
currentTypeIndex: 0,
recordListData: [],
PageCount: 0, // 总页数
}
async componentDidMount() {
await this.recordList()
}
async recordList() {
let res = await UserServiceImp.recordList(this.state.params);
if (res != null && res.hasOwnProperty("list")) {
res.list.forEach((val: any, i: number) => {
val.before_balance = Utils.conversionMoney(val.before_balance);
val.after_balance = Utils.conversionMoney(val.after_balance);
val.amount = Utils.conversionMoney(val.amount);
val.key = i
});
this.setState({ recordListData: res.list, PageCount: res.count })
}
}
render() {
return (
<div>
<NavTitle title="财务管理"></NavTitle>
<div className="items">
<p className='cTitle'></p>
<div className={style.info}>
<div className={style.item}>
<p className={style.title}></p>
<span className={style.tNumber}>999.00</span>
</div>
<div className={style.line}></div>
<div className={style.item}>
<p className={style.title}></p>
<span className={style.tNumber}>999.00</span>
</div>
<div className={style.line}></div>
<div className={style.item}>
<p className={style.title}></p>
<span className={style.tNumber}>99999.00</span>
</div>
</div>
</div>
<div className="items">
<p className='cTitle'></p>
<p>真实姓名: xxxxx</p>
<p>身份证: xxxx</p>
<p>开户地址: xxxxx</p>
<p>收款方开户行: xxxxx</p>
<p>银行帐号: xxxxx</p>
</div>
<div className="items">
<p className='cTitle'></p>
<Row>
{/*任务编号*/}
<Col span={2}>
<Select
defaultValue="资金流水号"
style={{ width: '100%' }}
onChange={(value: any) => {
this.state.params.text_field = value
}}>
<Option value="record"></Option>
<Option value="task"></Option>
<Option value="charge"></Option>
</Select>
</Col>
{/*输入搜索内容*/}
<Col span={4} style={{ marginRight: '10px' }}>
<Input
placeholder="请输入搜索内容"
onChange={e => {
if (e.target.value.length != 0) {
this.setState({ disabledType: true });
this.state.params.model_type = '';
this.state.params.sub_type = '';
this.state.params.text_value = e.target.value;
} else {
this.setState({ disabledType: false });
}
}}
/>
</Col>
{/*任务的交易类型*/}
<Col span={2}>
<Select
defaultValue="交易类型"
disabled={this.state.disabledType}
style={{ width: '100%' }}
onChange={(index: any) => {
this.state.params.model_type = this.state.options[index]['value'];
this.state.params.text_value = '';
this.state.params.text_field = '';
this.setState({ currentTypeIndex: index });
}}>
{this.state.options.map((val, index) => {
return (
<Option key={index} value={index}>
{val.label}
</Option>
);
})}
</Select>
</Col>
<Col span={2} style={{ marginRight: '10px' }}>
<Select
defaultValue="交易类型"
disabled={this.state.disabledType}
style={{ width: '100%' }}
onChange={(value: any) => {
this.state.params.sub_type = value;
this.state.params.text_value = '';
this.state.params.text_field = '';
}}>
{this.state.options[this.state.currentTypeIndex]['children'].map((val, index) => {
return (
<Option key={index} value={val.value}>
{val.label}
</Option>
);
})}
</Select>
</Col>
{/*选择事件范围*/}
<Col span={3} style={{ marginRight: '10px' }}>
<RangePicker
// @ts-ignore
onChange={(date: Date, dateString: Array<any>) => {
if (dateString.join(' - ') != ' - ') {
this.state.params.date_range = dateString.join(' - ');
} else {
this.state.params.date_range = '';
}
}}/>
</Col>
{/*搜索按钮*/}
<Col span={2}>
<Button
type="primary"
onClick={async () => {
await this.recordList()
}}>
</Button>
</Col>
</Row>
<br/>
{/*数据展示的表格*/}
<div className=''>
<Table
dataSource={this.state.recordListData}
pagination={{
showSizeChanger: true,
showQuickJumper: false,
current: this.state.params.page,
showTotal: () => `${this.state.PageCount}`,
total: this.state.PageCount,
pageSize: this.state.params.limit,
onShowSizeChange: async (current, size) => {
this.state.params.page = current;
this.state.params.limit = size;
await this.recordList();
},
onChange: async (current)=> {
this.state.params.page = current;
await this.recordList();
console.log("current: ", current);
}
}}
columns={this.state.tableCol}
/>
</div>
</div>
</div>
)
}
}

View File

@@ -0,0 +1,271 @@
import React, { Component } from 'react';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import style from '@/assets/less/page/TeamManagement.less';
import { Layout, Menu, Modal, Rate, Row, Col, Select, Space, DatePicker, Button, Table, Form, Input } from 'antd';
import NavTitle from "@/components/NavTitle";
import { DesktopOutlined,
PieChartOutlined,
FileOutlined,
TeamOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
const { RangePicker } = DatePicker;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
const { Option } = Select;
const { TextArea } = Input;
@LoadDemand
export default class InvitationCodeManagement extends Component {
state = {
inviteCodeList: [], // 邀请码列表
inviteCodeCol: [ // 邀请码表头
{
title: '邀请码序号',
dataIndex: 'id',
key: 'id',
},
{
title: '推广渠道',
dataIndex: 'channel_text',
key: 'channel_text',
},
{
title: '邀请码',
dataIndex: 'invite_code',
key: 'invite_code',
},
{
title: '备注说明',
dataIndex: 'remark',
key: 'remark',
},
{
title: '添加时间',
dataIndex: 'create_time',
key: 'create_time',
},
{
title: '操作',
key: 'x',
render: (text: any, record: any) => (
<Space size="middle">
<a onClick={async ()=>{
this.state.channelList.forEach((val:any,index: number)=> {
if (val.title === record.channel_text) { record.qid = val.id }
});
this.state.editParams = record;
this.state.isShowEdit = true
await this.setState({ })
}}></a>
</Space>
),
},
],
channelList: [], // 推广渠道
isShowAdd: false, // 是否展示添加邀请码的弹窗
isShowEdit: false, // 是否展示编辑邀请码的弹窗
editParams: {}, // 保存编辑修改 邀请码的参数
loading: false,
}
async componentDidMount() {
// 推广渠道
await this.getChannelList()
await this.getCodeList()
}
/**
* 邀请码列表
*/
async getCodeList() {
this.setState({ loading: true })
let res = await UserServiceImp.codeList({});
res.forEach((val:any,index:number)=> {
val.key = index;
val.create_time = Utils.formatDate(val.create_time)
})
this.setState({ inviteCodeList: res, loading: false})
}
/**
* 推广渠道列表
*/
async getChannelList() {
let data = await UserServiceImp.channelList({});
console.log(data);
this.setState({ channelList: data });
}
/**
* 添加推广邀请码
* @param params
*/
async addCode(params: any) {
console.log(params);
let res = await UserServiceImp.addCode(params)
if (res === undefined) {
console.log("undefined: ",res);
return false;
}
if (res === null) {
this.setState({ isShowAdd: false })
await this.getCodeList()
return false;
}
}
/**
* 编辑邀请码
*/
async editCode() {
console.log(this.state.editParams);
let res = await UserServiceImp.modifyCode({
code_id: (this.state.editParams as any).id,
channel_id: (this.state.editParams as any).qid,
invite_code: (this.state.editParams as any).invite_code,
remark: (this.state.editParams as any).remark
});
if (res === null) {
this.setState({ isShowEdit: false });
await this.getCodeList()
}
console.log("编辑邀请码: ", res);
}
render() {
const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 16 },
};
const tailLayout = {
wrapperCol: { offset: 4, span: 16 },
};
return (
<div className="InvitationCodeManagement">
<NavTitle title='邀请码管理'></NavTitle>
<div className="items">
<p className='cTitle'></p>
<Button type="primary" style={{ marginBottom: 10 }} onClick={()=>{ this.setState({ isShowAdd: true }) }}></Button>
<Table loading={this.state.loading} dataSource={this.state.inviteCodeList} columns={this.state.inviteCodeCol} />
</div>
<Modal
title="编辑邀请码"
destroyOnClose={true}
visible={this.state.isShowEdit}
footer=''
onCancel={() => {
this.setState({ isShowEdit: false })
}}>
<Row style={{ marginBottom: 24 }}>
<Col span={4}>广</Col>
<Col span={14}>
<Select onChange={(e)=>{ (this.state.editParams as any).qid = e }}
defaultValue={(this.state.editParams as any).qid} style={{ width: '100%' }}>
{
this.state.channelList.map((val:any,index: number) => {
return (
<Option key={index} value={val.id}>{val.title}</Option>
)
})
}
</Select>
</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col span={4}></Col>
<Col span={14}>
<Input onChange={(e)=>{
(this.state.editParams as any).invite_code = e.target.value;
this.setState({})
}} placeholder='请输入邀请码' value={(this.state.editParams as any).invite_code}/>
</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col span={4}></Col>
<Col span={14}>
<TextArea onChange={(e)=>{
(this.state.editParams as any).remark = e.target.value;
this.setState({})
}} placeholder='请输入备注信息' value={(this.state.editParams as any).remark}/>
</Col>
</Row>
<Row>
<Col span={4}></Col>
<Col span={14}>
<Button type='primary' style={{ width: 88 }} onClick={async ()=> {
await this.editCode()
}}></Button>
</Col>
</Row>
</Modal>
<Modal
title="添加邀请码"
visible={this.state.isShowAdd}
footer=''
onCancel={() => {
this.setState({ isShowAdd: false })
}}>
<Form
{...layout}
name="basic"
initialValues={{ remember: true }}
onFinish={this.addCode.bind(this)}>
<Form.Item
label="推广渠道"
name="channel_id"
rules={[{ required: true, message: '请输入选择' }]}>
<Select defaultValue="请选择渠道" style={{ width: '100%' }}>
{
this.state.channelList.map((val:any,index: number) => {
return (
<Option key={index} value={val.id}>{val.title}</Option>
)
})
}
</Select>
</Form.Item>
<Form.Item
name="invite_code"
label="邀请码"
rules={[{ required: true, message: '请输入邀请码' }]}>
<Input placeholder='请输入邀请码'/>
</Form.Item>
<Form.Item
name="remark"
label="备注信息"
rules={[{ required: true, message: '请输入备注信息' }]}>
<TextArea rows={4} placeholder='请输入备注信息'/>
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
</Button>
</Form.Item>
</Form>
</Modal>
</div>
)
}
}

View File

@@ -0,0 +1,118 @@
import React, { Component } from 'react';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import style from '@/assets/less/page/TeamManagement.less';
import { Layout, Menu, Modal, Rate, Row, Col, Select, Input, DatePicker, Button, Table, Cascader } from 'antd';
import NavTitle from "@/components/NavTitle";
import { DesktopOutlined,
PieChartOutlined,
FileOutlined,
TeamOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
import CityData from '../core/utils/city';
const { TextArea } = Input;
const { RangePicker } = DatePicker;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
const { Option } = Select;
@LoadDemand
export default class PersonalData extends Component {
state = {
oldPwd: '',
newPwd: '',
okPwd: '',
UserInfo: Utils.getUserInfo()
}
async changePwd() {
if (this.state.newPwd != this.state.okPwd) {
Modal.error({
title: '错误提示',
content: '两次密码不一致,请检查',
});
return false
}
let res = await UserServiceImp.setPassword({
origin_password: this.state.oldPwd,
new_password: this.state.newPwd,
repeat_password: this.state.okPwd,
});
console.log(res);
}
render() {
return (
<div className="PersonalData">
<NavTitle title="个人资料"></NavTitle>
<div className="items">
<p className='cTitle'></p>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>{this.state.UserInfo ? this.state.UserInfo.true_name : ''}</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}>QQ</Col>
<Col span={12}>{this.state.UserInfo ? this.state.UserInfo.qq : ''}</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>{this.state.UserInfo ? this.state.UserInfo.wechat : ''}</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>{this.state.UserInfo ? this.state.UserInfo.balance : ''}</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>{this.state.UserInfo ? this.state.UserInfo.refer_num : ''}</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>{this.state.UserInfo ? this.state.UserInfo.last_login_time : ''}</Col>
</Row>
</div>
<div className="items">
<p className='cTitle'></p>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>
<Input onChange={(e)=> {
this.setState({ oldPwd: e.target.value })
}} placeholder='请输入原密码'></Input>
</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>
<Input.Password onChange={(e)=> {
this.setState({ newPwd: e.target.value })
}} placeholder='请输入新密码'/>
</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>
<Input.Password onChange={(e)=> {
this.setState({ okPwd: e.target.value })
}} placeholder='请输入确认新密码'/>
</Col>
</Row>
<Row style={{ marginBottom: 24 }}>
<Col style={{ marginRight: 20 }} span={1}></Col>
<Col span={12}>
<Button onClick={async ()=>{
await this.changePwd()
}} type='primary'> </Button>
</Col>
</Row>
</div>
</div>
);
}
}

View File

@@ -0,0 +1,287 @@
import React, { Component } from 'react';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import style from '@/assets/less/page/TeamManagement.less';
import { Layout, Menu, Breadcrumb, Rate, Row, Col, Select, Input, DatePicker, Button, Table } from 'antd';
import NavTitle from "@/components/NavTitle";
import { DesktopOutlined,
PieChartOutlined,
FileOutlined,
TeamOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
const { RangePicker } = DatePicker;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
const { Option } = Select;
@LoadDemand
export default class PromotionEffect extends Component{
state = {
disabledType: false,
params: {
text_field: '', // 精确搜索的select
text_value: '', // 精确搜索的input值
model_type: '', // 一级
sub_type: '', // 二级subtype的数组为空时查询所有
dateField: 'create_time', // 时间字段
dateRange: '', // 时间段
limit: 10, // 每页显示数量
page: 1, // 页码
loading: false
},
options: [
{
value: 'task',
label: '任务',
children: [
{
value: '1',
label: '任务本金',
},
{
value: '2',
label: '任务佣金',
},
{
value: '3',
label: '评价佣金',
},
{
value: '4',
label: '推广收益',
},
{
value: '5',
label: '押款本金',
},
{
value: '6',
label: '押款佣金',
},
{
value: '7',
label: '押款评价佣金',
},
{
value: '8',
label: '快递',
},
],
},
{
value: 'charge',
label: '充值',
children: [
{
value: '1',
label: '银行卡',
},
],
},
],
tableCol: [
{
title: '流水号',
dataIndex: 'model_id',
key: 'model_id',
},
{
title: '发生金额',
dataIndex: 'amount',
key: 'amount',
},
{
title: '变化前',
dataIndex: 'before_balance',
key: 'before_balance',
},
{
title: '变化后',
dataIndex: 'after_balance',
key: 'after_balance',
},
{
title: '发生时间',
dataIndex: 'create_time',
key: 'create_time',
},
{
title: '是由',
dataIndex: 'sub_type_text',
key: 'sub_type_text',
},
{
title: '备注',
dataIndex: 'remark',
key: 'remark',
},
],
currentTypeIndex: 0,
recordListData: [],
PageCount: 0, // 总页数
}
async componentDidMount() {
await this.recordList()
}
async recordList() {
this.setState({ loading: true })
let res = await UserServiceImp.recordList(this.state.params);
if (res != null && res.hasOwnProperty("list")) {
res.list.forEach((val: any, i: number) => {
val.before_balance = Utils.conversionMoney(val.before_balance);
val.after_balance = Utils.conversionMoney(val.after_balance);
val.amount = Utils.conversionMoney(val.amount);
val.key = i
});
this.setState({ recordListData: res.list, PageCount: res.count })
}
this.setState({ loading: false })
}
render() {
return (
<div>
<NavTitle title="推广效果"></NavTitle>
<div className="items">
<p className='cTitle'></p>
<Row>
{/*任务编号*/}
<Col span={2}>
<Select
defaultValue="资金流水号"
style={{ width: '100%' }}
onChange={(value: any) => {
this.state.params.text_field = value
}}>
<Option value="record"></Option>
<Option value="task"></Option>
<Option value="charge"></Option>
</Select>
</Col>
{/*输入搜索内容*/}
<Col span={4} style={{ marginRight: '10px' }}>
<Input
placeholder="请输入搜索内容"
onChange={e => {
if (e.target.value.length != 0) {
this.setState({ disabledType: true });
this.state.params.model_type = '';
this.state.params.sub_type = '';
this.state.params.text_value = e.target.value;
} else {
this.setState({ disabledType: false });
}
}}
/>
</Col>
{/*任务的交易类型*/}
<Col span={2}>
<Select
defaultValue="交易类型"
disabled={this.state.disabledType}
style={{ width: '100%' }}
onChange={(index: any) => {
this.state.params.model_type = this.state.options[index]['value'];
this.state.params.text_value = '';
this.state.params.text_field = '';
this.setState({ currentTypeIndex: index });
}}>
{this.state.options.map((val, index) => {
return (
<Option key={index} value={index}>
{val.label}
</Option>
);
})}
</Select>
</Col>
<Col span={2} style={{ marginRight: '10px' }}>
<Select
defaultValue="交易类型"
disabled={this.state.disabledType}
style={{ width: '100%' }}
onChange={(value: any) => {
this.state.params.sub_type = value;
this.state.params.text_value = '';
this.state.params.text_field = '';
}}>
{this.state.options[this.state.currentTypeIndex]['children'].map((val, index) => {
return (
<Option key={index} value={val.value}>
{val.label}
</Option>
);
})}
</Select>
</Col>
{/*选择事件范围*/}
<Col span={3} style={{ marginRight: '10px' }}>
<RangePicker
// @ts-ignore
onChange={(date: Date, dateString: Array<any>) => {
if (dateString.join(' - ') != ' - ') {
this.state.params.dateRange = dateString.join(' - ');
} else {
this.state.params.dateRange = '';
}
}}/>
</Col>
{/*搜索按钮*/}
<Col span={2}>
<Button
type="primary"
onClick={async () => {
await this.recordList()
}}>
</Button>
</Col>
</Row>
<br/>
{/*数据展示的表格*/}
<div className=''>
<Table
loading={this.state.loading}
dataSource={this.state.recordListData}
pagination={{
showSizeChanger: true,
showQuickJumper: false,
current: this.state.params.page,
showTotal: () => `${this.state.PageCount}`,
total: this.state.PageCount,
pageSize: this.state.params.limit,
onShowSizeChange: async (current, size) => {
this.state.params.page = current;
this.state.params.limit = size;
await this.recordList();
},
onChange: async (current)=> {
this.state.params.page = current;
await this.recordList();
console.log("current: ", current);
}
}}
columns={this.state.tableCol}
/>
</div>
</div>
</div>
);
}
}

View File

@@ -0,0 +1,367 @@
import React, { Component } from 'react';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import style from '@/assets/less/page/TeamManagement.less';
import { Col, Row, Rate, Button, Modal, Input, Form, Table } from 'antd';
import NavTitle from "@/components/NavTitle";
import { DesktopOutlined,
LikeFilled,
FileOutlined,
TeamOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
/**
* 团队管理
*/
@LoadDemand
export default class TeamManagement extends Component {
state = {
isShowAddTeam: false, // 是否显示添加团队的弹窗
isShowAddUser: false, // 是否显示添加下级代理的弹窗
isShowAdd: false, // 控制是否显示添加成员按钮
TeamInfo: {}, // 团队信息
TeamList: [], // 团队成员
TeamListTitle: [
{
title: '手机号',
dataIndex: 'cellphone',
key: 'cellphone',
},
{
title: '激活状态',
dataIndex: 'is_use_refer_title',
key: 'is_use_refer_title',
},
{
title: '注册时间',
dataIndex: 'create_time',
key: 'create_time',
},
{
title: '下级人数',
dataIndex: 'refer_num',
key: 'refer_num',
},
{
title: '收益',
dataIndex: 'profit',
key: 'profit',
},
{
title: '做单数',
dataIndex: 'order_num',
key: 'order_num',
},
{
title: '身份',
dataIndex: 'member_title',
key: 'member_title',
},
],
TeamLogo: [], // 团队logo
currentImageIndex: 0, // 团队logo的默认选中下标
isPreviewVisibleImage: false, // 是否显示图片预览的弹窗
}
async componentDidMount() {
await this.details()
}
/**
* 添加下级代理
* @param res
*/
async addTeamUser(res: any) {
let data = await UserServiceImp.addRefer(res);
if (data == null) {
this.setState({ isShowAddUser: false })
await this.getPeopleList()
}
}
/**
* 团队信息展示
*/
async details() {
let res = await UserServiceImp.details({
team_id: Utils.getUserInfo().team_id
});
// 没有团队信息
if (res == null) {
this.setState({ isShowAdd: false })
await this.logo()
// 如果有团队信息
} else {
this.setState({ isShowAdd: true, TeamInfo: res })
await this.getPeopleList()
}
}
/**
* 获取团队成员
*/
async getPeopleList() {
let res = await UserServiceImp.people({})
if (res !== null && res.hasOwnProperty("list")) {
res.list.forEach((val:any,index:number) => {
switch (val.member_type) {
case 'seller':
val.member_title = '商家'
break;
case 'buyer':
val.member_title = '买家'
break;
case 'refer':
val.member_title = '推广'
break;
}
switch (val.is_use_refer) {
case 0:
val.is_use_refer_title = '未激活'
break;
case 1:
val.is_use_refer_title = '已激活'
break;
}
})
this.setState({ TeamList: res.list })
}
}
/**
* 添加团队
*/
async addTeam(params:any) {
params.team_logo = (this.state.TeamLogo[this.state.currentImageIndex] as any).image_id;
let res = await UserServiceImp.addTeam(params)
// 创建团队成功
if (res == null) {
this.setState({ isShowAddTeam: false, isShowAddUser: false })
await this.details()
}
}
/**
* 获取团队logo
*/
async logo() {
let res = await UserServiceImp.logo({})
this.setState({ TeamLogo: res })
}
ShowImageMoal(url: string) {
return (
<Modal
visible={this.state.isPreviewVisibleImage}
footer={null}
onCancel={() => {
this.setState({ isPreviewVisibleImage: false })
}}>
<img style={{ width: '100%' }} src={url} />
</Modal>
)
}
render() {
const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 16 },
};
const tailLayout = {
wrapperCol: { offset: 4, span: 16 },
};
return (
<div className={style.TeamManagement}>
<NavTitle title="团队管理"></NavTitle>
{
this.state.isShowAdd
?
(
<div>
<div className="items">
<p className='cTitle'></p>
<div className={style.info}>
<div className={style.item}>
<p className={style.title}></p>
<Rate />
</div>
<div className={style.line}></div>
<div className={style.item}>
<p className={style.title}></p>
<span className={style.tNumber}>4.0</span>
<span>%</span>
</div>
<div className={style.line}></div>
<div className={style.item}>
<p className={style.title}></p>
<span className={style.tNumber}>99999.00</span>
</div>
</div>
</div>
<div className="items">
<p className='cTitle'></p>
<p>: {(this.state.TeamInfo as any).team_name}</p>
<p>: {(this.state.TeamInfo as any).team_creater || '暂无'}</p>
<p>: {(this.state.TeamInfo as any).create_time}</p>
<p>: {(this.state.TeamInfo as any).team_scale}</p>
<p>: {(this.state.TeamInfo as any).team_slogan}</p>
<p>: &nbsp;
<img onClick={() => this.setState({ isPreviewVisibleImage: true })} style={{ width: 60, borderRadius: '100%' }} src={(this.state.TeamInfo as any).image_path} alt={(this.state.TeamInfo as any).team_name}/>
{ this.ShowImageMoal((this.state.TeamInfo as any).image_path) }
</p>
</div>
<div className="items">
<p className='cTitle'></p>
<Button type='primary' style={{ marginBottom: 20 }} onClick={() => { this.setState({ isShowAddUser: true }) }}>
广
</Button>
<Table dataSource={this.state.TeamList} rowKey={(record: any) => record.id} columns={this.state.TeamListTitle} />
</div>
</div>
)
:
(
<div className="items">
<p></p>
<Button className={style.addUser} onClick={ ()=> {
this.setState({ isShowAddTeam: true })
}} type='primary'>
</Button>
</div>
)
}
<Modal
title="创建团队"
footer=''
onCancel={() => {
this.setState({ isShowAddTeam: false })
}}
visible={this.state.isShowAddTeam}>
<Form
{...layout}
name="basic"
initialValues={{ remember: true }}
onFinish={this.addTeam.bind(this)}>
<Form.Item
label="团队名称"
name="team_name"
rules={[{ required: true, message: '请输入团队名称' }]}>
<Input placeholder='请输入团队名称'/>
</Form.Item>
<Form.Item
name="team_slogan"
label="团队口号"
rules={[{ required: true, message: '请输入团队口号' }]}>
<Input placeholder='请输入团队口号'/>
</Form.Item>
<Form.Item
name="team_logo"
label="团队Logo">
{
this.state.TeamLogo.map((val:any,index)=>{
return (
<div key={index} style={
{ position: 'relative', float: 'left', marginRight: 10, }
} onClick={(e) =>{
// @ts-ignore
this.setState({ currentImageIndex: e.target.getAttribute("data-index") })
}}>
{
index == this.state.currentImageIndex
? <LikeFilled style={{ position: 'absolute', left: -5, top: -12, fontSize: 28, color: '#1890ff' }}/>
: ''
}
<img data-index={index} style={{ width: 80, height: 55 }} src={val.image_path} alt=""/>
</div>
)
})
}
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
</Button>
</Form.Item>
</Form>
</Modal>
<Modal
title="创建团队"
footer=''
onCancel={() => {
this.setState({ isShowAddUser: false })
}}
visible={this.state.isShowAddUser}>
<Form
{...layout}
name="basic"
initialValues={{ remember: true }}
onFinish={this.addTeamUser.bind(this)}>
<Form.Item
label="手机号"
name="cellphone"
rules={[{ required: true, message: '请输入手机号' }]}>
<Input placeholder='请输入手机号'/>
</Form.Item>
<Form.Item
name="password"
label="密码"
rules={[{ required: true, message: '请输入密码' }]}>
<Input.Password placeholder='请输入密码'/>
</Form.Item>
<Form.Item
name="true_name"
label="真实姓名"
rules={[{ required: true, message: '请输入真实姓名' }]}>
<Input placeholder='请输入真实姓名'/>
</Form.Item>
<Form.Item
name="qq"
label="QQ"
rules={[{ required: true, message: '请输入QQ' }]}>
<Input placeholder='请输入QQ'/>
</Form.Item>
<Form.Item
name="wechat"
label="微信"
rules={[{ required: true, message: '请输入微信' }]}>
<Input placeholder='请输入微信'/>
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
</Button>
</Form.Item>
</Form>
</Modal>
</div>
)
}
}

View File

@@ -0,0 +1,212 @@
import React, { Component } from 'react';
import { UserServiceImp } from '@service/userServiceImp';
import { connect, ConnectProps, UserModelState, history } from 'umi';
import { LoadDemand } from '@annotation/index';
import style from '@/assets/less/page/TeamManagement.less';
import { Layout, Menu, Breadcrumb, Rate, Row, Col, Select, Input, DatePicker, Button, Table, Cascader } from 'antd';
import NavTitle from "@/components/NavTitle";
import { DesktopOutlined,
PieChartOutlined,
FileOutlined,
TeamOutlined,
UserOutlined, } from '@ant-design/icons';
import { Utils } from '@/core/utils/utils';
import CityData from '../core/utils/city';
const { TextArea } = Input;
const { RangePicker } = DatePicker;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
const { Option } = Select;
/**
* 财务管理 - 提现管理
* 提现申请
* 提现列表
*/
@LoadDemand
export default class WithdrawalManagement extends Component {
state = {
TableList: [
{
title: '提现金额',
dataIndex: 'amount',
key: 'amount',
},
{
title: '提交时间',
dataIndex: 'create_time',
key: 'create_time',
},
{
title: '备注',
dataIndex: 'remark',
key: 'remark',
},
{
title: '状态',
dataIndex: 'status_text',
key: 'status_text',
},
],
BankList: [],
params: {
bank_id: '', // 银行卡id
bank_num: '', // 银行卡号
bank_owner: '', // 卡主
amount: '', // 申请提现金额
district_id: '', // 区号340000
remark: '', // 备注
},
cashOutList: [], // 提现申请列表
}
async componentDidMount() {
await this.buyerBankList()
await this.cashOutList()
}
/**
* 获取银行卡列表
*/
async buyerBankList() {
let res = await UserServiceImp.buyerBankList({});
this.setState({
BankList: res
})
}
/**
* 提交申请
*/
async cashOut() {
let res = await UserServiceImp.cashOut(this.state.params);
await this.cashOutList()
console.log(res);
}
/**
* 提现申请列表
*/
async cashOutList() {
let res = await UserServiceImp.cashOutList({})
console.log("提现申请列表: ",res);
if (res.hasOwnProperty("list")) {
res.list.forEach((val:any,index:number)=> {
val.key = index
val.create_time = Utils.formatDate(val.create_time)
val.remark = val.remark || '无'
val.amount = Utils.conversionMoney(val.amount)
if (val.status == 1) {
val.status = '提现中'
}
if (val.status == 2) {
val.status = '提现成功'
}
if (val.status == 3) {
val.status = '提现失败'
}
})
this.setState({
cashOutList: res.list
})
}
}
render() {
return (
<div>
<NavTitle title="提现管理"></NavTitle>
<div className="items">
<p className='cTitle'></p>
<Row style={{ marginBottom: 15 }}>
<Col className='rtitle' span={2}></Col>
<Col span={4}>
<Select onChange={(res)=> {
this.state.params.bank_id = res
}} defaultValue="请选择银行" style={{ width: '100%' }}>
{
this.state.BankList.map((val:any,index:number)=> {
return (
<Option key={index} value={val.id}>{val.full_name}</Option>
)
})
}
</Select>
</Col>
</Row>
<Row style={{ marginBottom: 15 }}>
<Col className='rtitle' span={2}></Col>
<Col span={4}>
<Input placeholder='请输入银行卡号' onChange={(res)=> {
// @ts-ignore
this.state.params.bank_num = res.target.value
}} type='number'/>
</Col>
</Row>
<Row style={{ marginBottom: 15 }}>
<Col className='rtitle' span={2}></Col>
<Col span={4}>
<Input placeholder='请输入持卡人姓名' onChange={(res)=> {
// @ts-ignore
this.state.params.bank_owner = res.target.value
}} type='text'/>
</Col>
</Row>
<Row style={{ marginBottom: 15 }}>
<Col className='rtitle' span={2}></Col>
<Col span={4}>
<Input placeholder='请输入提现金额' onChange={(res)=> {
// @ts-ignore
this.state.params.amount = res.target.value
}} type='number'/>
</Col>
</Row>
<Row style={{ marginBottom: 15 }}>
<Col className='rtitle' span={2}></Col>
<Col span={4}>
<Cascader
style={{ width: '100%' }}
options={CityData}
onChange={(value, selectedOptions: any) => {
this.state.params.district_id = selectedOptions[selectedOptions.length - 1].code
}}
placeholder="请选择城市"
/>
</Col>
</Row>
<Row style={{ marginBottom: 15 }}>
<Col className='rtitle' span={2}></Col>
<Col span={4}>
<TextArea onChange={(res)=>{
this.state.params.remark = res.target.value
}} rows={4} placeholder='请输入备注'/>
</Col>
</Row>
<Row style={{ marginTop: 25 }}>
<Col span={2}></Col>
<Col span={4}>
<Button onClick={async ()=> {
await this.cashOut()
}} type="primary"></Button>
</Col>
</Row>
</div>
<div className="items">
<p className='cTitle'></p>
<Table dataSource={this.state.cashOutList} columns={this.state.TableList} />
</div>
</div>
);
}
}

View File

@@ -0,0 +1,119 @@
import React, { IocComponent } from '@Ioc/index';
import { LoadDemand, routerHoc } from '@annotation/index';
import { Card, Row, Col, Tabs, Table, List, Switch } from 'antd';
import style from '@/assets/less/page/home.less';
import publicCss from '@/assets/less/public/index.less'
import { CopyOutlined } from '@ant-design/icons';
const { TabPane } = Tabs;
const data = [
'Racing car sprays burning fuel into crowd.',
'Japanese princess to wed commoner.',
'Australian walks 100km after outback crash.',
'Man charged over missing wedding girl.',
'Los Angeles battles huge wildfires.',
];
@LoadDemand
@routerHoc
class Home extends IocComponent {
state = {
loading: true,
};
onChange = (checked: boolean) => {
this.setState({ loading: !checked });
};
cardTitle() {
return (
<div className={`${publicCss.flex} ${publicCss.align}`}>
<Switch
size='small'
className={publicCss.ml10}
checked={!this.state.loading}
onChange={res => this.onChange(res)} />
<span className={style.cardTitleSpan}>()</span>
</div>
)
}
render() {
return (
<div className={style.home}>
<div className={`${publicCss.flex} ${style.header} ${publicCss.mb10}`}>
<div className={`${publicCss.flex1} ${style.header_l}`}>
<div className={`${style.title} ${publicCss.mb5}`}>151****5554</div>
<p className={publicCss.mb5}></p>
<p className={publicCss.mb5}>5</p>
</div>
<div className={`${publicCss.flex1} ${publicCss.flex} ${style.header_r}`}>
<div className={publicCss.flex1}>
<div className={`${style.title} ${publicCss.mb5}`}></div>
<div className={`${publicCss.flex} ${publicCss.mb5}`}>
<span className={publicCss.mr10}></span>
<span className={publicCss.mr10}></span>
</div>
<div className={`${publicCss.flex} ${publicCss.mb5}`}>
<span className={publicCss.mr10}></span>
<span className={publicCss.mr10}></span>
</div>
</div>
<div className={publicCss.flex1}>
<div className={`${style.title} ${publicCss.mb5}`}></div>
<div className={`${publicCss.flex} ${publicCss.mb5}`}>
<span className={publicCss.mr10}></span>
<span className={publicCss.mr10}></span>
</div>
<div className={`${publicCss.flex} ${publicCss.mb5}`}>
<span className={publicCss.mr10}></span>
<span className={publicCss.mr10}></span>
</div>
</div>
</div>
</div>
<Card
size='small'
bordered={false}
style={{ width: '100%' }}
title={this.cardTitle()}>
<div className={`${publicCss.flex} ${publicCss.pd20}`}>
<div className={`${publicCss.flex1} ${style.col}`}>
<CopyOutlined style={{fontSize: 48}} />
<div className={style.text}> <span className={style.badge}>5</span></div>
</div>
<div className={`${publicCss.flex1} ${style.col}`}>
<CopyOutlined style={{fontSize: 48}} />
<div className={style.text}> <span className={style.badge}>5</span></div>
</div>
<div className={`${publicCss.flex1} ${style.col}`}>
<CopyOutlined style={{fontSize: 48}} />
<div className={style.text}> <span className={style.badge}>5</span></div>
</div>
<div className={`${publicCss.flex1} ${style.col}`}>
<CopyOutlined style={{fontSize: 48}} />
<div className={style.text}> <span className={style.badge}>5</span></div>
</div>
<div className={`${publicCss.flex1} ${style.col}`}>
<CopyOutlined style={{fontSize: 48}} />
<div className={style.text}> <span className={style.badge}>5</span></div>
</div>
<div className={`${publicCss.flex1} ${style.col}`}>
<CopyOutlined style={{fontSize: 48}} />
<div className={style.text}> <span className={style.badge}>5</span></div>
</div>
<div className={`${publicCss.flex1} ${style.col}`}>
<CopyOutlined style={{fontSize: 48}} />
<div className={style.text}> <span className={style.badge}>5</span></div>
</div>
</div>
</Card>
</div>
);
}
}
export default Home;

View File

@@ -0,0 +1,75 @@
import React, { Component } from 'react';
import style from '@assets/less/page/Login.less';
import { Form, Input, Button, Checkbox } from 'antd';
import { Utils } from '@/core/utils/utils';
import { UserServiceImp } from '@/core/service/imp/userServiceImp';
export default class Login extends Component {
state = {};
private layout: object = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
private butLayout: object = {
wrapperCol: { offset: 4, span: 16 },
};
async UserLogin(values: { username: string, password: string }) {
let res = await UserServiceImp.login({
cellphone: values.username,
password: values.password
});
console.log(res);
if ( res != undefined && res.hasOwnProperty("token")) {
// 获取用户的详细信息
let par = await UserServiceImp.userInfo({});
par.token = res.token
localStorage.setItem("token", JSON.stringify(par))
// // @ts-ignore
location.href = "#/home"
}
}
render() {
const onFinishFailed = (errorInfo: any) => {};
return (
<div className={style.login}>
<div className={style.form}>
<h2>广</h2>
<Form
{...this.layout}
name="basic"
initialValues={{ remember: true }}
onFinish={this.UserLogin}
onFinishFailed={onFinishFailed}
>
<Form.Item
label="手机"
name="username"
rules={[{ required: true, message: '请输入你的账号!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="密码"
name="password"
rules={[{ required: true, message: '请输入你的密码!' }]}
>
<Input.Password />
</Form.Item>
<Form.Item {...this.butLayout}>
<Button type="primary" htmlType="submit" block>
</Button>
</Form.Item>
</Form>
</div>
<div className={style.footer}>© 2020 </div>
</div>
);
}
}

View File

@@ -0,0 +1,73 @@
import React, { Component } from 'react';
import { LoadDemand } from '@annotation/index';
import { Card, Tabs, Table } from 'antd';
@LoadDemand
class Message extends Component {
state = {
selectedRowKeys: [],
pagination: {
defaultCurrent: 6,
total: 500,
showSizeChanger: true,
showQuickJumper: true,
},
};
// 选中的行
private onSelectChange = (selectedRowKeys: any) => {
console.log('selectedRowKeys changed: ', selectedRowKeys);
this.setState({ selectedRowKeys });
};
render() {
const { TabPane } = Tabs;
const columns = [
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Age',
dataIndex: 'age',
},
{
title: 'Address',
dataIndex: 'address',
},
];
const data = [];
for (let i = 0; i < 46; i++) {
data.push({
key: i,
name: `Edward King ${i}`,
age: 32,
address: `London, Park Lane no. ${i}`,
});
}
const { selectedRowKeys } = this.state;
const rowSelection = {
selectedRowKeys,
onChange: this.onSelectChange,
};
return (
<div>
<Card style={{ width: '100%' }}>
<Tabs defaultActiveKey="1">
<TabPane tab="消息中心" key="1">
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={data}
pagination={this.state.pagination}
/>
</TabPane>
</Tabs>
,
</Card>
</div>
);
}
}
export default Message;

View File

@@ -0,0 +1,240 @@
import React, { Component, Props } from 'react';
import style from '@assets/less/page/Login.less';
import { Form, Input, Button, Checkbox, Upload, Modal } from 'antd';
import { Utils } from '@/core/utils/utils';
import { UserServiceImp } from '@/core/service/imp/userServiceImp';
import { PublicServiceImp } from '@service/publicServiceImp';
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
export default class register extends Component {
private layout: object = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
private butLayout: object = {
wrapperCol: { offset: 4, span: 18 },
};
state = {
imgList: [],
previewVisible: false,
previewTitle: '',
previewImage: '',
loading: false,
fileList: [],
time: null, // 保存定时器
isClosedSendCode: false, // 控制按钮是否可以点击
SendCodeText: '发 送', // 按钮的文字
cellphone: '', // 手机号,用于发送验证码用
}
/**
* 用户注册
* @param params
* @constructor
*/
async UserReg(params: any) {
params['images_id'] = JSON.stringify(this.state.imgList)
let res = await UserServiceImp.reg(params)
console.log("注册信息:", res);
if (res == "error") {
return false
}
if (res == null) {
console.log("等于 null");
// @ts-ignore
this.props.history.push('/login');
}
}
/**
* 上传按钮样式
*/
uploadButton() {
return (
<div>
{this.state.loading ? <LoadingOutlined /> : <PlusOutlined />}
<div className="ant-upload-text"></div>
</div>
)
}
/**
* 图片File转base64预览图
* @param file
*/
async getBase64(file: any) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
/**
* 上传文件
* @param file
* @param onSuccess
*/
async uploadFile({ file, onSuccess }: any) {
let formData = new FormData()
formData.append('file', file)
formData.append('file_type', 'refer_reg')
let res: any = await PublicServiceImp.uploadFile(formData)
if (!!res) {
// @ts-ignore
this.state.imgList.push(res)
// @ts-ignore
this.state.fileList.push(Object.assign(file, { originFileObj: file }))
this.setState({})
onSuccess(null, res.path);
}
}
async startSemcode() {
let timeText = 60
// 禁用按钮
this.setState({ isClosedSendCode: true })
let res = await UserServiceImp.getSmsCode({
cellphone: this.state.cellphone,
scene: 'reg'
});
console.log(res);
// @ts-ignore
this.state.time = setInterval(()=> {
timeText -= 1;
this.setState({ SendCodeText: `发送(${timeText})` })
if (timeText <= 0) {
// @ts-ignore
// 重置定时器
clearInterval(this.state.time)
// 重置文字
this.setState({ SendCodeText: `发 送` })
// 取消按钮禁用
this.setState({ isClosedSendCode: false })
return false
}
},1000)
}
render() {
return (
<div className={style.login}>
<div className={style.form}>
<h2>广</h2>
<Form
{...this.layout}
name="basic"
initialValues={{ remember: true }}
onFinish={this.UserReg.bind(this)}>
<Form.Item
label="手机"
name="cellphone"
rules={[{ required: true, message: '请输入手机号' }]}>
<Input placeholder='请输入手机号' type='number' onChange={(e)=> {
this.setState({ cellphone: e.target.value })
}}/>
</Form.Item>
<Form.Item
label="验证码"
name="verify_code"
rules={[{ required: true, message: '验证码' }]}>
<div>
<Input placeholder='请输入验证码' type='number' />
<Button disabled={this.state.isClosedSendCode}
type='primary'
style={{ position: 'absolute', right: 0 }} onClick={async ()=>{
await this.startSemcode()
}}>{this.state.SendCodeText}</Button>
</div>
</Form.Item>
<Form.Item
label="密码"
name="password"
rules={[{ required: true, message: '请输入密码!' }]}>
<Input type='password' placeholder='请输入密码' />
</Form.Item>
<Form.Item
label="姓名"
name="true_name"
rules={[{ required: true, message: '请输入真实姓名' }]}>
<Input type='text' placeholder='请输入真实姓名' />
</Form.Item>
<Form.Item
label="QQ"
name="qq"
rules={[{ required: true, message: '请输入真实QQ' }]}>
<Input type='number' placeholder='请输入真实QQ' />
</Form.Item>
<Form.Item
label="微信"
name="wechat"
rules={[{ required: true, message: '请输入真实微信' }]}>
<Input type='text' placeholder='请输入真实微信' />
</Form.Item>
<Form.Item
label="图片"
name="images_id">
<div>
<Upload
name="avatar"
listType="picture-card"
fileList={this.state.fileList}
onPreview={async (file: any) => {
// 预览图片
if (!file.url && !file.preview) {
file.preview = await this.getBase64(file.originFileObj);
}
this.setState({
previewImage: file.url || file.preview,
previewVisible: true,
previewTitle: file.name || file.url.substring(file.url.lastIndexOf('/') + 1),
});
}}
onRemove={async (res: any) => {
// 删除图片
let fileList: any[] = this.state.fileList
fileList.forEach((v, i) => {
if (v.uid === res.uid) {
this.state.fileList.splice(i, 1)
this.state.imgList.splice(i, 1)
this.setState({})
}
})
}}
customRequest={async (res) => {
await this.uploadFile(res)
}}>
{this.state.fileList.length >= 5 ? null : this.uploadButton()}
</Upload>
<Modal
visible={this.state.previewVisible}
title={this.state.previewTitle}
footer={null}
onCancel={()=> {
this.setState({ previewVisible: false })
}}>
<img alt="example" style={{ width: '100%' }} src={this.state.previewImage} />
</Modal>
</div>
</Form.Item>
<Form.Item {...this.butLayout}>
<Button type="primary" htmlType="submit" block>
</Button>
</Form.Item>
</Form>
</div>
<div className={style.footer}>© 2020 </div>
</div>
)
}
}

View File

@@ -0,0 +1 @@
903f9277-58c9-4490-ae3f-47e17678a6ee

View File

@@ -0,0 +1,62 @@
let routes: any[] = [
{
path: '/login',
component: '@/pages/login',
title: '登录',
},
{
path: '/reg',
component: '@/pages/register',
title: '注册',
},
{
path: '/',
component: '@/layouts/index',
name: 'index',
routes: [
{
path: '/home',
component: '@/pages/home',
title: '后台首页',
},
{
path: '/Financial',
component: '@/pages/FinancialManagement',
title: '资金流水',
},
{
path: '/Withdrawal',
component: '@/pages/WithdrawalManagement',
title: '提现管理',
},
{
path: '/TeamManagement',
component: '@/pages/TeamManagement',
title: '团队管理',
},
{
path: '/PromotionEffect',
component: '@/pages/PromotionEffect',
title: '推广效果',
},
{
path: '/AssociatedUsers',
component: '@/pages/AssociatedUsers',
title: '关联用户',
},
{
path: '/InvitationCode',
component: '@/pages/InvitationCodeManagement',
title: '邀请码管理',
},
{
path: '/PersonalData',
component: '@/pages/PersonalData',
title: '个人资料',
},
],
},
{ component: '@/pages/404' },
];
export default routes;

View File

@@ -0,0 +1 @@
66a28a04-c945-4e6d-922b-b6fe87320a12

View File

@@ -0,0 +1,6 @@
import { CSSProperties } from 'react';
// style类型
export interface StyleCssOperties {
[k: string]: CSSProperties;
}

View File

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"jsx": "react",
"esModuleInterop": true,
"experimentalDecorators": true,
"sourceMap": true,
"baseUrl": "./",
"strict": true,
"paths": {
"@/*": ["src/*"],
"@@/*": ["src/.umi/*"],
"@service/*": ["src/core/service/imp/*"],
"@assets/*": ["src/assets/*"],
"@annotation/*": ["src/core/annotation/*"],
"@components/*": ["src/components/*"],
"@page/*": ["src/assets/less/page/*"],
"@Ioc/*": ["src/core/Ioc/*"]
},
"allowSyntheticDefaultImports": true
}
}

4
滴滴淘/admin/typings.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
declare module '*.css';
declare module '*.less';
declare module "*.png";
declare module "*.tsx";

View File

@@ -0,0 +1,15 @@
历史路由还差
全部清空 完成
关闭右边 完成
关闭当前 完成
关闭其他 完成
拖动移动按钮
1~5爱心6~10 钻11~15 银色皇冠(1冠)16~20 黄色皇冠(金冠)
1~5爱心6~10 钻11~15 银色皇冠(1冠)16~20 黄色皇冠(金冠)
1 1,2 2,3 3,4 4,5 5
6 1,7 2,8 3,9 4,10 5