@@ -1,3 +1,5 @@ | |||
const path = require('path'); | |||
const config = { | |||
projectName: 'LOCKING-mini', | |||
date: '2021-6-4', | |||
@@ -9,6 +11,9 @@ const config = { | |||
}, | |||
sourceRoot: 'src', | |||
outputRoot: 'dist', | |||
alias: { | |||
'@root': path.join(__dirname, '..', 'src'), | |||
}, | |||
plugins: [], | |||
defineConstants: { | |||
}, | |||
@@ -0,0 +1,7 @@ | |||
{ | |||
"compilerOptions": { | |||
"paths": { | |||
"@root/*": ["src/*"] | |||
} | |||
} | |||
} |
@@ -39,14 +39,18 @@ | |||
"@tarojs/cli": "3.2.10", | |||
"@tarojs/components": "3.2.10", | |||
"@tarojs/react": "3.2.10", | |||
"@tarojs/redux": "^2.2.10", | |||
"@tarojs/rn-runner": "^3.2.10", | |||
"@tarojs/runtime": "3.2.10", | |||
"@tarojs/taro": "3.2.10", | |||
"@tarojs/taro-rn": "^3.2.10", | |||
"lodash": "4.17.15", | |||
"dayjs": "^1.10.5", | |||
"lodash": "^4.17.21", | |||
"react": "^17.0.0", | |||
"react-dom": "^17.0.0", | |||
"react-native": "^0.64.0", | |||
"react-redux": "^7.2.4", | |||
"redux": "^4.1.0", | |||
"redux-logger": "^3.0.6", | |||
"redux-thunk": "^2.3.0", | |||
"taro-ui": "^3.0.0-alpha.3" | |||
}, | |||
"devDependencies": { | |||
@@ -0,0 +1,67 @@ | |||
import * as storage from '@root/utils/storage'; | |||
import getData from '@root/utils/request'; | |||
import Taro from '@tarojs/taro'; | |||
import { isReqSuccess } from '@root/utils/tool'; | |||
import { firstCharToLowerCase } from '../utils/tool'; | |||
import { getFileUrl } from '../service/oss'; | |||
async function saveSafeArea(dispatch) { | |||
const res = await Taro.getSystemInfo(); | |||
if (res.safeArea) { | |||
dispatch({ | |||
type: 'app/update', | |||
payload: { | |||
safeArea: res.safeArea, | |||
} | |||
}) | |||
} | |||
} | |||
const hint = (msg) => Taro.showToast({ title: msg, icon: 'none', duration: 2000 }) | |||
export function logout() { | |||
return async (dispatch) => { | |||
storage.remove('token'); | |||
dispatch({ | |||
type: 'app/logout', | |||
}); | |||
} | |||
} | |||
export function initApp() { | |||
return async (dispatch, getState ) => { | |||
saveSafeArea(dispatch); | |||
} | |||
} | |||
export function login({ username, password }) { | |||
return async (dispatch, getState) => { | |||
const res = await getData('authentication/login', { UserName: username, Password: password }); | |||
if (!isReqSuccess(res)) { | |||
dispatch(logout()); | |||
return res; | |||
} | |||
const userData = firstCharToLowerCase(res.data); | |||
// 角色判断 | |||
// const { app: appStore } = getState(); | |||
// if (appStore.appType && userData.userType !== appStore.appType) { // 登录角色权限不符合,退出登录 | |||
// hint('账号权限不足'); | |||
// dispatch(logout()); | |||
// return false; | |||
// } | |||
console.log(getFileUrl(userData.headImgUrl)); | |||
dispatch({ | |||
type: 'app/login', | |||
payload: { | |||
accountId: userData.id, | |||
accountName: userData.cnName, | |||
customerId: userData.companyId, | |||
avatorUrl: userData.headImgUrl, | |||
} | |||
}) | |||
return res; | |||
} | |||
}; |
@@ -1,12 +1,33 @@ | |||
export default { | |||
pages: [ | |||
'pages/login/index', | |||
'pages/index/index', | |||
'pages/project/index', | |||
'pages/recycle/index', | |||
], | |||
window: { | |||
backgroundTextStyle: 'light', | |||
navigationBarBackgroundColor: '#32323C', | |||
// navigationBarTitleText: 'WeChat', | |||
// navigationBarTextStyle: 'yellow' | |||
}, | |||
tabBar: { | |||
color: "#7A7E83", | |||
selectedColor: "#007AFF", | |||
borderStyle: "black", | |||
backgroundColor: "#F8F8F8", | |||
list: [ | |||
{ | |||
pagePath: "pages/project/index", | |||
// iconPath: "static/monitor.png", | |||
// selectedIconPath: "static/monitor-selected.png", | |||
text: "我的项目" | |||
}, | |||
{ | |||
pagePath: "pages/recycle/index", | |||
// iconPath: "static/user-center.png", | |||
// selectedIconPath: "static/user-center-selected.png", | |||
text: "回收站" | |||
} | |||
] | |||
} | |||
} |
@@ -1,21 +0,0 @@ | |||
import { Component } from 'react' | |||
import './app.scss' | |||
import './custom-taroui-variables.scss'; | |||
class App extends Component { | |||
componentDidMount () {} | |||
componentDidShow () {} | |||
componentDidHide () {} | |||
componentDidCatchError () {} | |||
// this.props.children 是将要会渲染的页面 | |||
render () { | |||
return this.props.children | |||
} | |||
} | |||
export default App |
@@ -0,0 +1,32 @@ | |||
import { Component } from 'react' | |||
import './app.scss' | |||
import './custom-taroui-variables.scss'; | |||
import configStore from './store'; | |||
import { initApp } from '@root/actions/app'; | |||
import { Provider } from 'react-redux'; | |||
const store = configStore(); | |||
class App extends Component { | |||
componentDidMount () { | |||
store.dispatch(initApp()); | |||
} | |||
componentDidShow () {} | |||
componentDidHide () {} | |||
componentDidCatchError () {} | |||
// this.props.children 是将要会渲染的页面 | |||
render () { | |||
return ( | |||
<Provider store={store}> | |||
{this.props.children} | |||
</Provider> | |||
) | |||
} | |||
} | |||
export default App |
@@ -1,3 +0,0 @@ | |||
export default { | |||
navigationBarTitleText: '首页' | |||
} |
@@ -1,32 +0,0 @@ | |||
import { Component } from 'react' | |||
import { View, Text } from '@tarojs/components' | |||
import { AtButton } from 'taro-ui' | |||
import "taro-ui/dist/style/components/button.scss" // 按需引入 | |||
import './index.scss' | |||
export default class Index extends Component { | |||
componentWillMount () { } | |||
componentDidMount () { } | |||
componentWillUnmount () { } | |||
componentDidShow () { } | |||
componentDidHide () { } | |||
render () { | |||
return ( | |||
<View className='index'> | |||
<Text>Hello world!</Text> | |||
<AtButton type='primary'>I need Taro UI</AtButton> | |||
<Text>Taro UI 支持 Vue 了吗?</Text> | |||
<AtButton type='primary' circle={true}>支持</AtButton> | |||
<Text>共建?</Text> | |||
<AtButton type='secondary' circle={true}>来</AtButton> | |||
</View> | |||
) | |||
} | |||
} |
@@ -1,22 +1,58 @@ | |||
import { Text, View } from '@tarojs/components'; | |||
import React, { useState } from 'react'; | |||
import Taro from '@tarojs/taro'; | |||
import React, { useCallback, useEffect, useState } from 'react'; | |||
import { AtButton } from 'taro-ui'; | |||
import YInput from '../../components/YInput'; | |||
import YInput from '@root/components/YInput'; | |||
import styles from './index.module.scss'; | |||
import { login } from '@root/actions/app'; | |||
import { useDispatch } from 'react-redux'; | |||
import { isReqSuccess } from '@root/utils/tool'; | |||
const inputField = setter => ({ detail: { value } }) => setter(value); | |||
export default function Login() { | |||
const [errText, setErrText] = useState(''); | |||
const [account, setAccount] = useState(''); | |||
const [password, setPassword] = useState(''); | |||
const dispatch = useDispatch(); | |||
const onLogin = useCallback(async () => { | |||
if(!account) { hint('账号/手机号不能为空'); return;} | |||
if (!password) { hint('密码不能为空'); return; } | |||
Taro.showLoading({ title: '', mask: true }); | |||
const res = await dispatch(login({ | |||
username: account, | |||
password: password, | |||
})); | |||
Taro.hideLoading(); | |||
if(!isReqSuccess(res)) { | |||
setErrText(res.msg); | |||
return; | |||
} | |||
Taro.switchTab({ url: '/pages/project/index' }); | |||
}, [account, password, dispatch]); | |||
useEffect(() => { | |||
setErrText(''); | |||
}, [account, password]) | |||
return ( | |||
<View className={styles.main}> | |||
<Text className={styles.logo}>LOCKING</Text> | |||
<YInput wrapperClassName={styles.inpWrapper} placeholder="请输入手机号或账号" /> | |||
<YInput wrapperClassName={styles.inpWrapper} placeholder="请输入密码" type="password" > | |||
<YInput wrapperClassName={styles.inpWrapper} placeholder="请输入手机号或账号" | |||
value={account} | |||
onInput={inputField(setAccount)} | |||
/> | |||
<YInput wrapperClassName={styles.inpWrapper} placeholder="请输入密码" type="password" | |||
value={password} | |||
onInput={inputField(setPassword)} | |||
> | |||
{/* <Text>忘记密码</Text> */} | |||
</YInput> | |||
<View className={styles.err}> | |||
{errText ? <Text>{errText}</Text>: null } | |||
</View> | |||
<AtButton className={styles.button} type="primary">登入</AtButton> | |||
<AtButton className={styles.button} type="primary" onClick={onLogin}>登入</AtButton> | |||
</View> | |||
) | |||
} |
@@ -0,0 +1,39 @@ | |||
const initState = { | |||
isLogin:false, | |||
safeArea: {}, | |||
accountId: '', | |||
accountName: '', | |||
companyId: '', | |||
avatorUrl: '', | |||
} | |||
export default (state = initState, { type, payload }) => { | |||
switch (type) { | |||
case 'app/update': | |||
return { | |||
...state, | |||
...payload, | |||
}; | |||
case 'app/login': | |||
return { | |||
...state, | |||
isLogin: true, | |||
...payload, | |||
} | |||
case 'app/logout': | |||
return { | |||
...state, | |||
isLogin: false, | |||
accountId: '', | |||
accountName: '', | |||
customerType: '', // 'provider' | 'ent' ent: 企业用户 | provider: 华能用户 | |||
customerId: '', | |||
customerName: '', | |||
customerShortName: '', | |||
orgId: '', | |||
} | |||
default: | |||
return state; | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
import { combineReducers } from 'redux'; | |||
import app from './app'; | |||
export default combineReducers({ | |||
app, | |||
}) |
@@ -0,0 +1,45 @@ | |||
import { memoize } from 'lodash'; | |||
// import { getData } from './request'; | |||
// const client = new OSS({ | |||
// region: 'oss-cn-hangzhou', | |||
// accessKeyId: 'LTAI4G2BEDNpfdLmquYYMaMV', | |||
// accessKeySecret: 'tPhAL3qAgF9Tq67h73snAmwu8iPZ5t', | |||
// bucket: 'yiyun-client-files', | |||
// secure: true, | |||
// }); | |||
/** | |||
* 存储逻辑 | |||
* + oss上的存储文件路径为 时间戳 / 文件名 | |||
* + 文件路径信息保存到服务器端时,添加拟协议头 oss:// | |||
* + 示例: | |||
* 文件名为oss.js | |||
* 则在oss上保存的路径为 1601016877378/oss.js | |||
* 在服务器上存储的记录为: oss://1601016877378/oss.js | |||
*/ | |||
// const generateStoreKey = name => `${new Date().getTime()}/${name}`; | |||
export const wrapOssProtocol = path => `oss://${path}`; | |||
/** | |||
* | |||
* @param {*} objectKey 文件在服务器上的path值,格式为: oss://${timestamp}/filename | |||
* @param {*} saveAs | |||
*/ | |||
export const getFileUrl = memoize(function getFileUrlInner(serverOSSPath = '', saveAs) { | |||
if (serverOSSPath.indexOf('oss://') !== 0) { | |||
return serverOSSPath; | |||
} | |||
const objectKey = serverOSSPath.substr(6); | |||
// const filename = saveAs || objectKey.split('/').pop(); | |||
return `https://yiyun-client-files.oss-cn-hangzhou.aliyuncs.com/${objectKey}`; | |||
}) | |||
// export async function saveStr(saveAs, str) { | |||
// return await getData('oss', 'saveStr', { saveAs, context: str }); | |||
// } | |||
// export async function getContext(objectKey) { | |||
// const data = await getData('oss', 'getContext', { objectKey }); | |||
// if (!data.type && data.code && data.code !== 'error') return null; | |||
// return data.data; | |||
// } |
@@ -0,0 +1,28 @@ | |||
import { createStore, applyMiddleware, compose } from 'redux' | |||
import thunkMiddleware from 'redux-thunk' | |||
import rootReducer from '../reducers' | |||
const composeEnhancers = | |||
typeof window === 'object' && | |||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? | |||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ | |||
// Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize... | |||
}) : compose | |||
const middlewares = [ | |||
thunkMiddleware | |||
] | |||
if (process.env.NODE_ENV === 'development' && process.env.TARO_ENV !== 'quickapp') { | |||
middlewares.push(require('redux-logger').createLogger()) | |||
} | |||
const enhancer = composeEnhancers( | |||
applyMiddleware(...middlewares), | |||
// other store enhancers if any | |||
) | |||
export default function configStore () { | |||
const store = createStore(rootReducer, enhancer) | |||
return store | |||
} |
@@ -0,0 +1,53 @@ | |||
const pmsServiceMap = ['template', 'project', 'folder', 'file', 'templateCompany', 'projectLinkInvite', 'lockingmsg'] | |||
.reduce((h, str) => (h[str] = 'pms', h), {}); | |||
const postRequestMap = [ | |||
'authentication/login', | |||
'authentication/passwordCheck', | |||
'company/addCompany', | |||
'company/queryGeneralOverview', | |||
'company/queryProviceTree', | |||
'company/updateCompanyById', | |||
'company/link/addCompanyLink', | |||
'company/link/updateCompanyLink', | |||
'dept/addDept', | |||
'dept/updateDept', | |||
'user/addUser', | |||
'user/resetPassWord', | |||
'user/updateUser', | |||
'template/createTemplate', | |||
'template/fileExchange', | |||
'template/updateTemplate', | |||
'template/uploadingXmind', | |||
'template/addTemplateNodeModelFile', | |||
'template/createNestedRelevance', | |||
'template/connectNestTemplateFolder', | |||
"folder/createSubfolder", | |||
"project/createProject", | |||
"project/editProject", | |||
"project/assignedWork", | |||
"file/addArchMilesStone", | |||
"file/addFile", | |||
"file/updateFile", | |||
"file/fileCoordinationChange", | |||
"file/setShareFile", | |||
"operation/record", | |||
"file/updateProjArchiveHistory", | |||
"templateCompany/addTemplateCompany", | |||
"project/addProjectGobalConfig", | |||
"project/linkProject", | |||
'file/submitDeliverables', | |||
'lockingmsg/markRead', | |||
'file/removeFromRecycleBin', | |||
'file/batchAddFile', | |||
].reduce((h, str) => (h[str] = 'POST', h), {}); | |||
export function parseRequest(path) { | |||
const [service] = path.split('/'); | |||
const prefix = pmsServiceMap[service] || 'cms'; | |||
const fullpath = `api/${prefix}/${service === 'authentication' ? '' : 'v1/'}${path}`; | |||
const method = postRequestMap[path] || 'GET'; | |||
return [method, fullpath]; | |||
} |
@@ -0,0 +1,24 @@ | |||
import Taro from '@tarojs/taro'; | |||
import { parseRequest } from './request.config'; | |||
import { firstCharToLowerCase } from './tool'; | |||
const ip = 'http://139.198.180.242:9003'; | |||
const header = { 'Content-Type': 'application/json' }; | |||
const getData = async (path, params = {}) => { | |||
const datas = JSON.stringify({ ...params }); | |||
const [method, fullpath] = parseRequest(path); | |||
const httpResponse = await Taro.request({ | |||
url: `${ip}/${fullpath}`, | |||
data: datas, | |||
header, | |||
method, | |||
}); | |||
if (httpResponse.statusCode !== 200) { | |||
debugger; | |||
} | |||
return firstCharToLowerCase(httpResponse.data); | |||
} | |||
export default getData; |
@@ -0,0 +1,13 @@ | |||
import Taro from '@tarojs/taro'; | |||
export function get(key) { | |||
return Taro.getStorageSync(key); | |||
} | |||
export function set(key, value) { | |||
Taro.setStorageSync(key, value); | |||
} | |||
export function remove(key) { | |||
Taro.removeStorageSync(key); | |||
} |
@@ -0,0 +1,17 @@ | |||
export const isReqSuccess = res => res.code === 0 || res.Code === 0; | |||
export function firstCharToLowerCase(obj) { | |||
return Object.entries(obj).reduce((o, [key, value]) => { | |||
o[`${key[0].toLocaleLowerCase()}${key.slice(1)}`] = value; | |||
return o; | |||
},{}); | |||
} | |||
export function firstCharToUpperCase(obj) { | |||
return Object.entries(obj).reduce((o, [key, value]) => { | |||
o[`${key[0].toLocaleUpperCase()}${key.slice(1)}`] = value; | |||
return o; | |||
},{}); | |||
} |