feat: update 1.11.0

This commit is contained in:
FairyEver
2020-05-08 10:41:10 +08:00
parent 9e8e3345f1
commit f9f0607430
41 changed files with 17240 additions and 825 deletions
+14
View File
@@ -0,0 +1,14 @@
import { assign, map } from 'lodash'
import faker from 'faker/locale/zh_CN'
import { request, mock } from './service'
import * as tools from './tools'
const files = require.context('./modules', false, /\.js$/)
const generators = files.keys().map(key => files(key).default)
export default assign({}, ...map(generators, generator => generator({
request,
faker,
mock,
tools
})))
+31
View File
@@ -0,0 +1,31 @@
import { find, assign } from 'lodash'
const users = [
{ username: 'admin', password: 'admin', uuid: 'admin-uuid', name: 'Admin' },
{ username: 'editor', password: 'editor', uuid: 'editor-uuid', name: 'Editor' },
{ username: 'user1', password: 'user1', uuid: 'user1-uuid', name: 'User1' }
]
export default ({ request, faker, mock, tools }) => ({
/**
* @description 登录
* @param {Object} data 登录携带的信息
*/
SYS_USER_LOGIN (data = {}) {
// 模拟数据
mock
.onAny('/login')
.reply(config => {
const user = find(users, tools.parse(config.data))
return user
? tools.responseSuccess(assign({}, user, { token: faker.random.uuid() }))
: tools.responseError({}, '账号或密码不正确')
})
// 接口请求
return request({
url: '/login',
method: 'post',
data
})
}
})
@@ -1,7 +1,9 @@
import store from '@/store'
import axios from 'axios'
import Adapter from 'axios-mock-adapter'
import { Message } from 'element-ui'
import { get } from 'lodash'
import util from '@/libs/util'
import store from '@/store'
// 创建一个错误
function errorCreate (msg) {
@@ -34,20 +36,11 @@ function errorLog (error) {
}
// 创建一个 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_API,
timeout: 5000 // 请求超时时间
})
const service = axios.create()
// 请求拦截器
service.interceptors.request.use(
config => {
// 在请求发送之前做一些处理
const token = util.cookies.get('token')
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
config.headers['X-Token'] = token
return config
},
config => config,
error => {
// 发送失败
console.log(error)
@@ -105,4 +98,18 @@ service.interceptors.response.use(
}
)
export default service
export const mock = new Adapter(service)
export function request (config) {
const token = util.cookies.get('token')
const configDefault = {
headers: {
Authorization: token,
'Content-Type': get(config, 'headers.Content-Type', 'application/json')
},
timeout: 5000,
baseURL: process.env.VUE_APP_API,
data: {}
}
return service(Object.assign(configDefault, config))
}
-9
View File
@@ -1,9 +0,0 @@
import request from '@/plugin/axios'
export function accountLogin (data) {
return request({
url: '/login',
method: 'post',
data
})
}
+46
View File
@@ -0,0 +1,46 @@
/**
* @description 安全地解析 json 字符串
* @param {String} jsonString 需要解析的 json 字符串
* @param {String} defaultValue 默认值
*/
export function parse (jsonString = '{}', defaultValue = {}) {
let result = defaultValue
try {
result = JSON.parse(jsonString)
} catch (error) {
console.log(error)
}
return result
}
/**
* @description 接口请求返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
* @param {Number} code 状态码
*/
export function response (data = {}, msg = '', code = 0) {
return [
200,
{ code, msg, data }
]
}
/**
* @description 接口请求返回 正确返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
*/
export function responseSuccess (data = {}, msg = '成功') {
return response(data, msg)
}
/**
* @description 接口请求返回 错误返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
* @param {Number} code 状态码
*/
export function responseError (data = {}, msg = '请求失败', code = 500) {
return response(data, msg, code)
}
+9
View File
@@ -0,0 +1,9 @@
// markdown 样式补丁
.markdown-body {
ul {
list-style: disc;
}
h1, h2 {
border-bottom: none;
}
}
+5
View File
@@ -0,0 +1,5 @@
.tree-view-wrapper.tree-view-small {
.tree-view-item {
font-size: 10px;
}
}
@@ -0,0 +1,9 @@
// vue-splitpane 样式补丁
.vue-grid-item {
&.vue-grid-placeholder {
border: 1px solid $color-border-1;
background-color: rgba(#FFF, .3);
opacity: 1;
border-radius: 4px;
}
}
@@ -0,0 +1,5 @@
// vue-splitpane 样式补丁
.splitter-pane-resizer {
background-color: $color-border-1 !important;
opacity: 1 !important;
}
+10
View File
@@ -4,6 +4,16 @@
@import '~@/assets/style/fixed/base.scss';
// 补丁 element
@import '~@/assets/style/fixed/element.scss';
// 补丁 markdown
@import '~@/assets/style/fixed/markdown.scss';
// 补丁 n-progress
@import '~@/assets/style/fixed/n-progress.scss';
// 补丁 vue-splitpane
@import '~@/assets/style/fixed/vue-splitpane.scss';
// 补丁 vue-grid-layout
@import '~@/assets/style/fixed/vue-grid-layout.scss';
// 补丁 tree-view
@import '~@/assets/style/fixed/tree-view.scss';
// 动画
@import '~@/assets/style/animate/vue-transition.scss';
@@ -0,0 +1,2 @@
@import './setting.scss';
@import '../theme.scss';
@@ -0,0 +1,64 @@
// 主题名称
$theme-name: 'element';
// 主题背景颜色
$theme-bg-color: #314255;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// 消息提示
$theme-message-info-background-color: #FFFFFF;
$theme-message-info-text-color: #202D3D;
$theme-message-info-border-color: #202D3D;
// container组件
$theme-container-background-color: rgba(#FFF, 1);
$theme-container-header-footer-background-color: #FFF;
$theme-container-border-inner: 1px solid #CFD7E5;
$theme-container-border-outer: 1px solid #011527;
$theme-multiple-page-control-color: #BFCBD9;
$theme-multiple-page-control-color-active: #46A0FC;
$theme-multiple-page-control-nav-prev-color: #BFCBD9;
$theme-multiple-page-control-nav-next-color: #BFCBD9;
$theme-multiple-page-control-border-color: #011527;
$theme-multiple-page-control-border-color-active: #FFFFFF;
$theme-multiple-page-control-background-color: #212D3D;
$theme-multiple-page-control-background-color-active: #FFFFFF;
// 顶栏和侧边栏中展开的菜单 hover 状态下
$theme-menu-item-color-hover: #BFCBD9;
$theme-menu-item-background-color-hover: #011527;
// 顶栏上的文字颜色
$theme-header-item-color: #BFCBD9;
$theme-header-item-background-color: transparent;
// 顶栏上的项目在 hover 时
$theme-header-item-color-hover: #BFCBD9;
$theme-header-item-background-color-hover: #011527;
// 顶栏上的项目在 focus 时
$theme-header-item-color-focus: #BFCBD9;
$theme-header-item-background-color-focus: #202D3D;
// 顶栏上的项目在 active 时
$theme-header-item-color-active: #46A0FC;
$theme-header-item-background-color-active: #202D3D;
// 侧边栏上的文字颜色
$theme-aside-item-color: #BFCBD9;
$theme-aside-item-background-color: transparent;
// 侧边栏上的项目在 hover 时
$theme-aside-item-color-hover: #BFCBD9;
$theme-aside-item-background-color-hover: #011527;
// 侧边栏上的项目在 focus 时
$theme-aside-item-color-focus: #BFCBD9;
$theme-aside-item-background-color-focus: #202D3D;
// 侧边栏上的项目在 active 时
$theme-aside-item-color-active: #46A0FC;
$theme-aside-item-background-color-active: #202D3D;
// 侧边栏菜单为空的时候显示的元素
$theme-aside-menu-empty-icon-color: #BFCBD9;
$theme-aside-menu-empty-text-color: #BFCBD9;
$theme-aside-menu-empty-background-color: #202D3D;
$theme-aside-menu-empty-icon-color-hover: #46A0FC;
$theme-aside-menu-empty-text-color-hover: #46A0FC;
$theme-aside-menu-empty-background-color-hover: #202D3D;
+1
View File
@@ -2,6 +2,7 @@
@import '~@/assets/style/theme/d2/index.scss';
@import '~@/assets/style/theme/chester/index.scss';
@import '~@/assets/style/theme/element/index.scss';
@import '~@/assets/style/theme/line/index.scss';
@import '~@/assets/style/theme/star/index.scss';
@import '~@/assets/style/theme/tomorrow-night-blue/index.scss';
+3 -3
View File
@@ -38,9 +38,9 @@ export default {
}
},
render (h) {
const slots = [ this.$slots.default ]
if (this.$slots.header) slots.push(h('template', { slot: 'header' }, [ this.$slots.header ]))
if (this.$slots.footer) slots.push(h('template', { slot: 'footer' }, [ this.$slots.footer ]))
const slots = [this.$slots.default]
if (this.$slots.header) slots.push(h('template', { slot: 'header' }, [this.$slots.header]))
if (this.$slots.footer) slots.push(h('template', { slot: 'footer' }, [this.$slots.footer]))
return h('div', {
ref: 'container',
class: 'container-component'
@@ -66,25 +66,10 @@ export default {
value: e.fullTitle,
...e
})) : this.results
}
},
methods: {
/**
* @description 过滤选项 这个方法在每次输入框的值发生变化时会触发
*/
querySearch (queryString, callback) {
var pool = this.pool
const results = this.query(queryString ? pool : [], queryString)
this.results = results
callback(results)
},
/**
* @description 指定的数据源中根据指定的查询字符串过滤数据
* @param {Object} pool 需要过滤的数据
* @param {String} queryString 查询字符串
*/
query (pool, queryString) {
return new Fuse(pool, {
// 根据 pool 更新 fuse 实例
fuse () {
return new Fuse(this.pool, {
shouldSort: true,
tokenize: true,
threshold: 0.6,
@@ -97,11 +82,16 @@ export default {
'path'
]
})
.search(queryString)
.map(e => ({
value: e.fullTitle,
...e
}))
}
},
methods: {
/**
* @description 过滤选项 这个方法在每次输入框的值发生变化时会触发
*/
querySearch (queryString, callback) {
const results = this.fuse.search(queryString).map(e => e.item)
this.results = results
callback(results)
},
/**
* @description 聚焦输入框
+1 -1
View File
@@ -9,7 +9,7 @@ const cookies = {}
* @param {Object} setting cookie setting
*/
cookies.set = function (name = 'default', value = '', cookieSetting = {}) {
let currentCookieSetting = {
const currentCookieSetting = {
expires: 1
}
Object.assign(currentCookieSetting, cookieSetting)
+2 -2
View File
@@ -6,8 +6,8 @@ export default {
if (process.env.VUE_APP_BUILD_MODE === 'PREVIEW') {
message = [
`当前语言:${this.$t('_name')} [ ${this.$i18n.locale} ]`,
`仅提供切换功能,没有配置具体的语言数据 `,
`文档参考:<a class="el-link el-link--primary is-underline" target="_blank" href="https://d2.pub/zh/doc/d2-admin/locales">《国际化 | D2Admin》</a>`
'仅提供切换功能,没有配置具体的语言数据 ',
'文档参考:<a class="el-link el-link--primary is-underline" target="_blank" href="https://d2.pub/zh/doc/d2-admin/locales">《国际化 | D2Admin》</a>'
].join('<br/>')
}
this.$notify({
-31
View File
@@ -1,31 +0,0 @@
const userDB = [
{ username: 'admin', password: 'admin', uuid: 'admin-uuid', name: 'Admin' },
{ username: 'editor', password: 'editor', uuid: 'editor-uuid', name: 'Editor' },
{ username: 'user1', password: 'user1', uuid: 'user1-uuid', name: 'User1' }
]
export default [
{
path: '/api/login',
method: 'post',
handle ({ body }) {
const user = userDB.find(e => e.username === body.username && e.password === body.password)
if (user) {
return {
code: 0,
msg: '登录成功',
data: {
...user,
token: '8dfhassad0asdjwoeiruty'
}
}
} else {
return {
code: 401,
msg: '用户名或密码错误',
data: {}
}
}
}
}
]
-73
View File
@@ -1,73 +0,0 @@
import Mock from 'mockjs'
import qs from 'qs'
import withCredentials from './patch/withCredentials'
/* 补丁 */
withCredentials(Mock)
/* Mock 默认配置 */
Mock.setup({ timeout: '200-300' })
/* 扩展 [生成器] */
const Generator = (prop, template) => {
const obj = {}
obj[prop] = [template]
return Mock.mock(obj)
}
/* 扩展 [循环] */
const Repeat = (num, itemTemplate) => Generator(`data|${num}`, itemTemplate).data
const CustomExtends = {
Generator,
Repeat,
Mock,
Random: Mock.Random
}
const extend = (prop, value) => {
CustomExtends[prop] = value
}
/* 装配配置组 */
const wired = ({ url, type, body }) => ({
method: type,
params: qs.parse(url.split('?').length > 1 ? url.split('?')[1] : ''),
body: JSON.parse(body),
url: qs.parse(url.split('?')[0]),
...CustomExtends
})
const setup = (path, method, handle) => {
Mock.mock(
RegExp(path),
method,
typeof handle === 'function' ? o => handle(wired(o)) : handle
)
}
const load = (collection) => {
collection.map(({ path, method, handle }) => {
if (method === '*') {
method = [
'get',
'head',
'post',
'put',
'delete',
'connect',
'options',
'trace',
'patch'
]
}
if (typeof method === 'string' && method.indexOf('|') > -1) method = method.split('|')
if (method instanceof Array) {
method.map(item => setup(path, item, handle))
} else {
setup(path, method, handle)
}
})
}
export default { setup, load, extend }
-14
View File
@@ -1,14 +0,0 @@
export default function (Mock) {
// http://cnine.me/note/FrontEnd/mock-lose-cookies-dbg.html
Mock.XHR.prototype.__send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function () {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
// https://github.com/d2-projects/d2-admin/issues/254
if (!this.custom.async) {
this.custom.xhr.responseType = this.responseType
}
}
this.__send.apply(this, arguments)
}
}
-10
View File
@@ -1,10 +0,0 @@
import d2Mock from './d2-mock'
const req = context => context.keys().map(context)
const options = req(require.context('./api/', true, /\.js$/))
.filter(e => e.default)
.map(e => e.default)
options.forEach(option => {
d2Mock.load(option)
})
+7
View File
@@ -0,0 +1,7 @@
import api from '@/api'
export default {
install (Vue) {
Vue.prototype.$api = api
}
}
+2
View File
@@ -11,6 +11,7 @@ import '@/assets/svg-icons'
import i18n from '@/i18n.js'
// 功能插件
import pluginApi from '@/plugin/api'
import pluginError from '@/plugin/error'
import pluginLog from '@/plugin/log'
import pluginOpen from '@/plugin/open'
@@ -33,6 +34,7 @@ export default {
i18n: (key, value) => i18n.t(key, value)
})
// 插件
Vue.use(pluginApi)
Vue.use(pluginError)
Vue.use(pluginLog)
Vue.use(pluginOpen)
+41 -15
View File
@@ -1,28 +1,54 @@
import { get, isObject } from 'lodash'
import store from '@/store'
import util from '@/libs/util'
export default {
install (Vue, options) {
Vue.config.errorHandler = function (error, instance, info) {
Vue.nextTick(() => {
// store 追加 log
store.dispatch('d2admin/log/push', {
message: `${info}: ${error.message}`,
type: 'danger',
meta: {
error,
instance
}
})
// 只在开发模式下打印 log
if (process.env.NODE_ENV === 'development') {
util.log.capsule('D2Admin', 'ErrorHandler', 'danger')
function writeLog (logType) {
return (error, vm, info = '') => {
Vue.nextTick(() => {
store.dispatch('d2admin/log/push', {
message: `${info}: ${isObject(error) ? error.message : error}`,
type: logType,
meta: {
error,
vm
}
})
if (process.env.NODE_ENV !== 'development') return
util.log.capsule('D2Admin', 'ErrorHandler', logType)
util.log.danger('>>>>>> 错误信息 >>>>>>')
console.log(info)
util.log.danger('>>>>>> Vue 实例 >>>>>>')
console.log(instance)
console.log(vm)
util.log.danger('>>>>>> Error >>>>>>')
console.log(error)
})
}
}
if (process.env.NODE_ENV === 'development') {
Vue.config.warnHandler = writeLog('warning')
}
Vue.config.errorHandler = writeLog('danger')
window.onunhandledrejection = error => {
store.dispatch('d2admin/log/push', {
message: get(error, 'reason.message', 'Unknown error'),
type: 'danger',
meta: {
error: get(error, 'reason'),
trace: get(error, 'reason.stack')
}
})
}
window.onerror = (event, source, lineno, colno, error) => {
store.dispatch('d2admin/log/push', {
message: get(error, 'message', 'Unknown error'),
type: 'danger',
meta: {
error,
trace: get(error, 'stack'),
source: `${source}@${lineno}:${colno}`,
event: event
}
})
}
+5
View File
@@ -42,6 +42,11 @@ export default {
name: 'chester',
preview: 'image/theme/chester/preview@2x.png'
},
{
title: 'Element',
name: 'element',
preview: 'image/theme/element/preview@2x.png'
},
{
title: '紫罗兰',
name: 'violet',
+2 -2
View File
@@ -1,7 +1,7 @@
import { Message, MessageBox } from 'element-ui'
import util from '@/libs/util.js'
import router from '@/router'
import { accountLogin } from '@api/sys.login'
import api from '@/api'
export default {
namespaced: true,
@@ -17,7 +17,7 @@ export default {
username = '',
password = ''
} = {}) {
const res = await accountLogin({ username, password })
const res = await api.SYS_USER_LOGIN({ username, password })
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
// 整个系统依赖这两个数据进行校验和存储
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
+7 -7
View File
@@ -93,7 +93,7 @@ export default {
*/
async openedUpdate ({ state, commit, dispatch }, { index, params, query, fullPath }) {
// 更新页面列表某一项
let page = state.opened[index]
const page = state.opened[index]
page.params = params || page.params
page.query = query || page.query
page.fullPath = fullPath || page.fullPath
@@ -109,7 +109,7 @@ export default {
*/
async openedSort ({ state, commit, dispatch }, { oldIndex, newIndex }) {
// 重排页面列表某一项
let page = state.opened[oldIndex]
const page = state.opened[oldIndex]
state.opened.splice(oldIndex, 1)
state.opened.splice(newIndex, 0, page)
// 持久化
@@ -123,7 +123,7 @@ export default {
*/
async add ({ state, commit, dispatch }, { tag, params, query, fullPath }) {
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
let newTag = tag
const newTag = tag
newTag.params = params || newTag.params
newTag.query = query || newTag.query
newTag.fullPath = fullPath || newTag.fullPath
@@ -142,7 +142,7 @@ export default {
*/
async open ({ state, commit, dispatch }, { name, params, query, fullPath, meta }) {
// 已经打开的页面
let opened = state.opened
const opened = state.opened
// 判断此页面是否已经打开 并且记录位置
let pageOpendIndex = 0
const pageOpend = opened.find((page, index) => {
@@ -160,7 +160,7 @@ export default {
})
} else {
// 页面以前没有打开过
let page = state.pool.find(t => t.name === name)
const page = state.pool.find(t => t.name === name)
// 如果这里没有找到 page 代表这个路由虽然在框架内 但是不参与标签页显示
if (page) {
await dispatch('add', {
@@ -189,7 +189,7 @@ export default {
// 如果关闭的页面就是当前显示的页面
if (isCurrent) {
// 去找一个新的页面
let len = state.opened.length
const len = state.opened.length
for (let i = 0; i < len; i++) {
if (state.opened[i].fullPath === tagName) {
newPage = i < len - 1 ? state.opened[i + 1] : state.opened[i - 1]
@@ -210,7 +210,7 @@ export default {
// 决定最后停留的页面
if (isCurrent) {
const { name = 'index', params = {}, query = {} } = newPage
let routerObj = { name, params, query }
const routerObj = { name, params, query }
await router.push(routerObj)
}
},
+2 -2
View File
@@ -39,11 +39,11 @@ export default {
const push = function (menu, titlePrefix = []) {
menu.forEach(m => {
if (m.children) {
push(m.children, [ ...titlePrefix, m.title ])
push(m.children, [...titlePrefix, m.title])
} else {
pool.push({
...m,
fullTitle: [ ...titlePrefix, m.title ].join(' / ')
fullTitle: [...titlePrefix, m.title].join(' / ')
})
}
})
+1 -1
View File
@@ -41,7 +41,7 @@ export default {
*/
async load ({ state, commit, dispatch }) {
// store 赋值
let activeName = await dispatch('d2admin/db/get', {
const activeName = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'theme.activeName',
defaultValue: state.list[0].name,
@@ -24,10 +24,10 @@ export default {
{ img: 'https://img.shields.io/github/last-commit/d2-projects/d2-admin.svg', link: linkD2Admin }
],
[
{ img: 'https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20https%3A%2F%2Fd2.pub/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fd2.pub%22` },
{ img: 'https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20https%3A%2F%2Fcdn.d2.pub/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fcdn.d2.pub%22` },
{ img: 'https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20Github/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+Github%22` },
{ img: 'https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status', link: 'https://app.netlify.com/sites/d2-admin-start-kit/deploys' }
{ img: 'https://github.com/d2-projects/d2-admin/workflows/Deploy%20https%3A%2F%2Fd2.pub/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fd2.pub%22` },
{ img: 'https://github.com/d2-projects/d2-admin/workflows/Deploy%20https%3A%2F%2Fcdn.d2.pub/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fcdn.d2.pub%22` },
{ img: 'https://github.com/d2-projects/d2-admin/workflows/Deploy%20Github/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+Github%22` },
{ img: 'https://api.netlify.com/api/v1/badges/a5dd4bbd-da3f-4145-98a9-8012577bdcf5/deploy-status', link: 'https://app.netlify.com/sites/d2-admin/deploys' }
],
[
{ img: 'https://visitor-count-badge.herokuapp.com/today.svg?repo_id=d2-projects.d2-admin', link: linkD2Admin },
-5
View File
@@ -36,11 +36,6 @@ export default {
D2Badge,
D2Help,
D2PageCover
},
data () {
return {
filename: __filename
}
}
}
</script>