mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-11-15 23:23:52 +08:00
v2.0 代码提交
This commit is contained in:
16
smart_admin_v1/smart-admin-h5/src/App.vue
Normal file
16
smart_admin_v1/smart-admin-h5/src/App.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
#nprogress .bar {
|
||||
background: #1989fa !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
43
smart_admin_v1/smart-admin-h5/src/api/employee.js
Normal file
43
smart_admin_v1/smart-admin-h5/src/api/employee.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { postAxios, getAxios } from '@/lib/http';
|
||||
export const employeeApi = {
|
||||
// 员工管理查询
|
||||
getEmployeeList: (data) => {
|
||||
return postAxios('admin/employee/query', data);
|
||||
},
|
||||
// 添加员工
|
||||
addEmployee: (data) => {
|
||||
return postAxios('admin/employee/add', data);
|
||||
},
|
||||
// 更新员工信息
|
||||
updateEmployee: (data) => {
|
||||
return postAxios('admin/employee/update', data);
|
||||
},
|
||||
// 禁用启用单个员工
|
||||
updateStatus: (employeeId, status) => {
|
||||
return getAxios('admin/employee/updateStatus/' + employeeId + '/' + status);
|
||||
},
|
||||
// 批量禁用
|
||||
updateStatusBatch: (data) => {
|
||||
return postAxios('admin/employee/batchUpdateStatus', data);
|
||||
},
|
||||
// 单个员工角色授权
|
||||
updateRoles: (data) => {
|
||||
return postAxios('admin/employee/updateRoles', data);
|
||||
},
|
||||
// 修改密码
|
||||
updatePwd: (data) => {
|
||||
return postAxios('admin/employee/updatePwd', data);
|
||||
},
|
||||
// 重置密码
|
||||
resetPassword: (employeeId) => {
|
||||
return getAxios('admin/employee/resetPasswd/' + employeeId);
|
||||
},
|
||||
// 通过部门id获取当前部门的人员&没有部门的人
|
||||
getListEmployeeByDeptId: (departmentId) => {
|
||||
return getAxios('admin/employee/listEmployeeByDeptId/' + departmentId);
|
||||
},
|
||||
// 删除员工
|
||||
deleteEmployee: (employeeId) => {
|
||||
return postAxios('admin/employee/delete/' + employeeId);
|
||||
}
|
||||
};
|
||||
14
smart_admin_v1/smart-admin-h5/src/api/file.js
Normal file
14
smart_admin_v1/smart-admin-h5/src/api/file.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { postAxios, getAxios } from '@/lib/http';
|
||||
import config from '@/config';
|
||||
import Cookies from '@/lib/cookie';
|
||||
const baseUrl = config.baseUrl.apiUrl;
|
||||
|
||||
export const fileApi = {
|
||||
// 文件上传
|
||||
fileUpload: (folder, data) => {
|
||||
const url = baseUrl + '/common/file/upload/' + folder + '?x-access-token=' + Cookies.getToken();
|
||||
return postAxios(url, data, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
});
|
||||
}
|
||||
};
|
||||
10
smart_admin_v1/smart-admin-h5/src/api/login.js
Normal file
10
smart_admin_v1/smart-admin-h5/src/api/login.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { getAxios, postAxios } from '@/lib/http';
|
||||
|
||||
export const loginApi = {
|
||||
login: (data) => {
|
||||
return postAxios('/session/login', data);
|
||||
},
|
||||
logout: (token) => {
|
||||
return getAxios(`/session/logOut?x-access-token=${token}`);
|
||||
}
|
||||
};
|
||||
31
smart_admin_v1/smart-admin-h5/src/api/system-config.js
Normal file
31
smart_admin_v1/smart-admin-h5/src/api/system-config.js
Normal file
@@ -0,0 +1,31 @@
|
||||
// 系统参数API
|
||||
import {
|
||||
postAxios,
|
||||
getAxios
|
||||
} from '@/lib/http';
|
||||
export const systemConfigApi = {
|
||||
// 查询系统参数列表
|
||||
getSystemConfigList: (data) => {
|
||||
return postAxios('/admin/systemConfig/getListPage', data);
|
||||
},
|
||||
// 添加系统参数
|
||||
addSystemConfig: (data) => {
|
||||
return postAxios('/admin/systemConfig/add', data);
|
||||
},
|
||||
// 更新单条系统参数
|
||||
updateSystemConfig: (data) => {
|
||||
return postAxios('/admin/systemConfig/update', data);
|
||||
},
|
||||
// 通过key获取对应的信息
|
||||
getConfigListByKey: (key) => {
|
||||
return getAxios(`/admin/systemConfig/selectByKey?configKey=${key}`);
|
||||
},
|
||||
// 根据分组查询所有系统配置
|
||||
getListByGroup: (group) => {
|
||||
return getAxios(`/admin/systemConfig/getListByGroup?group=${group}`);
|
||||
},
|
||||
// 获取系统版本信息
|
||||
getCodeVersion: () => {
|
||||
return getAxios('/admin/codeVersion');
|
||||
}
|
||||
};
|
||||
7
smart_admin_v1/smart-admin-h5/src/api/user.js
Normal file
7
smart_admin_v1/smart-admin-h5/src/api/user.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { getAxios } from '@/lib/http';
|
||||
|
||||
export const userApi = {
|
||||
getSession: () => {
|
||||
return getAxios('/session/get');
|
||||
}
|
||||
};
|
||||
5
smart_admin_v1/smart-admin-h5/src/assets/css/index.scss
Normal file
5
smart_admin_v1/smart-admin-h5/src/assets/css/index.scss
Normal file
@@ -0,0 +1,5 @@
|
||||
$text-color: #323233;
|
||||
$border-color: #ebedf0;
|
||||
$active-color: #f2f3f5;
|
||||
$background-color: #f7f8fa;
|
||||
$background-color-light: #fafafa;
|
||||
BIN
smart_admin_v1/smart-admin-h5/src/assets/logo.png
Normal file
BIN
smart_admin_v1/smart-admin-h5/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @description:department-employee-selector
|
||||
* @author: zhuoda
|
||||
* @date: 2020/10/30 13:56
|
||||
*/
|
||||
|
||||
<template>
|
||||
|
||||
<div style="padding: 20px">
|
||||
<template v-if="isRadio">
|
||||
<van-radio-group v-model="radioSelectEmployeeId">
|
||||
<van-radio
|
||||
v-for="item in employeeList"
|
||||
:key="item.id"
|
||||
:name="item.id"
|
||||
style="margin-top: 5px"
|
||||
@click="clickRadio"
|
||||
>
|
||||
{{
|
||||
item.actualName
|
||||
}}
|
||||
</van-radio>
|
||||
</van-radio-group>
|
||||
</template>
|
||||
|
||||
<template v-if="!isRadio">
|
||||
<van-checkbox-group ref="checkboxGroup" :max="max" v-model="selectEmployeeList">
|
||||
<van-checkbox
|
||||
:key="item.id"
|
||||
:name="item.id"
|
||||
v-model="item._checked"
|
||||
v-for="item in employeeList"
|
||||
style="margin-top: 5px">
|
||||
{{
|
||||
item.actualName
|
||||
}}
|
||||
</van-checkbox>
|
||||
</van-checkbox-group>
|
||||
</template>
|
||||
<br>
|
||||
<van-button v-if="!isRadio" type="primary" size="small" @click="checkAll" style="margin:0 10px">全选</van-button>
|
||||
<van-button v-if="!isRadio" type="info" size="small" @click="toggleAll">反选</van-button>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { systemConfigApi } from '@/api/system-config';
|
||||
import { employeeApi } from 'api/employee';
|
||||
|
||||
export default {
|
||||
name: 'DepartmentEmployeeSelector',
|
||||
props: {
|
||||
// 最大数
|
||||
max: Number,
|
||||
isRadio: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
selectEmployeeList: [],
|
||||
employeeList: [],
|
||||
radioSelectEmployeeId: null,
|
||||
radioSelectEmployeeName: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.loadEmployeeList();
|
||||
},
|
||||
methods: {
|
||||
updateRadioSelectEmployeeId(employeeId) {
|
||||
this.radioSelectEmployeeId = employeeId;
|
||||
},
|
||||
clickRadio(e, val) {
|
||||
this.radioSelectEmployeeName = e.target.innerText;
|
||||
},
|
||||
getSelected() {
|
||||
if (this.isRadio) {
|
||||
return [{
|
||||
id: this.radioSelectEmployeeId,
|
||||
actualName: this.radioSelectEmployeeName
|
||||
}];
|
||||
} else {
|
||||
const result = [];
|
||||
for (const employee of this.employeeList) {
|
||||
if (this.selectEmployeeList.indexOf(employee.id) > -1) {
|
||||
result.push(Object.assign({}, employee));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
async loadEmployeeList() {
|
||||
this.$smart.loading();
|
||||
try {
|
||||
const departmentIdResult = await systemConfigApi.getConfigListByKey('crm_school_share_department_id');
|
||||
const employeeListResult = await employeeApi.getListEmployeeByDeptId(departmentIdResult.data.configValue);
|
||||
this.employeeList = employeeListResult.data.filter(e => e.isDelete === 0 && e.isDisabled === 0).map(e => {
|
||||
e._checked = false;
|
||||
return e;
|
||||
});
|
||||
} catch (e) {
|
||||
this.$smartSentry.captureException(e);
|
||||
} finally {
|
||||
this.$smart.loadingClear();
|
||||
}
|
||||
},
|
||||
checkAll() {
|
||||
this.$refs.checkboxGroup.toggleAll(true);
|
||||
},
|
||||
toggleAll() {
|
||||
this.$refs.checkboxGroup.toggleAll();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div>
|
||||
<van-field
|
||||
v-model="result"
|
||||
v-bind="$attrs"
|
||||
readonly
|
||||
is-link
|
||||
@click="show = !show"
|
||||
/>
|
||||
<van-popup v-model="show" position="bottom">
|
||||
<van-picker
|
||||
value-key="desc"
|
||||
:columns="columns"
|
||||
show-toolbar
|
||||
:title="$attrs.label"
|
||||
@cancel="show = !show"
|
||||
@confirm="onConfirm"
|
||||
/>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'SmartEnumSelectPicker',
|
||||
model: {
|
||||
prop: 'selectValue'
|
||||
},
|
||||
props: {
|
||||
enumName: {
|
||||
type: String
|
||||
},
|
||||
selectValue: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
result: this.selectValue,
|
||||
columns: this.$enum.getValueDescList(this.enumName)
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onConfirm(value) {
|
||||
this.result = value.desc;
|
||||
this.show = !this.show;
|
||||
this.$emit('change', value);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectValue: function(newVal) {
|
||||
this.result = newVal;
|
||||
},
|
||||
result(newVal) {
|
||||
this.$emit('input', newVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div>
|
||||
<van-field
|
||||
v-model="result"
|
||||
v-bind="$attrs"
|
||||
readonly
|
||||
is-link
|
||||
@click="show = !show"
|
||||
/>
|
||||
<van-popup v-model="show" position="bottom">
|
||||
<van-picker
|
||||
value-key="value"
|
||||
:columns="columns"
|
||||
show-toolbar
|
||||
:title="$attrs.label"
|
||||
@cancel="show = !show"
|
||||
@confirm="onConfirm"
|
||||
/>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
model: {
|
||||
prop: 'selectValue'
|
||||
},
|
||||
props: {
|
||||
columns: {
|
||||
type: Array
|
||||
},
|
||||
selectValue: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
result: this.selectValue
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onConfirm(value) {
|
||||
this.result = value;
|
||||
this.show = !this.show;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectValue: function(newVal) {
|
||||
this.result = newVal;
|
||||
},
|
||||
result(newVal) {
|
||||
this.$emit('input', newVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,25 @@
|
||||
import cookie from '@/lib/cookie';
|
||||
import { userApi } from 'api/user';
|
||||
|
||||
/**
|
||||
* 此 mixin为登录以后的页面用的,因为所有的有效路由(排除登录、注册、404,500 这个几个特殊页面)都会走 App.vue里的router
|
||||
* @author zhuoda
|
||||
*/
|
||||
export default {
|
||||
created: function() {
|
||||
const token = cookie.getToken();
|
||||
// 如果登录过,获取token
|
||||
if (token && !this.$store.state.user.isHaveGotSessionInfo) {
|
||||
(async() => {
|
||||
try {
|
||||
console.debug(' request session info ');
|
||||
const res = await userApi.getSession();
|
||||
const loginInfo = res.data;
|
||||
this.$store.commit('user/updateSession', loginInfo);
|
||||
} catch (e) {
|
||||
this.$smartSentry.captureException(e);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
|
||||
<van-nav-bar :title="title" left-text="返回" left-arrow @click-left="onClickLeft" />
|
||||
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'BackNavBar',
|
||||
props: {
|
||||
title: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
onClickLeft() {
|
||||
this.$router.go(-1);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
|
||||
<van-nav-bar :title="title" left-text="返回" left-arrow @click-left="onClickLeft" />
|
||||
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'RouterNavBar',
|
||||
props: {
|
||||
title: {
|
||||
type: String
|
||||
},
|
||||
path: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
onClickLeft() {
|
||||
this.$router.push(this.path);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
46
smart_admin_v1/smart-admin-h5/src/config/index.js
Normal file
46
smart_admin_v1/smart-admin-h5/src/config/index.js
Normal file
@@ -0,0 +1,46 @@
|
||||
console.log('project api url : ', process.env.VUE_APP_URL);
|
||||
|
||||
const isProductionEnv = ['production'].includes(process.env.NODE_ENV);
|
||||
|
||||
module.exports = {
|
||||
// 配置显示在浏览器标签的title
|
||||
title: 'Smart-Admin-H5',
|
||||
// token在Cookie中存储的天数,默认7天
|
||||
cookieExpires: 7,
|
||||
/**
|
||||
* @description api请求基础路径
|
||||
*/
|
||||
baseUrl: {
|
||||
apiUrl: process.env.VUE_APP_URL,
|
||||
erpApiUrl: process.env.VUE_APP_ERP_URL,
|
||||
webSocketUrl: process.env.VUE_APP_SOCKET_URL
|
||||
},
|
||||
/**
|
||||
* 打包后静态资源地址;如果是走cdn的话,可以配置如下:
|
||||
* publicPath: isProd ? 'https://cdn.1024lab.net/static/smart-h5/' : '/'
|
||||
*/
|
||||
publicPath: isProductionEnv ? '/manage-h5/' : '/',
|
||||
|
||||
// ==================== cdn 相关 begin ====================
|
||||
cdn: {
|
||||
cdnResource: {
|
||||
css: [],
|
||||
js: [
|
||||
'https://cdn.bootcss.com/vue/2.6.11/vue.min.js',
|
||||
'https://cdn.bootcss.com/vue-router/3.2.0/vue-router.min.js',
|
||||
'https://cdn.bootcdn.net/ajax/libs/vuex/3.5.1/vuex.min.js',
|
||||
'https://cdn.bootcss.com/axios/0.19.2/axios.min.js',
|
||||
'https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.min.js'
|
||||
]
|
||||
},
|
||||
// 指定资源加载cdn
|
||||
externals: {
|
||||
vue: 'Vue',
|
||||
'vue-router': 'VueRouter',
|
||||
vuex: 'Vuex',
|
||||
axios: 'axios',
|
||||
lodash: '_'
|
||||
}
|
||||
}
|
||||
// ==================== cdn 相关 end ====================
|
||||
};
|
||||
4047
smart_admin_v1/smart-admin-h5/src/constants/area.js
Normal file
4047
smart_admin_v1/smart-admin-h5/src/constants/area.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* 往来单位性质
|
||||
* @type {{ENTERPRISE: {value: number, desc: string}, PERSONAL: {value: number, desc: string}}}
|
||||
*/
|
||||
export const CONTACT_COMPANY_NATURE_ENUM =
|
||||
{
|
||||
ENTERPRISE: {
|
||||
value: 0,
|
||||
desc: '企业'
|
||||
},
|
||||
PERSONAL: {
|
||||
value: 1,
|
||||
desc: '个人'
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 往来机构类型
|
||||
* @type {{CUSTOMER: {value: number, desc: string}, SUPPLIER: {value: number, desc: string}}}
|
||||
*/
|
||||
export const
|
||||
CONTACT_COMPANY_TYPE_ENUM =
|
||||
{
|
||||
CUSTOMER: {
|
||||
value: 0,
|
||||
desc: '客户'
|
||||
},
|
||||
SUPPLIER: {
|
||||
value: 1,
|
||||
desc: '供应商'
|
||||
},
|
||||
SCHOOL: {
|
||||
value: 2,
|
||||
desc: '分校'
|
||||
},
|
||||
COOPERATIVE_ORG: {
|
||||
value: 3,
|
||||
desc: '合作机构'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 付款方式
|
||||
* @type {{BANK: {value: number, desc: string}, ZHI_FU_BAO: {value: number, desc: string}, WE_CHAT: {value: number, desc: string}}}
|
||||
*/
|
||||
export const
|
||||
PAYMENT_TYPE_ENUM =
|
||||
{
|
||||
BANK: {
|
||||
value: 0,
|
||||
desc: '银行卡'
|
||||
},
|
||||
WE_CHAT: {
|
||||
value: 1,
|
||||
desc: '微信'
|
||||
},
|
||||
ZHI_FU_BAO: {
|
||||
value: 2,
|
||||
desc: '支付宝'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 往来机构余额类型
|
||||
* @type {{RECEIVE_BALANCE: {value: number, desc: string}, PAY_BALANCE: {value: number, desc: string}}}
|
||||
*/
|
||||
export const
|
||||
CONTACT_COMPANY_BALANCE_TYPE =
|
||||
{
|
||||
PAY_BALANCE: {
|
||||
value: 0,
|
||||
desc: '应付款余额'
|
||||
},
|
||||
RECEIVE_BALANCE: {
|
||||
value: 1,
|
||||
desc: '应收款余额'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 往来单位等级
|
||||
* @type {{CORE: {value: number, desc: string}, POTENTIAL: {value: number, desc: string}, BAD: {value: number, desc: string}, GENERAL: {value: number, desc: string}}}
|
||||
*/
|
||||
export const CONTACT_COMPANY_GRADE_ENUM = {
|
||||
CORE: {
|
||||
value: 1,
|
||||
desc: '核心',
|
||||
color: 'green'
|
||||
},
|
||||
POTENTIAL: {
|
||||
value: 2,
|
||||
desc: '有潜力',
|
||||
color: 'cyan'
|
||||
},
|
||||
GENERAL: {
|
||||
value: 3,
|
||||
desc: '普通',
|
||||
color: 'blue'
|
||||
},
|
||||
BAD: {
|
||||
value: 4,
|
||||
desc: '较差',
|
||||
color: 'purple'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 往来单位等级
|
||||
* @type {{OWNER: {value: number, desc: string}, SHARER: {value: number, desc: string}, COMMON: {value: number, desc: string}}}
|
||||
*/
|
||||
export const CONTACT_COMPANY_SHARE_TYPE_ENUM = {
|
||||
OWNER: {
|
||||
value: 0,
|
||||
desc: '属于我的'
|
||||
},
|
||||
SHARER: {
|
||||
value: 1,
|
||||
desc: '共享的'
|
||||
},
|
||||
COMMON: {
|
||||
value: 2,
|
||||
desc: '公共的'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 往来单位标签
|
||||
* @type {{OWNER: {value: number, desc: string}, SHARER: {value: number, desc: string}, COMMON: {value: number, desc: string}}}
|
||||
*/
|
||||
export const CONTACT_COMPANY_TAG_ENUM = {
|
||||
POTENTIAL: {
|
||||
value: 0,
|
||||
desc: '潜在',
|
||||
color: 'green'
|
||||
},
|
||||
INTENTION: {
|
||||
value: 1,
|
||||
desc: '意向',
|
||||
color: 'cyan'
|
||||
},
|
||||
NEGOTIATION: {
|
||||
value: 2,
|
||||
desc: '洽谈',
|
||||
color: 'blue'
|
||||
},
|
||||
DEAL: {
|
||||
value: 3,
|
||||
desc: '成交',
|
||||
color: 'geekblue'
|
||||
},
|
||||
LOSS: {
|
||||
value: 4,
|
||||
desc: '流失',
|
||||
color: 'red'
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
CONTACT_COMPANY_NATURE_ENUM,
|
||||
CONTACT_COMPANY_TYPE_ENUM,
|
||||
PAYMENT_TYPE_ENUM,
|
||||
CONTACT_COMPANY_BALANCE_TYPE,
|
||||
CONTACT_COMPANY_GRADE_ENUM,
|
||||
CONTACT_COMPANY_SHARE_TYPE_ENUM,
|
||||
CONTACT_COMPANY_TAG_ENUM
|
||||
};
|
||||
6
smart_admin_v1/smart-admin-h5/src/constants/erp/index.js
Normal file
6
smart_admin_v1/smart-admin-h5/src/constants/erp/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import contactCompany from './contact-company';
|
||||
|
||||
export default {
|
||||
...contactCompany
|
||||
};
|
||||
|
||||
92
smart_admin_v1/smart-admin-h5/src/constants/file.js
Normal file
92
smart_admin_v1/smart-admin-h5/src/constants/file.js
Normal file
@@ -0,0 +1,92 @@
|
||||
export const COMMON_FILE_FOLDER_TYPE_ENUM = {
|
||||
DISPLAY_PIC: {
|
||||
value: 1,
|
||||
desc: '轮播展示图'
|
||||
},
|
||||
RESOURCE_LECTURER: {
|
||||
value: 2,
|
||||
desc: '资源-讲师图片'
|
||||
},
|
||||
RESOURCE_FILE: {
|
||||
value: 3,
|
||||
desc: '资源-文件资源'
|
||||
},
|
||||
USER_AVATAR: {
|
||||
value: 4,
|
||||
desc: '用户头像'
|
||||
},
|
||||
STOCK_BASIC: {
|
||||
value: 5,
|
||||
desc: '货物基本信息图片'
|
||||
},
|
||||
PUBLICATION_QR_CODE: {
|
||||
value: 6,
|
||||
desc: '出版物二维码图片'
|
||||
},
|
||||
RESOURCE_PAGE_QR_CODE: {
|
||||
value: 7,
|
||||
desc: '资源页面链接二维码图片'
|
||||
},
|
||||
FINANCE_RECEIVE_QR_CODE: {
|
||||
value: 8,
|
||||
desc: '财务收款二维码'
|
||||
},
|
||||
FINANCE_WX_PAY_CERT: {
|
||||
value: 9,
|
||||
desc: '财务-微信支付证书'
|
||||
},
|
||||
GOODS: {
|
||||
value: 10,
|
||||
desc: '商品图片-公用文件夹'
|
||||
},
|
||||
EXCEL_EXPORT: {
|
||||
value: 11,
|
||||
desc: 'excel导出-私有文件夹'
|
||||
},
|
||||
FINANCE_WAIT_PAYMENT_PAYMENT_PROOF: {
|
||||
value: 12,
|
||||
desc: '财务待支付支付凭证'
|
||||
},
|
||||
FEEDBACK: {
|
||||
value: 99,
|
||||
desc: '用户反馈图片'
|
||||
},
|
||||
EDITOR: {
|
||||
value: 100,
|
||||
desc: '文本编辑器'
|
||||
},
|
||||
EDITOR_IMG: {
|
||||
value: 100,
|
||||
desc: '文本编辑器'
|
||||
},
|
||||
INTERNAL_INFORMATION: {
|
||||
value: 14,
|
||||
desc: '内部资料'
|
||||
},
|
||||
CRM_USER: {
|
||||
value: 111,
|
||||
desc: 'CRM学员跟进附件'
|
||||
},
|
||||
CRM_SCHOOL: {
|
||||
value: 112,
|
||||
desc: 'CRM分校跟进附件'
|
||||
},
|
||||
// = =======erp 相关 begin============
|
||||
ERP_STOCK_IMG: {
|
||||
value: 201,
|
||||
desc: '货物图片'
|
||||
},
|
||||
ERP_CONTACT_COMPANY_RECEIVE_IMAGE: {
|
||||
value: 210,
|
||||
desc: '往来单位收款二维码'
|
||||
},
|
||||
ERP_CONTACT_COMPANY_ATTACHMENT: {
|
||||
value: 211,
|
||||
desc: '往来单位附件'
|
||||
}
|
||||
// = =======erp 相关 end ============
|
||||
};
|
||||
|
||||
export default {
|
||||
COMMON_FILE_FOLDER_TYPE_ENUM
|
||||
};
|
||||
7
smart_admin_v1/smart-admin-h5/src/constants/index.js
Normal file
7
smart_admin_v1/smart-admin-h5/src/constants/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import school from '@/constants/school';
|
||||
import erp from './erp';
|
||||
|
||||
export default {
|
||||
...school,
|
||||
...erp
|
||||
};
|
||||
71
smart_admin_v1/smart-admin-h5/src/constants/school.js
Normal file
71
smart_admin_v1/smart-admin-h5/src/constants/school.js
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 分校标签
|
||||
*/
|
||||
export const SCHOOL_TAG_ENUM = {
|
||||
POTENTIAL: {
|
||||
value: 0,
|
||||
desc: '潜在'
|
||||
},
|
||||
INTENTION: {
|
||||
value: 1,
|
||||
desc: '意向'
|
||||
},
|
||||
NEGOTIATION: {
|
||||
value: 2,
|
||||
desc: '洽谈'
|
||||
},
|
||||
DEAL: {
|
||||
value: 3,
|
||||
desc: '成交'
|
||||
},
|
||||
LOSS: {
|
||||
value: 4,
|
||||
desc: '流失'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 分校等级
|
||||
*/
|
||||
export const SCHOOL_GRADE_ENUM = {
|
||||
CORE: {
|
||||
value: 1,
|
||||
desc: '核心'
|
||||
},
|
||||
POTENTIAL: {
|
||||
value: 2,
|
||||
desc: '有潜力'
|
||||
},
|
||||
GENERAL: {
|
||||
value: 3,
|
||||
desc: '普通'
|
||||
},
|
||||
BAD: {
|
||||
value: 4,
|
||||
desc: '较差'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 共享类型
|
||||
*/
|
||||
export const SCHOOL_SHARE_TYPE_ENUM = {
|
||||
OWNER: {
|
||||
value: 0,
|
||||
desc: '属于我的'
|
||||
},
|
||||
SHARER: {
|
||||
value: 1,
|
||||
desc: '共享的'
|
||||
},
|
||||
COMMON: {
|
||||
value: 2,
|
||||
desc: '公共的'
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
SCHOOL_TAG_ENUM,
|
||||
SCHOOL_GRADE_ENUM,
|
||||
SCHOOL_SHARE_TYPE_ENUM
|
||||
};
|
||||
298
smart_admin_v1/smart-admin-h5/src/filters/filter.js
Normal file
298
smart_admin_v1/smart-admin-h5/src/filters/filter.js
Normal file
@@ -0,0 +1,298 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
function ellipsis(value, length) {
|
||||
if (!value) return '';
|
||||
if (value.length > length) {
|
||||
return value.slice(0, length) + '...';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除空格 type 1-所有空格 2-前后空格 3-前空格 4-后空格
|
||||
*/
|
||||
function trim(value, trim) {
|
||||
switch (trim) {
|
||||
case 1:
|
||||
return value.replace(/\s+/g, '');
|
||||
case 2:
|
||||
return value.replace(/(^\s*)|(\s*$)/g, '');
|
||||
case 3:
|
||||
return value.replace(/(^\s*)/g, '');
|
||||
case 4:
|
||||
return value.replace(/(\s*$)/g, '');
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任意格式日期处理
|
||||
使用格式:
|
||||
{{ '2018-09-14 01:05' | formatDate(yyyy-MM-dd hh:mm:ss) }}
|
||||
{{ '2018-09-14 01:05' | formatDate(yyyy-MM-dd) }}
|
||||
{{ '2018-09-14 01:05' | formatDate(MM/dd) }} 等
|
||||
|
||||
* @param value
|
||||
* @param fmt
|
||||
* @returns {*}
|
||||
*/
|
||||
function formatDate(value, fmt) {
|
||||
var date = new Date(value);
|
||||
var o = {
|
||||
'M+': date.getMonth() + 1, // 月份
|
||||
'd+': date.getDate(), // 日
|
||||
'h+': date.getHours(), // 小时
|
||||
'm+': date.getMinutes(), // 分
|
||||
's+': date.getSeconds(), // 秒
|
||||
'w+': date.getDay(), // 星期
|
||||
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
|
||||
'S': date.getMilliseconds() // 毫秒
|
||||
};
|
||||
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
|
||||
for (var k in o) {
|
||||
if (k === 'w+') {
|
||||
if (o[k] === 0) {
|
||||
fmt = fmt.replace('w', '周日');
|
||||
} else if (o[k] === 1) {
|
||||
fmt = fmt.replace('w', '周一');
|
||||
} else if (o[k] === 2) {
|
||||
fmt = fmt.replace('w', '周二');
|
||||
} else if (o[k] === 3) {
|
||||
fmt = fmt.replace('w', '周三');
|
||||
} else if (o[k] === 4) {
|
||||
fmt = fmt.replace('w', '周四');
|
||||
} else if (o[k] === 5) {
|
||||
fmt = fmt.replace('w', '周五');
|
||||
} else if (o[k] === 6) {
|
||||
fmt = fmt.replace('w', '周六');
|
||||
}
|
||||
} else if (new RegExp('(' + k + ')').test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字母大小写切换
|
||||
type
|
||||
1:首字母大写
|
||||
2:首页母小写
|
||||
3:大小写转换
|
||||
4:全部大写
|
||||
5:全部小写
|
||||
* @param str
|
||||
* @param type
|
||||
* @returns {string|*}
|
||||
*/
|
||||
function changeCase(str, type) {
|
||||
function ToggleCase(str) {
|
||||
var itemText = '';
|
||||
str.split('').forEach(
|
||||
function(item) {
|
||||
if (/^([a-z]+)/.test(item)) {
|
||||
itemText += item.toUpperCase();
|
||||
} else if (/^([A-Z]+)/.test(item)) {
|
||||
itemText += item.toLowerCase();
|
||||
} else {
|
||||
itemText += item;
|
||||
}
|
||||
});
|
||||
return itemText;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 1:
|
||||
return str.replace(/\b\w+\b/g, function(word) {
|
||||
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
|
||||
});
|
||||
case 2:
|
||||
return str.replace(/\b\w+\b/g, function(word) {
|
||||
return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
|
||||
});
|
||||
case 3:
|
||||
return ToggleCase(str);
|
||||
case 4:
|
||||
return str.toUpperCase();
|
||||
case 5:
|
||||
return str.toLowerCase();
|
||||
default:
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串循环复制,count->次数
|
||||
*/
|
||||
function repeatStr(str, count) {
|
||||
var text = '';
|
||||
for (var i = 0; i < count; i++) {
|
||||
text += str;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串替换
|
||||
*/
|
||||
function replaceAll(str, AFindText, ARepText) {
|
||||
const raRegExp = new RegExp(AFindText, 'g');
|
||||
return str.replace(raRegExp, ARepText);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 字符替换*,隐藏手机号或者身份证号等
|
||||
replaceStr(字符串,字符格式, 替换方式,替换的字符(默认*))
|
||||
ecDo.replaceStr('18819322663',[3,5,3],0)
|
||||
result:188*****663
|
||||
ecDo.replaceStr('asdasdasdaa',[3,5,3],1)
|
||||
result:***asdas***
|
||||
ecDo.replaceStr('1asd88465asdwqe3',[5],0)
|
||||
result:*****8465asdwqe3
|
||||
ecDo.replaceStr('1asd88465asdwqe3',[5],1,'+')
|
||||
result:"1asd88465as+++++"
|
||||
*
|
||||
* @param str
|
||||
* @param regArr
|
||||
* @param type
|
||||
* @param ARepText
|
||||
* @returns {*}
|
||||
*/
|
||||
function replaceStr(str, regArr, type, ARepText) {
|
||||
var regtext = '';
|
||||
var Reg = null;
|
||||
var replaceText = ARepText || '*';
|
||||
// repeatStr是在上面定义过的(字符串循环复制),大家注意哦
|
||||
if (regArr.length === 3 && type === 0) {
|
||||
regtext = '(\\w{' + regArr[0] + '})\\w{' + regArr[1] + '}(\\w{' + regArr[2] + '})';
|
||||
Reg = new RegExp(regtext);
|
||||
var replaceCount = this.repeatStr(replaceText, regArr[1]);
|
||||
return str.replace(Reg, '$1' + replaceCount + '$2');
|
||||
} else if (regArr.length === 3 && type === 1) {
|
||||
regtext = '\\w{' + regArr[0] + '}(\\w{' + regArr[1] + '})\\w{' + regArr[2] + '}';
|
||||
Reg = new RegExp(regtext);
|
||||
var replaceCount1 = this.repeatStr(replaceText, regArr[0]);
|
||||
var replaceCount2 = this.repeatStr(replaceText, regArr[2]);
|
||||
return str.replace(Reg, replaceCount1 + '$1' + replaceCount2);
|
||||
} else if (regArr.length === 1 && type === 0) {
|
||||
regtext = '(^\\w{' + regArr[0] + '})';
|
||||
Reg = new RegExp(regtext);
|
||||
var replaceCount = this.repeatStr(replaceText, regArr[0]);
|
||||
return str.replace(Reg, replaceCount);
|
||||
} else if (regArr.length === 1 && type === 1) {
|
||||
regtext = '(\\w{' + regArr[0] + '}$)';
|
||||
Reg = new RegExp(regtext);
|
||||
var replaceCount = this.repeatStr(replaceText, regArr[0]);
|
||||
return str.replace(Reg, replaceCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化处理字符串
|
||||
ecDo.formatText('1234asda567asd890')
|
||||
result:"12,34a,sda,567,asd,890"
|
||||
ecDo.formatText('1234asda567asd890',4,' ')
|
||||
result:"1 234a sda5 67as d890"
|
||||
ecDo.formatText('1234asda567asd890',4,'-')
|
||||
result:"1-234a-sda5-67as-d890"
|
||||
|
||||
* @param str
|
||||
* @param size
|
||||
* @param delimiter
|
||||
* @returns {*}
|
||||
*/
|
||||
function formatText(str, size, delimiter) {
|
||||
var _size = size || 3;
|
||||
var _delimiter = delimiter || ',';
|
||||
var regText = '\\B(?=(\\w{' + _size + '})+(?!\\w))';
|
||||
var reg = new RegExp(regText, 'g');
|
||||
return str.replace(reg, _delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 现金额大写转换函数
|
||||
ecDo.upDigit(168752632)
|
||||
result:"人民币壹亿陆仟捌佰柒拾伍万贰仟陆佰叁拾贰元整"
|
||||
ecDo.upDigit(1682)
|
||||
result:"人民币壹仟陆佰捌拾贰元整"
|
||||
ecDo.upDigit(-1693)
|
||||
result:"欠人民币壹仟陆佰玖拾叁元整"
|
||||
* @param n
|
||||
* @returns {string}
|
||||
*/
|
||||
function upDigit(n) {
|
||||
var fraction = ['角', '分', '厘'];
|
||||
var digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
|
||||
var unit = [
|
||||
['元', '万', '亿'],
|
||||
['', '拾', '佰', '仟']
|
||||
];
|
||||
var head = n < 0 ? '欠人民币' : '人民币';
|
||||
n = Math.abs(n);
|
||||
var s = '';
|
||||
for (var i = 0; i < fraction.length; i++) {
|
||||
s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
|
||||
}
|
||||
s = s || '整';
|
||||
n = Math.floor(n);
|
||||
for (var i = 0; i < unit[0].length && n > 0; i++) {
|
||||
var p = '';
|
||||
for (var j = 0; j < unit[1].length && n > 0; j++) {
|
||||
p = digit[n % 10] + unit[1][j] + p;
|
||||
n = Math.floor(n / 10);
|
||||
}
|
||||
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
|
||||
// s = p + unit[0][i] + s;
|
||||
}
|
||||
return head + s.replace(/(零.)*零元/, '元').replace(/(零.)+/g, '零').replace(/^整$/, '零元整');
|
||||
}
|
||||
|
||||
// 保留2位小数
|
||||
function toFixed(val, acc) {
|
||||
let num = parseFloat(val);
|
||||
if (isNaN(num)) {
|
||||
num = 0;
|
||||
}
|
||||
let accuracy = parseInt(acc);
|
||||
if (isNaN(accuracy) || accuracy < 0 || accuracy > 10) {
|
||||
accuracy = 2;
|
||||
}
|
||||
return num.toFixed(accuracy);
|
||||
}
|
||||
|
||||
// 转百分比
|
||||
function toPercent(val, acc) {
|
||||
let num = parseFloat(val);
|
||||
if (isNaN(num)) {
|
||||
num = 0;
|
||||
}
|
||||
let accuracy = parseInt(acc);
|
||||
if (isNaN(accuracy) || accuracy < 0 || accuracy > 10) {
|
||||
accuracy = 2;
|
||||
}
|
||||
return (num * 100).toFixed(accuracy) + '%';
|
||||
}
|
||||
|
||||
// ------------ enum begin ------------
|
||||
function getEnumDescByValue(value, enumName) {
|
||||
return Vue.prototype.$enum.getDescByValue(enumName, value);
|
||||
}
|
||||
|
||||
// ------------ enum end ------------
|
||||
|
||||
export {
|
||||
trim,
|
||||
changeCase,
|
||||
repeatStr,
|
||||
replaceAll,
|
||||
replaceStr,
|
||||
formatText,
|
||||
upDigit,
|
||||
toFixed,
|
||||
formatDate,
|
||||
toPercent,
|
||||
getEnumDescByValue,
|
||||
ellipsis
|
||||
};
|
||||
5
smart_admin_v1/smart-admin-h5/src/filters/index.js
Normal file
5
smart_admin_v1/smart-admin-h5/src/filters/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
import * as filter from './filter'
|
||||
|
||||
Object.keys(filter).forEach(key => Vue.filter(key, filter[key]))
|
||||
21
smart_admin_v1/smart-admin-h5/src/lib/cookie.js
Normal file
21
smart_admin_v1/smart-admin-h5/src/lib/cookie.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import config from '@/config';
|
||||
const { cookieExpires } = config;
|
||||
export const TOKEN_KEY = 'token';
|
||||
|
||||
export default {
|
||||
setToken: token => {
|
||||
Cookies.set(TOKEN_KEY, token, {
|
||||
// token在Cookie中存储的天数,默认1天
|
||||
expires: cookieExpires || 7
|
||||
});
|
||||
},
|
||||
getToken: () => {
|
||||
const token = Cookies.get(TOKEN_KEY);
|
||||
if (token) return token;
|
||||
else return null;
|
||||
},
|
||||
clearToken: () => {
|
||||
Cookies.remove(TOKEN_KEY);
|
||||
}
|
||||
};
|
||||
65
smart_admin_v1/smart-admin-h5/src/lib/erp-http.js
Normal file
65
smart_admin_v1/smart-admin-h5/src/lib/erp-http.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import Axios from 'axios';
|
||||
import config from '@/config';
|
||||
import cookie from '@/lib/cookie';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export const baseUrl = config.baseUrl.erpApiUrl;
|
||||
|
||||
const axios = Axios.create({
|
||||
baseURL: baseUrl,
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
});
|
||||
|
||||
// 添加请求拦截器
|
||||
axios.interceptors.request.use(
|
||||
function(config) {
|
||||
const token = cookie.getToken();
|
||||
if (token) {
|
||||
config.headers['x-access-token'] = token;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
function(error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 添加响应拦截器
|
||||
axios.interceptors.response.use(
|
||||
res => {
|
||||
const { data } = res;
|
||||
if (data && data.code && data.code !== 1) {
|
||||
if (data.code === 121) {
|
||||
cookie.clearToken();
|
||||
localStorage.clear();
|
||||
window.location.href = window.location.pathname + '#/login';
|
||||
Toast.fail('未登录,或登录失效,请登录');
|
||||
return;
|
||||
} else if (data.code === 502) {
|
||||
window.location.href = window.location.pathname + '#/500';
|
||||
return;
|
||||
} else {
|
||||
Toast.fail(data.msg);
|
||||
return Promise.reject(res);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(data);
|
||||
},
|
||||
error => {
|
||||
Toast.fail('服务内部错误');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export const postAxios = (url, data, config) => {
|
||||
return axios.post(url, data, config);
|
||||
};
|
||||
|
||||
export const getAxios = (url, data) => {
|
||||
return axios.get(url, {
|
||||
params: data
|
||||
});
|
||||
};
|
||||
65
smart_admin_v1/smart-admin-h5/src/lib/http.js
Normal file
65
smart_admin_v1/smart-admin-h5/src/lib/http.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import Axios from 'axios';
|
||||
import config from '@/config';
|
||||
import cookie from '@/lib/cookie';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export const baseUrl = config.baseUrl.apiUrl;
|
||||
|
||||
const axios = Axios.create({
|
||||
baseURL: baseUrl,
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
});
|
||||
|
||||
// 添加请求拦截器
|
||||
axios.interceptors.request.use(
|
||||
function(config) {
|
||||
const token = cookie.getToken();
|
||||
if (token) {
|
||||
config.headers['x-access-token'] = token;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
function(error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 添加响应拦截器
|
||||
axios.interceptors.response.use(
|
||||
res => {
|
||||
const { data } = res;
|
||||
if (data && data.code && data.code !== 1) {
|
||||
if (data.code === 1001) {
|
||||
cookie.clearToken();
|
||||
localStorage.clear();
|
||||
window.location.href = window.location.pathname + '#/login';
|
||||
Toast.fail('未登录,或登录失效,请登录');
|
||||
return;
|
||||
} else if (data.code === 502) {
|
||||
window.location.href = window.location.pathname + '#/500';
|
||||
return;
|
||||
} else {
|
||||
Toast.fail(data.msg);
|
||||
return Promise.reject(res);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(data);
|
||||
},
|
||||
error => {
|
||||
Toast.fail('服务内部错误');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export const postAxios = (url, data, config) => {
|
||||
return axios.post(url, data, config);
|
||||
};
|
||||
|
||||
export const getAxios = (url, data) => {
|
||||
return axios.get(url, {
|
||||
params: data
|
||||
});
|
||||
};
|
||||
8
smart_admin_v1/smart-admin-h5/src/lib/local.js
Normal file
8
smart_admin_v1/smart-admin-h5/src/lib/local.js
Normal file
@@ -0,0 +1,8 @@
|
||||
export const localSave = (key, value) => {
|
||||
localStorage.setItem(key, value);
|
||||
};
|
||||
|
||||
export const localRead = key => {
|
||||
return localStorage.getItem(key) || '';
|
||||
};
|
||||
|
||||
276
smart_admin_v1/smart-admin-h5/src/lib/menu-func.js
Normal file
276
smart_admin_v1/smart-admin-h5/src/lib/menu-func.js
Normal file
@@ -0,0 +1,276 @@
|
||||
import { forEach, hasOneOf, objEqual } from '@/lib/util';
|
||||
import config from '@/config';
|
||||
import { localRead, localSave } from '@/lib/local';
|
||||
const { title, useI18n } = config;
|
||||
export const hasChild = item => {
|
||||
return item.children && item.children.length !== 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 通过权限过滤菜单
|
||||
* @param {Object} map 权限对象
|
||||
* @param {Array} menuList 菜单列表
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getShowMenu = (map = {}, menuList, access = false) => {
|
||||
// 判断是否为超级管理员
|
||||
if (access) {
|
||||
return menuList;
|
||||
}
|
||||
// 返回的菜单列表
|
||||
let result = [];
|
||||
for (let menuItem of menuList) {
|
||||
let routerObj = JSON.parse(JSON.stringify(menuItem));
|
||||
if (
|
||||
map.hasOwnProperty(menuItem.name) &&
|
||||
(menuItem.name !== 'home' && menuItem.name !== '_home')
|
||||
) {
|
||||
// 判断该菜单权限下是否为数组,若为数组,则为功能点权限否则为子菜单
|
||||
if (getType(map[routerObj.name]) === 'array') {
|
||||
let funcPrivilege = localRead('funcPrivilegeInfo')
|
||||
? JSON.parse(localRead('funcPrivilegeInfo'))
|
||||
: {};
|
||||
localSave(
|
||||
'funcPrivilegeInfo',
|
||||
JSON.stringify({
|
||||
...funcPrivilege,
|
||||
[routerObj.name]: map[routerObj.name]
|
||||
})
|
||||
);
|
||||
} else if (
|
||||
getType(map[routerObj.name]) !== 'array' &&
|
||||
!routerObj.children
|
||||
) {
|
||||
// 判断是否为二级菜单,若是则需要多枚举一层赋值
|
||||
let funcPrivilege = localRead('funcPrivilegeInfo')
|
||||
? JSON.parse(localRead('funcPrivilegeInfo'))
|
||||
: {};
|
||||
localSave(
|
||||
'funcPrivilegeInfo',
|
||||
JSON.stringify({
|
||||
...funcPrivilege,
|
||||
[routerObj.name]: map[routerObj.name][routerObj.name]
|
||||
})
|
||||
);
|
||||
} else if (
|
||||
getType(map[routerObj.name]) !== 'array' &&
|
||||
routerObj.children
|
||||
) {
|
||||
// 循环子菜单权限
|
||||
routerObj.children = getShowMenu(
|
||||
map[routerObj.name],
|
||||
routerObj.children
|
||||
);
|
||||
}
|
||||
result.push(routerObj);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// 获取数据类型
|
||||
export const getType = obj => {
|
||||
return {}.toString
|
||||
.call(obj)
|
||||
.match(/\s([a-zA-Z]+)/)[1]
|
||||
.toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 本地存储和获取标签导航列表
|
||||
*/
|
||||
export const setTagNavListInLocalStorage = list => {
|
||||
localStorage.tagNaveList = JSON.stringify(list);
|
||||
};
|
||||
/**
|
||||
* @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项
|
||||
*/
|
||||
export const getTagNavListFromLocalStorage = () => {
|
||||
const list = localStorage.tagNaveList;
|
||||
return list ? JSON.parse(list) : [];
|
||||
};
|
||||
export const getBreadCrumbList = (route, homeRoute) => {
|
||||
let homeItem = {
|
||||
...homeRoute,
|
||||
icon: homeRoute.meta.icon
|
||||
};
|
||||
let routeMatched = route.matched;
|
||||
if (routeMatched.some(item => item.name === homeRoute.name)) {
|
||||
return [homeItem];
|
||||
}
|
||||
let res = routeMatched
|
||||
.filter(item => {
|
||||
return item.meta === undefined || !item.meta.hideInBread;
|
||||
})
|
||||
.map(item => {
|
||||
let meta = {
|
||||
...item.meta
|
||||
};
|
||||
if (meta.title && typeof meta.title === 'function') {
|
||||
meta.__titleIsFunction__ = true;
|
||||
meta.title = meta.title(route);
|
||||
}
|
||||
let obj = {
|
||||
icon: (item.meta && item.meta.icon) || '',
|
||||
name: item.name,
|
||||
meta: meta
|
||||
};
|
||||
return obj;
|
||||
});
|
||||
res = res.filter(item => {
|
||||
return !item.meta.hideInMenu;
|
||||
});
|
||||
return [...res];
|
||||
};
|
||||
/**
|
||||
* @param {Array} routers 路由列表数组
|
||||
* @description 用于找到路由列表中name为home的对象
|
||||
*/
|
||||
export const getHomeRoute = (routers, homeName = 'Home') => {
|
||||
let i = -1;
|
||||
let len = routers.length;
|
||||
let homeRoute = {};
|
||||
while (++i < len) {
|
||||
let item = routers[i];
|
||||
if (item.children && item.children.length) {
|
||||
let res = getHomeRoute(item.children, homeName);
|
||||
if (res.name) return res;
|
||||
} else {
|
||||
if (item.name === homeName) homeRoute = item;
|
||||
}
|
||||
}
|
||||
return homeRoute;
|
||||
};
|
||||
/**
|
||||
* @param {Array} list 标签列表
|
||||
* @param {String} name 当前关闭的标签的name
|
||||
*/
|
||||
export const getNextRoute = (list, route) => {
|
||||
let res = {};
|
||||
if (list.length === 2) {
|
||||
res = getHomeRoute(list);
|
||||
} else {
|
||||
const index = list.findIndex(item => routeEqual(item, route));
|
||||
if (index === list.length - 1) res = list[list.length - 2];
|
||||
else res = list[index + 1];
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断打开的标签列表里是否已存在这个新添加的路由对象
|
||||
*/
|
||||
export const routeHasExist = (tagNavList, routeItem) => {
|
||||
let len = tagNavList.length;
|
||||
let res = false;
|
||||
doCustomTimes(len, index => {
|
||||
if (routeEqual(tagNavList[index], routeItem)) res = true;
|
||||
});
|
||||
return res;
|
||||
};
|
||||
/**
|
||||
* @param {*} list 现有标签导航列表
|
||||
* @param {*} newRoute 新添加的路由原信息对象
|
||||
* @description 如果该newRoute已经存在则不再添加
|
||||
*/
|
||||
export const getNewTagList = (list, newRoute) => {
|
||||
const { name, path, meta, query } = newRoute;
|
||||
let newList = [...list];
|
||||
let index = newList.findIndex(item => item.name === name);
|
||||
if (index >= 0) {
|
||||
newList[index] = { name, path, meta, query };
|
||||
} else newList.push({ name, path, meta, query });
|
||||
return newList;
|
||||
};
|
||||
export const routeEqual = (route1, route2) => {
|
||||
return route1.name === route2.name;
|
||||
};
|
||||
export const getRouteTitleHandled = route => {
|
||||
let router = {
|
||||
...route
|
||||
};
|
||||
let meta = {
|
||||
...route.meta
|
||||
};
|
||||
let title = '';
|
||||
if (meta.title) {
|
||||
if (typeof meta.title === 'function') {
|
||||
meta.__titleIsFunction__ = true;
|
||||
title = meta.title(router);
|
||||
} else title = meta.title;
|
||||
}
|
||||
meta.title = title;
|
||||
router.meta = meta;
|
||||
return router;
|
||||
};
|
||||
/**
|
||||
* @param {Number} times 回调函数需要执行的次数
|
||||
* @param {Function} callback 回调函数
|
||||
*/
|
||||
export const doCustomTimes = (times, callback) => {
|
||||
let i = -1;
|
||||
while (++i < times) {
|
||||
callback(i);
|
||||
}
|
||||
};
|
||||
export const showTitle = (item, vm) => {
|
||||
let { title, __titleIsFunction__ } = item.meta;
|
||||
if (!title) return;
|
||||
if (useI18n) {
|
||||
if (title.includes('{{') && title.includes('}}') && useI18n) {
|
||||
title = title.replace(/({{[\s\S]+?}})/, (m, str) =>
|
||||
str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim()))
|
||||
);
|
||||
} else if (__titleIsFunction__) title = item.meta.title;
|
||||
else title = vm.$t(item.name);
|
||||
} else title = (item.meta && item.meta.title) || item.name;
|
||||
return title;
|
||||
};
|
||||
/**
|
||||
* @description 根据当前跳转的路由设置显示在浏览器标签的title
|
||||
* @param {Object} routeItem 路由对象
|
||||
* @param {Object} vm Vue实例
|
||||
*/
|
||||
export const setTitle = (routeItem, vm) => {
|
||||
const handledRoute = getRouteTitleHandled(routeItem);
|
||||
const pageTitle = showTitle(handledRoute, vm);
|
||||
const resTitle = pageTitle ? `${pageTitle} - ${title}` : title;
|
||||
window.document.title = resTitle;
|
||||
};
|
||||
|
||||
export const findNodeUpper = (ele, tag) => {
|
||||
if (ele.parentNode) {
|
||||
if (ele.parentNode.tagName === tag.toUpperCase()) {
|
||||
return ele.parentNode;
|
||||
} else {
|
||||
return findNodeUpper(ele.parentNode, tag);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const findNodeUpperByClasses = (ele, classes) => {
|
||||
let parentNode = ele.parentNode;
|
||||
if (parentNode) {
|
||||
let classList = parentNode.classList;
|
||||
if (
|
||||
classList &&
|
||||
classes.every(className => classList.contains(className))
|
||||
) {
|
||||
return parentNode;
|
||||
} else {
|
||||
return findNodeUpperByClasses(parentNode, classes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const findNodeDownward = (ele, tag) => {
|
||||
const tagName = tag.toUpperCase();
|
||||
if (ele.childNodes.length) {
|
||||
let i = -1;
|
||||
let len = ele.childNodes.length;
|
||||
while (++i < len) {
|
||||
let child = ele.childNodes[i];
|
||||
if (child.tagName === tagName) return child;
|
||||
else return findNodeDownward(child, tag);
|
||||
}
|
||||
}
|
||||
};
|
||||
133
smart_admin_v1/smart-admin-h5/src/lib/printPlugs.js
Normal file
133
smart_admin_v1/smart-admin-h5/src/lib/printPlugs.js
Normal file
@@ -0,0 +1,133 @@
|
||||
// 打印类属性、方法定义
|
||||
/* eslint-disable */
|
||||
//第二个参数表明是否要关闭当前窗口
|
||||
const Print = function(dom, close, options) {
|
||||
if (!(this instanceof Print)) return new Print(dom, close, options);
|
||||
|
||||
this.options = this.extend(
|
||||
{
|
||||
noPrint: '.no-print'
|
||||
},
|
||||
options
|
||||
);
|
||||
|
||||
if (typeof dom === 'string') {
|
||||
this.dom = document.querySelector(dom);
|
||||
} else {
|
||||
this.dom = dom;
|
||||
}
|
||||
|
||||
this.init(close);
|
||||
};
|
||||
Print.prototype = {
|
||||
init: function(close) {
|
||||
var content = this.getStyle() + this.getHtml();
|
||||
this.writeIframe(content, close);
|
||||
},
|
||||
extend: function(obj, obj2) {
|
||||
for (var k in obj2) {
|
||||
obj[k] = obj2[k];
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
getStyle: function() {
|
||||
var str = '',
|
||||
styles = document.querySelectorAll('style,link');
|
||||
for (var i = 0; i < styles.length; i++) {
|
||||
str += styles[i].outerHTML;
|
||||
}
|
||||
str +=
|
||||
'<style>body, html{height: auto; overflow: auto !important;}' +
|
||||
(this.options.noPrint ? this.options.noPrint : '.no-print') +
|
||||
'{display:none;}</style>';
|
||||
|
||||
return str;
|
||||
},
|
||||
|
||||
getHtml: function() {
|
||||
var inputs = document.querySelectorAll('input');
|
||||
var textareas = document.querySelectorAll('textarea');
|
||||
var selects = document.querySelectorAll('select');
|
||||
|
||||
for (var k in inputs) {
|
||||
if (inputs[k].type == 'checkbox' || inputs[k].type == 'radio') {
|
||||
if (inputs[k].checked == true) {
|
||||
inputs[k].setAttribute('checked', 'checked');
|
||||
} else {
|
||||
inputs[k].removeAttribute('checked');
|
||||
}
|
||||
} else if (inputs[k].type == 'text') {
|
||||
inputs[k].setAttribute('value', inputs[k].value);
|
||||
}
|
||||
}
|
||||
|
||||
for (var k2 in textareas) {
|
||||
if (textareas[k2].type == 'textarea') {
|
||||
textareas[k2].innerHTML = textareas[k2].value;
|
||||
}
|
||||
}
|
||||
|
||||
for (var k3 in selects) {
|
||||
if (selects[k3].type == 'select-one') {
|
||||
var child = selects[k3].children;
|
||||
for (var i in child) {
|
||||
if (child[i].tagName == 'OPTION') {
|
||||
if (child[i].selected == true) {
|
||||
child[i].setAttribute('selected', 'selected');
|
||||
} else {
|
||||
child[i].removeAttribute('selected');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.dom.outerHTML;
|
||||
},
|
||||
|
||||
writeIframe: function(content, close) {
|
||||
var w,
|
||||
doc,
|
||||
iframe = document.createElement('iframe'),
|
||||
f = document.body.appendChild(iframe);
|
||||
iframe.id = 'myIframe';
|
||||
iframe.style = 'position:absolute;';
|
||||
|
||||
w = f.contentWindow || f.contentDocument;
|
||||
doc = f.contentDocument || f.contentWindow.document;
|
||||
doc.open();
|
||||
doc.write(content);
|
||||
doc.close();
|
||||
this.toPrint(w, close);
|
||||
setTimeout(function() {
|
||||
document.body.removeChild(iframe);
|
||||
}, 500);
|
||||
},
|
||||
|
||||
toPrint: function(frameWindow, close) {
|
||||
try {
|
||||
setTimeout(function() {
|
||||
frameWindow.focus();
|
||||
try {
|
||||
if (!frameWindow.document.execCommand('print', false, null)) {
|
||||
frameWindow.print();
|
||||
}
|
||||
} catch (e) {
|
||||
frameWindow.print();
|
||||
}
|
||||
frameWindow.close();
|
||||
if (close) {
|
||||
window.close();
|
||||
}
|
||||
}, 500);
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
}
|
||||
}
|
||||
};
|
||||
const MyPlugin = {};
|
||||
MyPlugin.install = function(Vue, options) {
|
||||
// 4. 添加实例方法
|
||||
Vue.prototype.$print = Print;
|
||||
};
|
||||
export default MyPlugin;
|
||||
10
smart_admin_v1/smart-admin-h5/src/lib/render-dom.js
Normal file
10
smart_admin_v1/smart-admin-h5/src/lib/render-dom.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export default {
|
||||
name: 'RenderDom',
|
||||
functional: true,
|
||||
props: {
|
||||
render: Function
|
||||
},
|
||||
render: (h, ctx) => {
|
||||
return ctx.props.render(h);
|
||||
}
|
||||
};
|
||||
21
smart_admin_v1/smart-admin-h5/src/lib/smart-sentry.js
Normal file
21
smart_admin_v1/smart-admin-h5/src/lib/smart-sentry.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* @Description:
|
||||
* @Author: hanyu
|
||||
* @Date: 2020-05-28 12:46:06
|
||||
* @LastEditTime: 2020-07-08 09:16:15
|
||||
* @LastEditors: hy
|
||||
*/
|
||||
// smart sentry
|
||||
import * as Sentry from '@sentry/browser';
|
||||
export default {
|
||||
/**
|
||||
* sentry 主动上报
|
||||
* @param {error} error 错误信息
|
||||
*/
|
||||
captureException: (error) => {
|
||||
if (error.config && error.data && error && error.headers && error.request && error.status) {
|
||||
return;
|
||||
}
|
||||
Sentry.captureException(error);
|
||||
}
|
||||
};
|
||||
515
smart_admin_v1/smart-admin-h5/src/lib/util.js
Normal file
515
smart_admin_v1/smart-admin-h5/src/lib/util.js
Normal file
@@ -0,0 +1,515 @@
|
||||
import moment from 'moment';
|
||||
/**
|
||||
* @param {String} url
|
||||
* @description 从URL中解析参数
|
||||
*/
|
||||
export const getParams = url => {
|
||||
const keyValueArr = url.split('?')[1].split('&');
|
||||
let paramObj = {};
|
||||
keyValueArr.forEach(item => {
|
||||
const keyValue = item.split('=');
|
||||
paramObj[keyValue[0]] = keyValue[1];
|
||||
});
|
||||
return paramObj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Any} obj
|
||||
* @description 获取数据类型
|
||||
*/
|
||||
export const getType = obj => {
|
||||
return {}.toString
|
||||
.call(obj)
|
||||
.match(/\s([a-zA-Z]+)/)[1]
|
||||
.toLowerCase();
|
||||
};
|
||||
// 日期格式
|
||||
export const dateFormat = {
|
||||
YMD: 'YMD',
|
||||
YMDHM: 'YMDHM',
|
||||
YMDHMS: 'YMDHMS'
|
||||
};
|
||||
export const forEach = (arr, fn) => {
|
||||
if (!arr.length || !fn) return;
|
||||
let i = -1;
|
||||
let len = arr.length;
|
||||
while (++i < len) {
|
||||
let item = arr[i];
|
||||
fn(item, i, arr);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array} arr1
|
||||
* @param {Array} arr2
|
||||
* @description 得到两个数组的交集, 两个数组的元素为数值或字符串
|
||||
*/
|
||||
export const getIntersection = (arr1, arr2) => {
|
||||
let len = Math.min(arr1.length, arr2.length);
|
||||
let i = -1;
|
||||
let res = [];
|
||||
while (++i < len) {
|
||||
const item = arr2[i];
|
||||
if (arr1.indexOf(item) > -1) res.push(item);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array} arr1
|
||||
* @param {Array} arr2
|
||||
* @description 得到两个数组的并集, 两个数组的元素为数值或字符串
|
||||
*/
|
||||
export const getUnion = (arr1, arr2) => {
|
||||
return Array.from(new Set([...arr1, ...arr2]));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array} target 目标数组
|
||||
* @param {Array} arr 需要查询的数组
|
||||
* @description 判断要查询的数组是否至少有一个元素包含在目标数组中
|
||||
*/
|
||||
export const hasOneOf = (targetarr, arr) => {
|
||||
return targetarr.some(_ => arr.indexOf(_) > -1);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String|Number} value 要验证的字符串或数值
|
||||
* @param {*} validList 用来验证的列表
|
||||
*/
|
||||
export function oneOf (value, validList) {
|
||||
for (let i = 0; i < validList.length; i++) {
|
||||
if (value === validList[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 判断时间戳格式是否是毫秒
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
const isMillisecond = timeStamp => {
|
||||
const timeStr = String(timeStamp);
|
||||
return timeStr.length > 10;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 传入的时间戳
|
||||
* @param {Number} currentTime 当前时间时间戳
|
||||
* @returns {Boolean} 传入的时间戳是否早于当前时间戳
|
||||
*/
|
||||
const isEarly = (timeStamp, currentTime) => {
|
||||
return timeStamp < currentTime;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Number} num 数值
|
||||
* @returns {String} 处理后的字符串
|
||||
* @description 如果传入的数值小于10,即位数只有1位,则在前面补充0
|
||||
*/
|
||||
const getHandledValue = num => {
|
||||
return num < 10 ? '0' + num : num;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 传入的时间戳
|
||||
* @param {Number} startType 要返回的时间字符串的格式类型,传入'year'则返回年开头的完整时间
|
||||
*/
|
||||
const getDate = (timeStamp, startType) => {
|
||||
const d = new Date(timeStamp * 1000);
|
||||
const year = d.getFullYear();
|
||||
const month = getHandledValue(d.getMonth() + 1);
|
||||
const date = getHandledValue(d.getDate());
|
||||
const hours = getHandledValue(d.getHours());
|
||||
const minutes = getHandledValue(d.getMinutes());
|
||||
const second = getHandledValue(d.getSeconds());
|
||||
let resStr = '';
|
||||
if (startType === 'year') {
|
||||
resStr =
|
||||
year +
|
||||
'-' +
|
||||
month +
|
||||
'-' +
|
||||
date +
|
||||
' ' +
|
||||
hours +
|
||||
':' +
|
||||
minutes +
|
||||
':' +
|
||||
second;
|
||||
}
|
||||
else resStr = month + '-' + date + ' ' + hours + ':' + minutes;
|
||||
return resStr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String|Number} timeStamp 时间戳
|
||||
* @returns {String} 相对时间字符串
|
||||
*/
|
||||
export const getRelativeTime = timeStamp => {
|
||||
// 判断当前传入的时间戳是秒格式还是毫秒
|
||||
const IS_MILLISECOND = isMillisecond(timeStamp);
|
||||
// 如果是毫秒格式则转为秒格式
|
||||
if (IS_MILLISECOND) Math.floor((timeStamp /= 1000));
|
||||
// 传入的时间戳可以是数值或字符串类型,这里统一转为数值类型
|
||||
timeStamp = Number(timeStamp);
|
||||
// 获取当前时间时间戳
|
||||
const currentTime = Math.floor(Date.parse(new Date()) / 1000);
|
||||
// 判断传入时间戳是否早于当前时间戳
|
||||
const IS_EARLY = isEarly(timeStamp, currentTime);
|
||||
// 获取两个时间戳差值
|
||||
let diff = currentTime - timeStamp;
|
||||
// 如果IS_EARLY为false则差值取反
|
||||
if (!IS_EARLY) diff = -diff;
|
||||
let resStr = '';
|
||||
const dirStr = IS_EARLY ? '前' : '后';
|
||||
// 少于等于59秒
|
||||
if (diff <= 59) resStr = diff + '秒' + dirStr;
|
||||
// 多于59秒,少于等于59分钟59秒
|
||||
else if (diff > 59 && diff <= 3599) { resStr = Math.floor(diff / 60) + '分钟' + dirStr; }
|
||||
// 多于59分钟59秒,少于等于23小时59分钟59秒
|
||||
else if (diff > 3599 && diff <= 86399) { resStr = Math.floor(diff / 3600) + '小时' + dirStr; }
|
||||
// 多于23小时59分钟59秒,少于等于29天59分钟59秒
|
||||
else if (diff > 86399 && diff <= 2623859) { resStr = Math.floor(diff / 86400) + '天' + dirStr; }
|
||||
// 多于29天59分钟59秒,少于364天23小时59分钟59秒,且传入的时间戳早于当前
|
||||
else if (diff > 2623859 && diff <= 31567859 && IS_EARLY) { resStr = getDate(timeStamp); }
|
||||
else resStr = getDate(timeStamp, 'year');
|
||||
return resStr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {String} 当前浏览器名称
|
||||
*/
|
||||
export const getExplorer = () => {
|
||||
const ua = window.navigator.userAgent;
|
||||
const isExplorer = exp => {
|
||||
return ua.indexOf(exp) > -1;
|
||||
};
|
||||
if (isExplorer('MSIE')) return 'IE';
|
||||
else if (isExplorer('Firefox')) return 'Firefox';
|
||||
else if (isExplorer('Chrome')) return 'Chrome';
|
||||
else if (isExplorer('Opera')) return 'Opera';
|
||||
else if (isExplorer('Safari')) return 'Safari';
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 绑定事件 on(element, event, handler)
|
||||
*/
|
||||
export const on = (function () {
|
||||
if (document.addEventListener) {
|
||||
return function (element, event, handler) {
|
||||
if (element && event && handler) {
|
||||
element.addEventListener(event, handler, false);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return function (element, event, handler) {
|
||||
if (element && event && handler) {
|
||||
element.attachEvent('on' + event, handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* @description 解绑事件 off(element, event, handler)
|
||||
*/
|
||||
export const off = (function () {
|
||||
if (document.removeEventListener) {
|
||||
return function (element, event, handler) {
|
||||
if (element && event) {
|
||||
element.removeEventListener(event, handler, false);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return function (element, event, handler) {
|
||||
if (element && event) {
|
||||
element.detachEvent('on' + event, handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* 判断一个对象是否存在key,如果传入第二个参数key,则是判断这个obj对象是否存在key这个属性
|
||||
* 如果没有传入key这个参数,则判断obj对象是否有键值对
|
||||
*/
|
||||
export const hasKey = (obj, key) => {
|
||||
if (key) return key in obj;
|
||||
else {
|
||||
let keysArr = Object.keys(obj);
|
||||
return keysArr.length;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} obj1 对象
|
||||
* @param {*} obj2 对象
|
||||
* @description 判断两个对象是否相等,这两个对象的值只能是数字或字符串
|
||||
*/
|
||||
export const objEqual = (obj1, obj2) => {
|
||||
const keysArr1 = Object.keys(obj1);
|
||||
const keysArr2 = Object.keys(obj2);
|
||||
if (keysArr1.length !== keysArr2.length) return false;
|
||||
else if (keysArr1.length === 0 && keysArr2.length === 0) return true;
|
||||
/* eslint-disable-next-line */ else { return !keysArr1.some(key => obj1[key] != obj2[key]); }
|
||||
};
|
||||
|
||||
// 相关工具类
|
||||
export const utils = {
|
||||
/**
|
||||
* @description table实现反选
|
||||
* @param {Object} vm Vue实例
|
||||
* @param {Array} tableSelectDate 选中的数据
|
||||
* @param {Array} allData 所有数据
|
||||
* @param {Array} key 数据中的唯一值
|
||||
*/
|
||||
reverseSelect (vm, tableSelectDate, allData, key) {
|
||||
let copyMess = JSON.parse(JSON.stringify(tableSelectDate));
|
||||
// 流程:先全部选中->再部分选中
|
||||
vm.handleSelectAll(false);
|
||||
// 选中的idList
|
||||
let idList = copyMess.map(item => item[key]);
|
||||
console.log(idList);
|
||||
for (let item of allData) {
|
||||
if (idList.every(id => id !== item.id)) {
|
||||
vm.$set(item, '_checked', true);
|
||||
tableSelectDate.push(item);
|
||||
} else {
|
||||
vm.$set(item, '_checked', false);
|
||||
}
|
||||
}
|
||||
},
|
||||
// 校验字符串是否相同 合同使用
|
||||
contrastString (originStr, changeStr) {
|
||||
let origin = originStr
|
||||
.replace(/\s*/g, '')
|
||||
.replace(/"/g, '\'')
|
||||
.replace(/ /g, '')
|
||||
.replace(/disabled=\/'\/'/g, 'disabled');
|
||||
let change = changeStr
|
||||
.replace(/\s*/g, '')
|
||||
.replace(/"/g, '\'')
|
||||
.replace(/ /g, '')
|
||||
.replace(/disabled=\/'\/'/g, 'disabled');
|
||||
return origin === change;
|
||||
},
|
||||
// 获取当前日期getDateStr(0)、前几天getDateStr(-10)、后几天getDateStr(20)
|
||||
getDateStr (AddDayCount, format) {
|
||||
let date = new Date();
|
||||
// 获取AddDayCount天后的日期
|
||||
date.setDate(date.getDate() + AddDayCount);
|
||||
return this.getDate(date, format);
|
||||
},
|
||||
getDate (date, format) {
|
||||
let year = date.getFullYear();
|
||||
// day获取当前几号,不足10补0
|
||||
let day = date.getDate() > 9 ? date.getDate() : '0' + date.getDate();
|
||||
// month获取当前月份的日期,不足10补0
|
||||
let month =
|
||||
date.getMonth() + 1 > 9
|
||||
? date.getMonth() + 1
|
||||
: '0' + (date.getMonth() + 1);
|
||||
// h获取当前小时,不足10补0
|
||||
let h = date.getHours() > 9 ? date.getHours() : '0' + date.getHours();
|
||||
// s获取当前分钟,不足10补0
|
||||
let m = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes();
|
||||
// s获取当前秒数,不足10补0
|
||||
let s = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds();
|
||||
let resultDate = '';
|
||||
if (format === dateFormat.YMD) {
|
||||
resultDate = year + '-' + month + '-' + day;
|
||||
}
|
||||
if (format === dateFormat.YMDHM) {
|
||||
resultDate = year + '-' + month + '-' + day + ' ' + h + ':' + m;
|
||||
}
|
||||
if (format === dateFormat.YMDHMS) {
|
||||
resultDate = year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s;
|
||||
}
|
||||
return resultDate;
|
||||
},
|
||||
// 获取周一和周日日期,返回两种格式时间
|
||||
getDateWeek () {
|
||||
let now = new Date();
|
||||
let nowTime = now.getTime();
|
||||
let day = now.getDay();
|
||||
let oneDayLong = 1000 * 60 * 60 * 24;
|
||||
let MondayTime = nowTime - (day - 1) * oneDayLong;
|
||||
let SundayTime = nowTime + (7 - day) * oneDayLong;
|
||||
let monday = new Date(MondayTime);
|
||||
let sunday = new Date(SundayTime);
|
||||
return {
|
||||
// first: this.getDateAll(monday),
|
||||
// last: this.getDateAll(sunday),
|
||||
firstDate: monday,
|
||||
lastDate: sunday
|
||||
};
|
||||
},
|
||||
// 获取月初与月末日期,返回两种时间格式
|
||||
getDateMonth () {
|
||||
let dateFirter = new Date();
|
||||
let dateLast = new Date();
|
||||
dateFirter.setDate(1);
|
||||
|
||||
let currentMonth = dateLast.getMonth();
|
||||
let nextMonth = ++currentMonth;
|
||||
let nextMonthFirstDay = new Date(dateLast.getFullYear(), nextMonth, 1);
|
||||
let oneDay = 1000 * 60 * 60 * 24;
|
||||
dateLast = new Date(nextMonthFirstDay - oneDay);
|
||||
|
||||
return {
|
||||
// first: this.getDateAll(dateFirter),
|
||||
// last: this.getDateAll(dateLast),
|
||||
firstDate: dateFirter,
|
||||
lastDate: dateLast
|
||||
};
|
||||
},
|
||||
// 计算天数
|
||||
getDayBetweenDate (date) {
|
||||
date = this.getDate(new Date(date), 'YMD');
|
||||
let startTime = Date.parse(new Date(date)); // IE支持“yyyy/MM/dd”格式
|
||||
let endTime = Date.parse(this.getDate(new Date(), 'YMD'));
|
||||
let day = parseInt((endTime - startTime) / (1000 * 60 * 60 * 24));
|
||||
return day;
|
||||
},
|
||||
getDateIntervalYear (firstDate, secondDate) {
|
||||
if (!firstDate || !secondDate) {
|
||||
return 0;
|
||||
}
|
||||
let first = new Date(firstDate);
|
||||
let second = new Date(secondDate);
|
||||
let firstYear = first.getFullYear();
|
||||
let secondYear = second.getFullYear();
|
||||
let intervalYear = secondYear - firstYear;
|
||||
return intervalYear < 0 ? 0 : intervalYear;
|
||||
},
|
||||
getDateIntervalYearFixed2 (firstDate, secondDate) {
|
||||
if (!firstDate || !secondDate) {
|
||||
return 0;
|
||||
}
|
||||
// 格式化时间
|
||||
let startDate = new Date(this.getDate(new Date(firstDate), 'YMD'));
|
||||
let endDate = new Date(this.getDate(new Date(secondDate), 'YMD'));
|
||||
// 得到毫秒值
|
||||
let startTime = Date.parse(startDate);
|
||||
let endTime = Date.parse(endDate);
|
||||
// 得到差了多少天
|
||||
let day = parseInt((endTime - startTime) / (1000 * 60 * 60 * 24));
|
||||
if (day <= 0) {
|
||||
return 0;
|
||||
}
|
||||
// 得到差的多少年 保留两位小数
|
||||
let resultYear = parseFloat((day / (30 * 12)).toFixed(2));
|
||||
return resultYear;
|
||||
},
|
||||
// 数字转化为中文大写
|
||||
// 代码如下所示:
|
||||
convertCurrency (money) {
|
||||
// 汉字的数字
|
||||
let cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
|
||||
// 基本单位
|
||||
let cnIntRadice = ['', '拾', '佰', '仟'];
|
||||
// 对应整数部分扩展单位
|
||||
let cnIntUnits = ['', '万', '亿', '兆'];
|
||||
// 对应小数部分单位
|
||||
let cnDecUnits = ['角', '分', '毫', '厘'];
|
||||
// 整数金额时后面跟的字符
|
||||
let cnInteger = '整';
|
||||
// 整型完以后的单位
|
||||
let cnIntLast = '元';
|
||||
// 最大处理的数字
|
||||
let maxNum = 999999999999999.9999;
|
||||
// 金额整数部分
|
||||
let integerNum;
|
||||
// 金额小数部分
|
||||
let decimalNum;
|
||||
// 输出的中文金额字符串
|
||||
let chineseStr = '';
|
||||
// 分离金额后用的数组,预定义
|
||||
let parts;
|
||||
if (money === '') {
|
||||
return '';
|
||||
}
|
||||
money = parseFloat(money);
|
||||
if (money >= maxNum) {
|
||||
// 超出最大处理数字
|
||||
return '';
|
||||
}
|
||||
if (money === 0) {
|
||||
chineseStr = cnNums[0] + cnIntLast + cnInteger;
|
||||
return chineseStr;
|
||||
}
|
||||
// 转换为字符串
|
||||
money = money.toString();
|
||||
if (money.indexOf('.') === -1) {
|
||||
integerNum = money;
|
||||
decimalNum = '';
|
||||
} else {
|
||||
parts = money.split('.');
|
||||
integerNum = parts[0];
|
||||
decimalNum = parts[1].substr(0, 4);
|
||||
}
|
||||
// 获取整型部分转换
|
||||
if (parseInt(integerNum, 10) > 0) {
|
||||
let zeroCount = 0;
|
||||
let IntLen = integerNum.length;
|
||||
for (let i = 0; i < IntLen; i++) {
|
||||
let n = integerNum.substr(i, 1);
|
||||
let p = IntLen - i - 1;
|
||||
let q = p / 4;
|
||||
let m = p % 4;
|
||||
if (n === '0') {
|
||||
zeroCount++;
|
||||
} else {
|
||||
if (zeroCount > 0) {
|
||||
chineseStr += cnNums[0];
|
||||
}
|
||||
// 归零
|
||||
zeroCount = 0;
|
||||
chineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
|
||||
}
|
||||
if (m === 0 && zeroCount < 4) {
|
||||
chineseStr += cnIntUnits[q];
|
||||
}
|
||||
}
|
||||
chineseStr += cnIntLast;
|
||||
}
|
||||
// 小数部分
|
||||
if (decimalNum !== '') {
|
||||
let decLen = decimalNum.length;
|
||||
for (let i = 0; i < decLen; i++) {
|
||||
let n = decimalNum.substr(i, 1);
|
||||
if (n !== '0') {
|
||||
chineseStr += cnNums[Number(n)] + cnDecUnits[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chineseStr === '') {
|
||||
chineseStr += cnNums[0] + cnIntLast + cnInteger;
|
||||
} else if (decimalNum === '') {
|
||||
chineseStr += cnInteger;
|
||||
}
|
||||
return chineseStr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const dateTimeRangeConvert = (timerange) => {
|
||||
// timerange
|
||||
let arr = [];
|
||||
if (timerange[0] === '') {
|
||||
arr.push(null);
|
||||
} else {
|
||||
arr.push(moment(timerange[0]).format("YYYY-MM-DD 00:00:00"));
|
||||
}
|
||||
|
||||
if (timerange[1] === '') {
|
||||
arr.push(null);
|
||||
} else {
|
||||
arr.push(moment(timerange[1]).format("YYYY-MM-DD 23:59:59"));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
49
smart_admin_v1/smart-admin-h5/src/lib/watermark.js
Normal file
49
smart_admin_v1/smart-admin-h5/src/lib/watermark.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const watermark = {};
|
||||
|
||||
const setWatermark = (str) => {
|
||||
const id = '1.23452384164.123412415';
|
||||
|
||||
if (document.getElementById(id) !== null) {
|
||||
document.body.removeChild(document.getElementById(id));
|
||||
}
|
||||
|
||||
const can = document.createElement('canvas');
|
||||
can.width = 150;
|
||||
can.height = 120;
|
||||
|
||||
const cans = can.getContext('2d');
|
||||
cans.rotate(-20 * Math.PI / 180);
|
||||
cans.font = '15px Vedana';
|
||||
cans.fillStyle = 'rgba(0, 0, 0, 0.15)';
|
||||
cans.textAlign = 'left';
|
||||
cans.textBaseline = 'Middle';
|
||||
cans.fillText(str, can.width / 20, can.height);
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.id = id;
|
||||
div.style.pointerEvents = 'none';
|
||||
div.style.top = '3px';
|
||||
div.style.left = '0px';
|
||||
div.style.position = 'fixed';
|
||||
div.style.zIndex = '100000';
|
||||
div.style.width = document.documentElement.clientWidth + 'px';
|
||||
div.style.height = document.documentElement.clientHeight + 'px';
|
||||
div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat';
|
||||
document.body.appendChild(div);
|
||||
return id;
|
||||
};
|
||||
|
||||
// 该方法只允许调用一次
|
||||
watermark.set = (str) => {
|
||||
let id = setWatermark(str);
|
||||
setInterval(() => {
|
||||
if (document.getElementById(id) === null) {
|
||||
id = setWatermark(str);
|
||||
}
|
||||
}, 2000);
|
||||
window.onresize = () => {
|
||||
setWatermark(str);
|
||||
};
|
||||
};
|
||||
|
||||
export default watermark;
|
||||
62
smart_admin_v1/smart-admin-h5/src/main.js
Normal file
62
smart_admin_v1/smart-admin-h5/src/main.js
Normal file
@@ -0,0 +1,62 @@
|
||||
// vue 三大核心
|
||||
import Vue from 'vue';
|
||||
import router from '@/router';
|
||||
import store from '@/store';
|
||||
|
||||
// 更好的兼容性
|
||||
import 'core-js/stable';
|
||||
import 'regenerator-runtime/runtime';
|
||||
// 移动端适配
|
||||
import 'lib-flexible/flexible.js';
|
||||
import 'vant/lib/index.css';
|
||||
// 引入首个组件
|
||||
import App from './App.vue';
|
||||
// 引入自定义主题样式
|
||||
import './themes/index.scss';
|
||||
// 引入过滤器
|
||||
import './filters';
|
||||
// 引入配置信息
|
||||
import config from '@/config';
|
||||
// 引入自定义smart 插件
|
||||
import SmartPlugin from './plugins/smart';
|
||||
// Import component
|
||||
import Loading from 'vue-loading-overlay';
|
||||
// Import stylesheet
|
||||
import 'vue-loading-overlay/dist/vue-loading.css';
|
||||
|
||||
import Vant from 'vant';
|
||||
import 'vant/lib/index.css';
|
||||
|
||||
// sentry错误预警
|
||||
import SmartSentry from './plugins/smart-sentry';
|
||||
|
||||
import Enum from 'vue-enum';
|
||||
|
||||
import enumInfo from '@/constants';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
Vue.use(Vant);
|
||||
|
||||
Vue.use(Loading);
|
||||
|
||||
Vue.use(SmartPlugin);
|
||||
|
||||
Vue.use(SmartSentry);
|
||||
|
||||
Vue.prototype.$config = config;
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.use(Enum, {
|
||||
enumInfo
|
||||
});
|
||||
|
||||
window._ = _;
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
});
|
||||
17
smart_admin_v1/smart-admin-h5/src/plugins/smart-sentry.js
Normal file
17
smart_admin_v1/smart-admin-h5/src/plugins/smart-sentry.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import * as Sentry from '@sentry/browser';
|
||||
|
||||
const SmartSentry = {};
|
||||
|
||||
SmartSentry.install = function(Vue, options) {
|
||||
Vue.prototype.$smartSentry = {
|
||||
captureException: (error) => {
|
||||
console.error(error);
|
||||
if (error.config && error.data && error && error.headers && error.request && error.status) {
|
||||
return;
|
||||
}
|
||||
Sentry.captureException(error);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default SmartSentry;
|
||||
24
smart_admin_v1/smart-admin-h5/src/plugins/smart.js
Normal file
24
smart_admin_v1/smart-admin-h5/src/plugins/smart.js
Normal file
@@ -0,0 +1,24 @@
|
||||
let loader = null;
|
||||
|
||||
const SmartPlugin = {};
|
||||
|
||||
SmartPlugin.install = function(Vue, options) {
|
||||
Vue.prototype.$smart = {
|
||||
loading: (message) => {
|
||||
if (loader) {
|
||||
loader.hide();
|
||||
}
|
||||
|
||||
loader = Vue.$loading.show({
|
||||
// Optional parameters
|
||||
lockScroll: true,
|
||||
color: '#1989fa'
|
||||
});
|
||||
},
|
||||
loadingClear: () => {
|
||||
loader.hide();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default SmartPlugin;
|
||||
8
smart_admin_v1/smart-admin-h5/src/plugins/vant.js
Normal file
8
smart_admin_v1/smart-admin-h5/src/plugins/vant.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// 按需全局引入 vant组件
|
||||
import Vue from 'vue';
|
||||
import { Button, List, Cell, Tabbar, TabbarItem } from 'vant';
|
||||
|
||||
Vue.use(Button);
|
||||
Vue.use(Cell);
|
||||
Vue.use(List);
|
||||
Vue.use(Tabbar).use(TabbarItem);
|
||||
42
smart_admin_v1/smart-admin-h5/src/router/dashboard/index.js
Normal file
42
smart_admin_v1/smart-admin-h5/src/router/dashboard/index.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
|
||||
|
||||
/**
|
||||
* dashboard首页
|
||||
*/
|
||||
export const dashboardRouter = [
|
||||
{
|
||||
path: '/',
|
||||
// redirect: '/dashboard/contact-company',
|
||||
redirect: '/dashboard/user',
|
||||
meta: {
|
||||
title: '首页',
|
||||
keepAlive: true,
|
||||
permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
|
||||
},
|
||||
component: () => import('@/views/dashboard/dashboard'),
|
||||
children: [
|
||||
// {
|
||||
// path: '/dashboard/contact-company',
|
||||
// name: 'ContactCompany',
|
||||
// meta: {
|
||||
// title: '往来单位',
|
||||
// keepAlive: true,
|
||||
// showTabbar: true,
|
||||
// permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
|
||||
// },
|
||||
// component: () => import('@/views/erp/contact-company/contact-company')
|
||||
// },
|
||||
{
|
||||
path: '/dashboard/user',
|
||||
name: 'Mine',
|
||||
meta: {
|
||||
title: '我的',
|
||||
keepAlive: false,
|
||||
showTabbar: true,
|
||||
permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
|
||||
},
|
||||
component: () => import('@/views/user/index')
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
21
smart_admin_v1/smart-admin-h5/src/router/develop/develop.js
Normal file
21
smart_admin_v1/smart-admin-h5/src/router/develop/develop.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
|
||||
|
||||
export const developRouter = [
|
||||
{
|
||||
path: '/develop',
|
||||
component: () => import('@/views/dashboard/dashboard'),
|
||||
children: [
|
||||
{
|
||||
path: '/develop/config',
|
||||
name: 'DevelopConfig',
|
||||
meta: {
|
||||
title: '开发专用配置',
|
||||
permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
|
||||
},
|
||||
component: () => import('views/develop/config')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
26
smart_admin_v1/smart-admin-h5/src/router/error/error.js
Normal file
26
smart_admin_v1/smart-admin-h5/src/router/error/error.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// 错误页
|
||||
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
|
||||
|
||||
export const errorRouter = [
|
||||
{
|
||||
path: '/404',
|
||||
name: 'Error404',
|
||||
meta: {
|
||||
hideInMenu: true,
|
||||
access: true,
|
||||
permissionType: ROUTER_PERMISSION_TYPE.NO_VALID.value
|
||||
},
|
||||
component: () => import('views/error/404.vue')
|
||||
},
|
||||
{
|
||||
path: '/500',
|
||||
name: 'Error500',
|
||||
meta: {
|
||||
hideInMenu: true,
|
||||
access: true,
|
||||
noValidatePrivilege: true,
|
||||
permissionType: ROUTER_PERMISSION_TYPE.NO_VALID.value
|
||||
},
|
||||
component: () => import('views/error/404.vue')
|
||||
}
|
||||
];
|
||||
150
smart_admin_v1/smart-admin-h5/src/router/index.js
Normal file
150
smart_admin_v1/smart-admin-h5/src/router/index.js
Normal file
@@ -0,0 +1,150 @@
|
||||
import Vue from 'vue';
|
||||
import Router from 'vue-router';
|
||||
import { routers } from './routers';
|
||||
import cookie from '@/lib/cookie';
|
||||
import { ROUTER_PERMISSION_TYPE } from './router-const';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
|
||||
const projectConfig = require('@/config/index.js');
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
/**
|
||||
* 导入所有的router
|
||||
* @type {VueRouter}
|
||||
*/
|
||||
const router = new Router({
|
||||
routes: routers
|
||||
});
|
||||
|
||||
// 解决路由跳转相同的地址报错
|
||||
const originalPush = Router.prototype.push;
|
||||
Router.prototype.push = function(location) {
|
||||
try {
|
||||
return originalPush.call(this, location).catch(err => err);
|
||||
} catch (error) {
|
||||
// TODO zhuoda sentry
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const LOGIN_PAGE_NAME = 'Login';
|
||||
|
||||
// --------------------- router 守卫 begin ---------------------
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 加载进度条
|
||||
NProgress.start();
|
||||
|
||||
// 权限
|
||||
const permissionType = to.meta.permissionType;
|
||||
// 不需要验证,直接放行
|
||||
if (permissionType === ROUTER_PERMISSION_TYPE.NO_VALID.value) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
const token = cookie.getToken();
|
||||
// 需要登录
|
||||
if (permissionType === ROUTER_PERMISSION_TYPE.NEED_LOGIN.value) {
|
||||
if (token) {
|
||||
next();
|
||||
} else {
|
||||
next({
|
||||
name: LOGIN_PAGE_NAME
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 需要登录,且验证权限
|
||||
if (permissionType === ROUTER_PERMISSION_TYPE.VALIDATE_PERMISSION.value) {
|
||||
if (!token) {
|
||||
// TODO 验证权限
|
||||
next({
|
||||
name: LOGIN_PAGE_NAME
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
next({
|
||||
name: 'Error404'
|
||||
});
|
||||
});
|
||||
|
||||
router.afterEach(to => {
|
||||
NProgress.done();
|
||||
window.scrollTo(0, 0);
|
||||
if (to.meta.title) {
|
||||
console.log(to.meta);
|
||||
document.title = to.meta.title + ' ' + projectConfig.title;
|
||||
}
|
||||
});
|
||||
|
||||
// --------------------- router 守卫 end ---------------------
|
||||
|
||||
/**
|
||||
* router 检测
|
||||
*
|
||||
* 如果存在相同的 path 或者 name 是一件非常恐怖的事情,所以在develop环境将所有router进行一次遍历<br>
|
||||
* 检测内容如下:<br>
|
||||
* 1、相同的router name
|
||||
* 2、相同的router name
|
||||
* 3、path没有以 / 开头
|
||||
*
|
||||
*/
|
||||
|
||||
const tempCheckObj = {
|
||||
checkRouterNameMap: new Map(),
|
||||
checkRouterPathMap: new Map()
|
||||
};
|
||||
|
||||
function recursionCheckRouter(routerArray) {
|
||||
for (const routerItem of routerArray) {
|
||||
if (!routerItem.name) {
|
||||
console.error('没有配置router name', routerItem);
|
||||
} else {
|
||||
const existNameRouter = tempCheckObj.checkRouterNameMap.get(
|
||||
routerItem.name
|
||||
);
|
||||
if (typeof existNameRouter !== 'undefined') {
|
||||
console.error('存在相同的router name', routerItem, existNameRouter);
|
||||
} else {
|
||||
tempCheckObj.checkRouterNameMap.set(routerItem.name, routerItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (!routerItem.path) {
|
||||
console.error('没有配置router path', routerItem);
|
||||
} else {
|
||||
// path必须以 / 开头
|
||||
if (routerItem.path !== '*' && routerItem.path.indexOf('/') !== 0) {
|
||||
console.error('path 没有以/开头 ', routerItem);
|
||||
}
|
||||
|
||||
const existPathRouter = tempCheckObj.checkRouterPathMap.get(
|
||||
routerItem.path
|
||||
);
|
||||
if (typeof existPathRouter !== 'undefined') {
|
||||
console.error('存在相同的router path', routerItem, existPathRouter);
|
||||
} else {
|
||||
tempCheckObj.checkRouterPathMap.set(routerItem.path, routerItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (routerItem.children) {
|
||||
recursionCheckRouter(routerItem.children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是开发环境,需要检测router的规范性
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
recursionCheckRouter(routers);
|
||||
delete tempCheckObj.checkRouterNameMap;
|
||||
delete tempCheckObj.checkRouterPathMap;
|
||||
}
|
||||
|
||||
export default router;
|
||||
15
smart_admin_v1/smart-admin-h5/src/router/login/login.js
Normal file
15
smart_admin_v1/smart-admin-h5/src/router/login/login.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
|
||||
|
||||
export const loginRouter = [
|
||||
{
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
meta: {
|
||||
title: '登录',
|
||||
keepAlive: false,
|
||||
permissionType: ROUTER_PERMISSION_TYPE.NO_VALID.value
|
||||
},
|
||||
component: () => import('@/views/login/login.vue')
|
||||
}
|
||||
|
||||
];
|
||||
23
smart_admin_v1/smart-admin-h5/src/router/router-const.js
Normal file
23
smart_admin_v1/smart-admin-h5/src/router/router-const.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 权限类型
|
||||
*/
|
||||
export const ROUTER_PERMISSION_TYPE = {
|
||||
/**
|
||||
* 不 验 证
|
||||
*/
|
||||
NO_VALID: {
|
||||
value: 1
|
||||
},
|
||||
/**
|
||||
* 需要登录
|
||||
*/
|
||||
NEED_LOGIN: {
|
||||
value: 2
|
||||
},
|
||||
/**
|
||||
* 需要验证权限
|
||||
*/
|
||||
VALIDATE_PERMISSION: {
|
||||
value: 3
|
||||
}
|
||||
};
|
||||
32
smart_admin_v1/smart-admin-h5/src/router/routers.js
Normal file
32
smart_admin_v1/smart-admin-h5/src/router/routers.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// 全局错误页面
|
||||
import { errorRouter } from './error/error';
|
||||
// 登录注册模块
|
||||
import { loginRouter } from './login/login';
|
||||
// tabbar dashboard 框架页面
|
||||
import { dashboardRouter } from './dashboard';
|
||||
// 用户相关
|
||||
import { userRouter } from './user/user';
|
||||
// 开发相关
|
||||
import { developRouter } from './develop/develop';
|
||||
|
||||
/**
|
||||
* router meta 说明: <br>
|
||||
*
|
||||
* title: 为页面的title,会显示到浏览器的title上
|
||||
* permissionType: 具体使用 router-const.js中的 ROUTER_PERMISSION_TYPE 常量;情况有: 1)不验证 2)校验登录 3)登录后校验权限
|
||||
* keepAlive: true or false ; 是否进行页面keepalive, 如果想删除keepalive,可以使用vuex中的app module里有mutation
|
||||
* showTabbar: true or false ; 是否展示 tabbar, 如果是true, 则会展示tabbar
|
||||
*
|
||||
*/
|
||||
export const routers = [
|
||||
// 登录、注册
|
||||
...loginRouter,
|
||||
// 404、500、403等
|
||||
...errorRouter,
|
||||
// tab bar 页面
|
||||
...dashboardRouter,
|
||||
// 用户
|
||||
...userRouter,
|
||||
// 开发相关
|
||||
...developRouter
|
||||
];
|
||||
21
smart_admin_v1/smart-admin-h5/src/router/user/user.js
Normal file
21
smart_admin_v1/smart-admin-h5/src/router/user/user.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
|
||||
|
||||
export const userRouter = [
|
||||
{
|
||||
path: '/user',
|
||||
component: () => import('@/views/dashboard/dashboard'),
|
||||
children: [
|
||||
{
|
||||
path: '/user/change-password',
|
||||
name: 'UserChangePassword',
|
||||
meta: {
|
||||
title: '修改密码',
|
||||
permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
|
||||
},
|
||||
component: () =>
|
||||
import('views/user/change-password')
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
23
smart_admin_v1/smart-admin-h5/src/store/index.js
Normal file
23
smart_admin_v1/smart-admin-h5/src/store/index.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import user from './module/user';
|
||||
import app from './module/app';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
//
|
||||
},
|
||||
mutations: {
|
||||
//
|
||||
},
|
||||
actions: {
|
||||
//
|
||||
},
|
||||
modules: {
|
||||
app,
|
||||
user
|
||||
}
|
||||
});
|
||||
32
smart_admin_v1/smart-admin-h5/src/store/module/app.js
Normal file
32
smart_admin_v1/smart-admin-h5/src/store/module/app.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 整个应用相关的状态信息
|
||||
*
|
||||
* 比如: keepalive等
|
||||
*/
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
// 缓存路由
|
||||
keepAliveIncludes: []
|
||||
},
|
||||
|
||||
mutations: {
|
||||
// 加入keep-alive缓存
|
||||
pushKeepAliveIncludes(state, val) {
|
||||
if (state.keepAliveIncludes.length < 30) {
|
||||
const number = state.keepAliveIncludes.findIndex(e => e === val);
|
||||
if (number === -1) {
|
||||
state.keepAliveIncludes.push(val);
|
||||
}
|
||||
}
|
||||
},
|
||||
// 删除缓存
|
||||
deleteKeepAliveIncludes(state, val) {
|
||||
const number = state.keepAliveIncludes.findIndex(e => e === val);
|
||||
if (number !== -1) {
|
||||
state.keepAliveIncludes.splice(number, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
41
smart_admin_v1/smart-admin-h5/src/store/module/user.js
Normal file
41
smart_admin_v1/smart-admin-h5/src/store/module/user.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import cookie from '@/lib/cookie.js';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
token: cookie.getToken(),
|
||||
// session 信息
|
||||
sessionInfo: {},
|
||||
// 是否获取了session
|
||||
isHaveGotSessionInfo: false,
|
||||
// 权限集合
|
||||
privilegeKeySet: new Set()
|
||||
|
||||
},
|
||||
mutations: {
|
||||
clearSession() {
|
||||
state.token = null;
|
||||
state.sessionInfo = null;
|
||||
state.privilegeKeySet = new Set();
|
||||
},
|
||||
updateSession(state, userLoginInfo) {
|
||||
state.isHaveGotSessionInfo = true;
|
||||
state.sessionInfo = userLoginInfo;
|
||||
if (userLoginInfo.privilegeList) {
|
||||
state.privilegeKeySet = new Set(userLoginInfo.privilegeList.map(e => e.key));
|
||||
}
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
// 用户菜单权限
|
||||
privilegeKeySet: state => state.privilegeKeySet,
|
||||
isSuperMan: state => state.sessionInfo.isSuperMan,
|
||||
actualName: state => state.sessionInfo.actualName,
|
||||
loginUserId: state => state.sessionInfo.id
|
||||
},
|
||||
actions: {
|
||||
// 登录
|
||||
handleLogin({ commit }, params) {
|
||||
}
|
||||
}
|
||||
};
|
||||
6
smart_admin_v1/smart-admin-h5/src/themes/index.scss
Normal file
6
smart_admin_v1/smart-admin-h5/src/themes/index.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family: Arial, Helvetica, 'STHeiti STXihei', 'Microsoft YaHei', Tohoma, sans-serif;
|
||||
background-color: $background-color;
|
||||
}
|
||||
110
smart_admin_v1/smart-admin-h5/src/utils/index.js
Normal file
110
smart_admin_v1/smart-admin-h5/src/utils/index.js
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Created by PanJiaChen on 16/11/18.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse the time to string
|
||||
* @param {(Object|string|number)} time
|
||||
* @param {string} cFormat
|
||||
* @returns {string}
|
||||
*/
|
||||
export function parseTime(time, cFormat) {
|
||||
if (arguments.length === 0) {
|
||||
return null
|
||||
}
|
||||
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
||||
let date
|
||||
if (typeof time === 'object') {
|
||||
date = time
|
||||
} else {
|
||||
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
|
||||
time = parseInt(time)
|
||||
}
|
||||
if ((typeof time === 'number') && (time.toString().length === 10)) {
|
||||
time = time * 1000
|
||||
}
|
||||
date = new Date(time)
|
||||
}
|
||||
const formatObj = {
|
||||
y: date.getFullYear(),
|
||||
m: date.getMonth() + 1,
|
||||
d: date.getDate(),
|
||||
h: date.getHours(),
|
||||
i: date.getMinutes(),
|
||||
s: date.getSeconds(),
|
||||
a: date.getDay()
|
||||
}
|
||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
||||
let value = formatObj[key]
|
||||
// Note: getDay() returns 0 on Sunday
|
||||
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = '0' + value
|
||||
}
|
||||
return value || 0
|
||||
})
|
||||
return time_str
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} time
|
||||
* @param {string} option
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatTime(time, option) {
|
||||
if (('' + time).length === 10) {
|
||||
time = parseInt(time) * 1000
|
||||
} else {
|
||||
time = +time
|
||||
}
|
||||
const d = new Date(time)
|
||||
const now = Date.now()
|
||||
|
||||
const diff = (now - d) / 1000
|
||||
|
||||
if (diff < 30) {
|
||||
return '刚刚'
|
||||
} else if (diff < 3600) {
|
||||
// less 1 hour
|
||||
return Math.ceil(diff / 60) + '分钟前'
|
||||
} else if (diff < 3600 * 24) {
|
||||
return Math.ceil(diff / 3600) + '小时前'
|
||||
} else if (diff < 3600 * 24 * 2) {
|
||||
return '1天前'
|
||||
}
|
||||
if (option) {
|
||||
return parseTime(time, option)
|
||||
} else {
|
||||
return (
|
||||
d.getMonth() +
|
||||
1 +
|
||||
'月' +
|
||||
d.getDate() +
|
||||
'日' +
|
||||
d.getHours() +
|
||||
'时' +
|
||||
d.getMinutes() +
|
||||
'分'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function param2Obj(url) {
|
||||
const search = url.split('?')[1]
|
||||
if (!search) {
|
||||
return {}
|
||||
}
|
||||
return JSON.parse(
|
||||
'{"' +
|
||||
decodeURIComponent(search)
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/&/g, '","')
|
||||
.replace(/=/g, '":"')
|
||||
.replace(/\+/g, ' ') +
|
||||
'"}'
|
||||
)
|
||||
}
|
||||
58
smart_admin_v1/smart-admin-h5/src/utils/request.js
Normal file
58
smart_admin_v1/smart-admin-h5/src/utils/request.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import axios from 'axios'
|
||||
import store from '@/store'
|
||||
import { Toast } from 'vant'
|
||||
// 根据环境不同引入不同api地址
|
||||
import { baseApi } from '@/config'
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
baseURL: baseApi, // url = base api url + request url
|
||||
withCredentials: true, // send cookies when cross-domain requests
|
||||
timeout: 5000 // request timeout
|
||||
})
|
||||
|
||||
// request拦截器 request interceptor
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// 不传递默认开启loading
|
||||
if (!config.hideloading) {
|
||||
// loading
|
||||
Toast.loading({
|
||||
forbidClick: true
|
||||
})
|
||||
}
|
||||
if (store.getters.token) {
|
||||
config.headers['X-Token'] = ''
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// do something with request error
|
||||
console.log(error) // for debug
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
// respone拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
Toast.clear()
|
||||
const res = response.data
|
||||
if (res.status && res.status !== 200) {
|
||||
// 登录超时,重新登录
|
||||
if (res.status === 401) {
|
||||
store.dispatch('FedLogOut').then(() => {
|
||||
location.reload()
|
||||
})
|
||||
}
|
||||
return Promise.reject(res || 'error')
|
||||
} else {
|
||||
return Promise.resolve(res)
|
||||
}
|
||||
},
|
||||
error => {
|
||||
Toast.clear()
|
||||
console.log('err' + error) // for debug
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default service
|
||||
20
smart_admin_v1/smart-admin-h5/src/utils/validate.js
Normal file
20
smart_admin_v1/smart-admin-h5/src/utils/validate.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Created by Sunnie on 19/06/04.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function validUsername(str) {
|
||||
const valid_map = ['admin', 'editor']
|
||||
return valid_map.indexOf(str.trim()) >= 0
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<!---------------- 页面内容 begin ---------------->
|
||||
<div class="main-content">
|
||||
<keep-alive :include="keepAliveIncludes">
|
||||
<router-view/>
|
||||
</keep-alive>
|
||||
</div>
|
||||
<!---------------- 页面内容 end ---------------->
|
||||
|
||||
<!---------------- 底部 tabbar begin ---------------->
|
||||
|
||||
<!---------------- 对于一些需要展示tabbar的页面,则进行展示 ---------------->
|
||||
<div class="main-footer" v-show="$route.meta && $route.meta.showTabbar">
|
||||
<van-tabbar
|
||||
fixed
|
||||
route
|
||||
v-model="active"
|
||||
>
|
||||
<van-tabbar-item
|
||||
v-for="(item, index) in tabbar"
|
||||
:to="item.to"
|
||||
:icon="item.icon"
|
||||
:name="item.name"
|
||||
:key="index">
|
||||
{{ item.title }}
|
||||
</van-tabbar-item>
|
||||
</van-tabbar>
|
||||
</div>
|
||||
<!---------------- 底部 tabbar end ---------------->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script type="text/javascript">
|
||||
import SessionMixin from 'components/mixin/session-mixin';
|
||||
import { mapMutations, mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'DashBoard',
|
||||
mixins: [SessionMixin],
|
||||
data() {
|
||||
return {
|
||||
active: 'Mine',
|
||||
tabbar: [
|
||||
// {
|
||||
// name: 'ContactCompany',
|
||||
// title: '首页',
|
||||
// icon: 'user-o',
|
||||
// badge: 0,
|
||||
// to: '/contact-company'
|
||||
// },
|
||||
{
|
||||
name: 'Mine',
|
||||
title: '我的',
|
||||
icon: 'user-o',
|
||||
to: '/user'
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
keepAliveIncludes: state => state.app.keepAliveIncludes
|
||||
})
|
||||
},
|
||||
created() {
|
||||
// 通过路由跳转绑定Tabbar的选中
|
||||
this.updateTabbarSelected(this.$route.name);
|
||||
this.checkRouterKeepAlive(this.$route);
|
||||
},
|
||||
watch: {
|
||||
$route(newRoute) {
|
||||
this.checkRouterKeepAlive(newRoute);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('app', [
|
||||
'pushKeepAliveIncludes',
|
||||
'deleteKeepAliveIncludes'
|
||||
]),
|
||||
checkRouterKeepAlive(newRoute) {
|
||||
const { name, meta } = newRoute;
|
||||
if (meta && meta.keepAlive) {
|
||||
this.pushKeepAliveIncludes(name);
|
||||
} else {
|
||||
this.deleteKeepAliveIncludes(name);
|
||||
}
|
||||
},
|
||||
updateTabbarSelected(item) {
|
||||
console.log(item, 12222);
|
||||
this.active = item;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
47
smart_admin_v1/smart-admin-h5/src/views/develop/config.vue
Normal file
47
smart_admin_v1/smart-admin-h5/src/views/develop/config.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<!-- home -->
|
||||
<template>
|
||||
<div>
|
||||
<router-nav-bar path="/dashboard/user" title="开发专用配置" left-text="返回" left-arrow />
|
||||
|
||||
<van-cell center title="VConsole">
|
||||
<van-switch v-model="vconsoleFlag" @change="switchVConsole" />
|
||||
</van-cell>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RouterNavBar from 'components/van-bar/RouterNavBar';
|
||||
const VCONSOLE_ID = '__vconsole';
|
||||
export default {
|
||||
name: 'DevelopConfig',
|
||||
components: {
|
||||
RouterNavBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
vconsole: null,
|
||||
vconsoleFlag: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.checkVConsoleExist();
|
||||
},
|
||||
methods: {
|
||||
// 检测vconsole是否存在
|
||||
checkVConsoleExist() {
|
||||
const vconsoleElement = document.getElementById(VCONSOLE_ID);
|
||||
this.vconsoleFlag = !!vconsoleElement;
|
||||
},
|
||||
// 提交表单
|
||||
switchVConsole(flag) {
|
||||
if (flag) {
|
||||
this.vconsole = new VConsole();
|
||||
} else {
|
||||
delete this.vconsole;
|
||||
document.getElementById(VCONSOLE_ID).remove();
|
||||
this.vconsole = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
23
smart_admin_v1/smart-admin-h5/src/views/error/404.vue
Normal file
23
smart_admin_v1/smart-admin-h5/src/views/error/404.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<!-- home -->
|
||||
<template>
|
||||
<div class="index-container">
|
||||
<h1>404!</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list: []
|
||||
};
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
mounted() {
|
||||
},
|
||||
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
68
smart_admin_v1/smart-admin-h5/src/views/login/login.vue
Normal file
68
smart_admin_v1/smart-admin-h5/src/views/login/login.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<!-- home -->
|
||||
<template>
|
||||
<div style="padding: 0.4rem">
|
||||
<h1 align="center">Smart-Admin-H5</h1>
|
||||
<van-form @submit="onSubmit">
|
||||
<van-field
|
||||
v-model="formData.loginName"
|
||||
name="用户名"
|
||||
label="用户名"
|
||||
placeholder="用户名"
|
||||
:rules="[{ required: true, message: '请填写用户名' }]"
|
||||
/>
|
||||
<van-field
|
||||
v-model="formData.loginPwd"
|
||||
type="password"
|
||||
name="密码"
|
||||
label="密码"
|
||||
placeholder="密码"
|
||||
:rules="[{ required: true, message: '请填写密码' }]"
|
||||
/>
|
||||
<div style="margin: 16px;">
|
||||
<van-button block type="info" native-type="submit">
|
||||
登录
|
||||
</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { loginApi } from '@/api/login';
|
||||
import cookie from '@/lib/cookie';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
loginName: '',
|
||||
loginPwd: ''
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
// 提交登录表单
|
||||
async onSubmit() {
|
||||
this.$smart.loading();
|
||||
try {
|
||||
const res = await loginApi.login(this.formData);
|
||||
const loginInfo = res.data;
|
||||
this.$store.commit('user/updateSession', loginInfo);
|
||||
cookie.setToken(loginInfo.xaccessToken);
|
||||
this.$toast.success('登录成功');
|
||||
this.$router.replace('/dashboard/user');
|
||||
// this.$router.replace('/contact-company');
|
||||
} catch (e) {
|
||||
this.$smartSentry.captureException(e);
|
||||
await this.getVerificationCode();
|
||||
} finally {
|
||||
this.$smart.loadingClear();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,76 @@
|
||||
<!-- home -->
|
||||
<template>
|
||||
<div>
|
||||
<router-nav-bar path="/dashboard/user" title="修改密码" left-text="返回" left-arrow />
|
||||
|
||||
<van-form @submit="onSubmit">
|
||||
<van-field
|
||||
v-model="formData.loginName"
|
||||
name="旧密码"
|
||||
label="旧密码"
|
||||
placeholder="旧密码"
|
||||
:rules="[{ required: true, message: '请填写旧密码' }]"
|
||||
/>
|
||||
<van-field
|
||||
v-model="formData.loginPwd"
|
||||
type="password"
|
||||
name="新密码"
|
||||
label="新密码"
|
||||
placeholder="新密码"
|
||||
:rules="[{ required: true, message: '请填写新密码' }]"
|
||||
/>
|
||||
<van-field
|
||||
style="width: 60%;float:left"
|
||||
v-model="formData.code"
|
||||
type="password"
|
||||
name="新密码"
|
||||
label="新密码"
|
||||
placeholder="新密码"
|
||||
:rules="[{ required: true, message: '请填写新密码' }]"
|
||||
/>
|
||||
<div style="margin: 16px;">
|
||||
<van-button block type="info" native-type="submit" size="small">
|
||||
提交
|
||||
</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RouterNavBar from 'components/van-bar/RouterNavBar';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
RouterNavBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
loginName: '',
|
||||
loginPwd: '',
|
||||
code: '',
|
||||
codeUuid: ''
|
||||
},
|
||||
codeUrl: ''
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
// 提交表单
|
||||
onSubmit() {
|
||||
this.$smart.loading();
|
||||
try {
|
||||
this.$toast.success('暂未实现');
|
||||
this.$router.replace('/dashboard/user');
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.$smartSentry.captureException(e);
|
||||
} finally {
|
||||
this.$smart.loadingClear();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
79
smart_admin_v1/smart-admin-h5/src/views/user/index.vue
Normal file
79
smart_admin_v1/smart-admin-h5/src/views/user/index.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<!-- home -->
|
||||
<template>
|
||||
<div>
|
||||
<van-nav-bar title="个人中心"/>
|
||||
|
||||
<van-grid :column-num="1">
|
||||
<van-grid-item icon="home-o" :text="actualName"/>
|
||||
</van-grid>
|
||||
|
||||
<van-cell-group>
|
||||
<van-cell icon="location-o" to="/user/change-password" title="修改密码" is-link />
|
||||
<van-cell icon="bulb-o" title="更新权限" @click="forceUpdatePrivilege" is-link/>
|
||||
<van-cell icon="delete" title="清空缓存" @click="clearCache" is-link/>
|
||||
<van-cell icon="apps-o" title="开发专用" is-link to="/develop/config"/>
|
||||
</van-cell-group>
|
||||
|
||||
<div style="margin: 16px;">
|
||||
<van-button block @click="logout" type="warning" size="small">
|
||||
退出登录
|
||||
</van-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { loginApi } from 'api/login';
|
||||
import cookie from '@/lib/cookie';
|
||||
import { userApi } from 'api/user';
|
||||
|
||||
export default {
|
||||
name: 'Mine',
|
||||
data() {
|
||||
return {
|
||||
actualName: null
|
||||
};
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
mounted() {
|
||||
this.actualName = '你好, ' + this.$store.getters['user/actualName'];
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 清空缓存
|
||||
clearCache() {
|
||||
this.$toast('清空了!!');
|
||||
},
|
||||
// 更新权限
|
||||
async forceUpdatePrivilege() {
|
||||
this.$smart.loading();
|
||||
try {
|
||||
const res = await userApi.getSession();
|
||||
const loginInfo = res.data;
|
||||
this.$store.commit('user/updateSession', loginInfo);
|
||||
this.$toast('已成功更新权限!');
|
||||
} catch (e) {
|
||||
this.$smartSentry.captureException(e);
|
||||
} finally {
|
||||
this.$smart.loadingClear();
|
||||
}
|
||||
},
|
||||
// 退出
|
||||
async logout() {
|
||||
this.$smart.loading();
|
||||
try {
|
||||
await loginApi.logout(cookie.getToken());
|
||||
} catch (e) {
|
||||
this.$smartSentry.captureException(e);
|
||||
} finally {
|
||||
cookie.clearToken();
|
||||
this.$smart.loadingClear();
|
||||
this.$router.replace('/login');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user