提交 4ba741f8 authored 作者: 王鹏飞's avatar 王鹏飞

v2

上级 87dc63ee
......@@ -5,6 +5,7 @@ module.exports = {
extends: ['plugin:vue/essential', 'standard'],
rules: {
'vue/comment-directive': 'off',
'vue/multi-word-component-names': 'off',
'space-before-function-paren': 'off'
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"version": "0.0.0",
"scripts": {
"dev": "vite --mode dev",
"build": "cross-env BUILD_ENV=prod vite build && cross-env BUILD_ENV=prod npm run deploy",
"build:pre": "vite build",
"dev": "vite",
"build": "vite build && npm run deploy",
"build:pre": "vite build --mode pre",
"build:test": "vite build --mode test",
"preview": "vite preview",
"deploy": "node ./deploy.js",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src"
},
"dependencies": {
"axios": "^0.24.0",
"axios": "^0.26.0",
"element-ui": "^2.15.6",
"lodash": "^4.17.21",
"query-string": "^7.0.1",
"vue": "^2.6.14",
"vue-router": "^3.5.3",
"vuex": "^3.6.2"
},
"devDependencies": {
"@rollup/plugin-eslint": "^8.0.1",
"ali-oss": "^6.16.0",
"ali-oss": "^6.17.1",
"chalk": "^4.1.2",
"cross-env": "^7.0.3",
"eslint": "^7.32.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-vue": "^7.19.1",
"sass": "1.42.1",
"vite": "^2.7.3",
"vite-plugin-vue2": "^1.9.0",
"eslint-plugin-promise": "^5.2.0",
"eslint-plugin-vue": "^8.4.1",
"sass": "1.49.7",
"vite": "^2.8.3",
"vite-plugin-checker": "^0.4.2",
"vite-plugin-vue2": "^1.9.3",
"vue-template-compiler": "^2.6.14"
}
}
......@@ -34,3 +34,10 @@ export function uploadFile(data) {
export function getPermissions(params) {
return httpRequest.get('/api/permissions/api/v1/user/permissions', { params })
}
/**
* 获取所有项目列表
*/
export function getAllProjects(params) {
return httpRequest.get('/api/xedu/admin/v2/project/all', { params })
}
......@@ -46,6 +46,12 @@ export default {
name: '权限管理',
path: '/permissions',
icon: 'el-icon-coordinate'
},
{
tag: 'menu_project',
name: '项目管理',
path: '/projects',
icon: 'el-icon-folder-opened'
}
]
}
......@@ -83,17 +89,17 @@ export default {
<style lang="scss">
.app-aside {
position: sticky;
top: 0;
width: 200px;
z-index: 100;
background: #fff;
border-right: 1px solid rgba(0, 0, 0, 0.12);
overflow-x: hidden;
overflow-y: auto;
flex: 0 0 200px;
box-sizing: content-box;
}
.nav {
// position: fixed;
width: 200px;
margin: 20px 0;
.el-menu {
border-right: 0;
......
......@@ -4,14 +4,25 @@
<router-link to="/"><img src="https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo-white.svg" /></router-link>
</div>
<div class="app-header-right">
<el-select :value="activeProject.id" placeholder="所属项目" size="medium" clearable @change="handleChangeProject">
<el-option v-for="item in projects" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
<el-dropdown>
<div class="avatar">
<img :src="user.avatar || 'https://zws-imgs-pub.ezijing.com/pc/base/logo.png'" />
<img :src="user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/avatar.svg'" />
</div>
<el-dropdown-menu slot="dropdown">
<div class="user">
<div class="user-name">{{ user.realname || user.nickname }}</div>
<el-button round size="medium" class="btn-logout" @click="logout">退出登录</el-button>
<el-dropdown-menu slot="dropdown" style="width: 280px">
<div class="app-header-user">
<div class="app-header-user-avatar">
<img :src="user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/avatar.svg'" />
</div>
<div class="app-header-user-main">
<h3>{{ user.realname || user.nickname }}</h3>
<p>{{ user.email || user.mobile }}</p>
</div>
<div class="app-header-user-buttons">
<el-button size="medium" round @click="logout">退出登录</el-button>
</div>
</div>
</el-dropdown-menu>
</el-dropdown>
......@@ -24,7 +35,13 @@ export default {
name: 'AppHeader',
computed: {
user() {
return this.$store.state.user
return this.$store.state.user || {}
},
projects() {
return this.$store.state.projects || []
},
activeProject() {
return this.$store.state.activeProject || {}
}
},
methods: {
......@@ -32,6 +49,11 @@ export default {
this.$store.dispatch('logout').then(() => {
window.location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(window.location.href)}`
})
},
handleChangeProject(id) {
const project = this.projects.find(item => item.id === id) || {}
this.$store.commit('setActiveProjedct', project)
this.$router.push({ path: '/', query: { project_id: id } })
}
}
}
......@@ -39,6 +61,9 @@ export default {
<style lang="scss">
.app-header {
// position: sticky;
// top: 0;
// z-index: 1000;
padding: 0 20px;
display: flex;
align-items: center;
......@@ -53,12 +78,14 @@ export default {
}
.app-header-right {
display: flex;
align-items: center;
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
margin-left: 20px;
img {
width: 100%;
height: 100%;
......@@ -66,15 +93,50 @@ export default {
border-radius: 50%;
overflow: hidden;
}
&:hover {
background-color: rgba(60, 64, 67, 0.08);
}
}
}
.user {
.app-header-user {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 16px;
}
.user-name {
margin-bottom: 20px;
.app-header-user-avatar {
margin-bottom: 6px;
width: 80px;
height: 80px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.app-header-user-main {
h3 {
color: #202124;
font: 500 16px/22px Helvetica, Arial, sans-serif;
letter-spacing: 0.29px;
margin: 0;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
p {
color: #5f6368;
font: 400 14px/19px Helvetica, Arial, sans-serif;
letter-spacing: normal;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
}
.btn-logout {
width: 200px;
.app-header-user-buttons {
padding-top: 16px;
}
</style>
......@@ -2,7 +2,7 @@
<div class="app-layout">
<app-header></app-header>
<div class="app-layout-container">
<app-aside></app-aside>
<app-aside v-if="sidebar"></app-aside>
<app-main></app-main>
</div>
</div>
......@@ -15,6 +15,7 @@ import AppMain from './Main.vue'
export default {
name: 'AppLayout',
props: { sidebar: { type: Boolean, default: true } },
components: { AppHeader, AppAside, AppMain }
}
</script>
......
......@@ -5,7 +5,7 @@
<app-breadcrumb v-if="hasBreadcrumb"></app-breadcrumb>
</div>
<div class="app-main-container">
<router-view></router-view>
<router-view :key="$route.fullPath"></router-view>
</div>
</div>
</section>
......
......@@ -39,8 +39,8 @@ export default {
this.dispatch('ElFormItem', 'el.form.blur', editor.getContent())
},
dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root
var name = parent.$options.componentName
let parent = this.$parent || this.$root
let name = parent.$options.componentName
while (parent && (!name || name !== componentName)) {
parent = parent.$parent
......
......@@ -144,8 +144,8 @@ export default {
this.$emit('input', this.fileList)
},
dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root
var name = parent.$options.componentName
let parent = this.$parent || this.$root
let name = parent.$options.componentName
while (parent && (!name || name !== componentName)) {
parent = parent.$parent
......
......@@ -13,8 +13,6 @@ import './assets/theme/style.scss'
import AppCard from './components/base/AppCard.vue'
import AppList from './components/base/AppList.vue'
import beforeEnter from './utils/beforeEnter'
// 注册element-ui组件
Vue.use(ElementUI, { size: 'small' })
......@@ -25,8 +23,6 @@ Vue.component('app-list', AppList)
// 注册模块
modules({ router, store })
router.beforeEach(beforeEnter)
new Vue({
store,
router,
......
......@@ -4,33 +4,33 @@ import httpRequest from '@/utils/axios'
* 获取权限列表
*/
export function getPermissionList(params) {
return httpRequest.get('/api/xedu/admin/v1/permissions', { params })
return httpRequest.get('/api/xedu/admin/v2/permissions', { params })
}
/**
* 获取权限详情
*/
export function getPermission(params) {
return httpRequest.get(`/api/xedu/admin/v1/permission/${params.id}`, { params })
return httpRequest.get(`/api/xedu/admin/v2/permission/${params.id}`, { params })
}
/**
* 创建权限
*/
export function createPermission(data) {
return httpRequest.post('/api/xedu/admin/v1/permission', data)
return httpRequest.post('/api/xedu/admin/v2/permission', data)
}
/**
* 修改权限
*/
export function updatePermission(data) {
return httpRequest.put(`/api/xedu/admin/v1/permission/${data.id}`, data)
return httpRequest.put(`/api/xedu/admin/v2/permission/${data.id}`, data)
}
/**
* 删除权限
*/
export function deletePermission(data) {
return httpRequest.delete(`/api/xedu/admin/v1/permission/${data.id}`, data)
return httpRequest.delete(`/api/xedu/admin/v2/permission/${data.id}`, data)
}
......@@ -37,6 +37,7 @@
<script>
// lodash
import { createPermission, updatePermission } from '../api.js'
import { pick } from 'lodash'
export default {
props: {
isEdit: { type: Boolean, default: false },
......@@ -74,20 +75,21 @@ export default {
// 确定
onPrimary() {
this.$refs.form.validate().then(() => {
this.isEdit ? this.edit() : this.create()
const params = pick(this.form, ['id', 'parent_id', 'name', 'tag', 'type', 'system_tag', 'desc', 'effect_uris'])
this.isEdit ? this.edit(params) : this.create(params)
})
},
// 创建权限
create() {
createPermission(this.form).then(res => {
create(params) {
createPermission(params).then(res => {
this.$message.success('创建成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
})
},
// 编辑权限
edit() {
updatePermission(this.form).then(res => {
edit(params) {
updatePermission(params).then(res => {
this.$message.success('修改成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
......
import httpRequest from '@/utils/axios'
/**
* 获取项目列表
*/
export function getProjectList(params) {
return httpRequest.get('/api/xedu/admin/v2/projects', { params })
}
/**
* 获取项目详情
*/
export function getProject(params) {
return httpRequest.get(`/api/xedu/admin/v2/${params.id}/project`, { params })
}
/**
* 创建项目
*/
export function createProject(data) {
return httpRequest.post('/api/xedu/admin/v2/project', data)
}
/**
* 修改项目
*/
export function updateProject(data) {
return httpRequest.put(`/api/xedu/admin/v2/${data.id}/project`, data)
}
/**
* 修改项目状态
*/
export function updateProjectStatus(data) {
return httpRequest.post(`/api/xedu/admin/v2/project/${data.id}/status`, data)
}
/**
* 删除项目
*/
export function deleteProject(data) {
return httpRequest.delete(`/api/xedu/admin/v2/${data.id}/project`, data)
}
<template>
<el-dialog :title="title" :close-on-click-modal="false" v-bind="$attrs" v-on="$listeners" width="500px">
<el-form ref="form" :model="form" :rules="rules" label-position="top">
<el-form-item label="项目名称" prop="name">
<el-input v-model="form.name" clearable placeholder="请输入项目名称" />
</el-form-item>
<el-form-item label="项目标识" prop="tag">
<el-input v-model="form.tag" clearable placeholder="请输入项目标识" :readonly="isEdit" />
</el-form-item>
</el-form>
<template #footer>
<el-button type="text" @click="onCancel">取消</el-button>&nbsp;&nbsp;
<el-button type="primary" size="medium" @click="onPrimary">保存</el-button>
</template>
</el-dialog>
</template>
<script>
import { createProject, updateProject } from '../api.js'
import { pick } from 'lodash'
export default {
props: {
isEdit: { type: Boolean, default: false },
data: { type: Object, default: () => ({}) }
},
data() {
return {
form: { name: '', tag: '' },
rules: {
name: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
tag: [{ required: true, message: '请输入项目标识', trigger: 'blur' }]
}
}
},
watch: {
data: {
immediate: true,
handler(data) {
this.form = Object.assign({}, this.form, data)
}
}
},
computed: {
title() {
return this.isEdit ? '编辑项目' : '添加项目'
}
},
methods: {
// 取消
onCancel() {
this.$emit('update:visible', false)
},
// 确定
onPrimary() {
this.$refs.form.validate().then(() => {
const params = pick(this.form, ['id', 'name', 'tag'])
this.isEdit ? this.edit(params) : this.create(params)
})
},
// 添加项目
create(params) {
createProject(params).then(res => {
this.$message.success('添加成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
})
},
// 编辑项目
edit(params) {
updateProject(params).then(res => {
this.$message.success('编辑成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
})
}
}
}
</script>
<style></style>
const routes = [
{
path: '/projects',
component: () => import('@/components/layout/Index.vue'),
meta: { title: '项目管理' },
children: [{ path: '', component: () => import('./views/List.vue'), meta: { requireProjectId: false } }]
},
{
path: '/choose',
component: () => import('@/components/layout/Index.vue'),
props: { sidebar: false },
children: [{ path: '', component: () => import('./views/Choose.vue'), meta: { requireProjectId: false } }]
}
]
export { routes }
<template>
<div class="choose-list">
<el-card class="choose-item" v-for="item in projects" :key="item.id" @click.native="handleClick(item)">
<h2>{{ item.name }}</h2>
</el-card>
</div>
</template>
<script>
export default {
computed: {
projects() {
return this.$store.state.projects || []
}
},
methods: {
handleClick(item) {
this.$store.commit('setActiveProjedct', item)
this.$router.push({ path: '/', query: { project_id: item.id } })
}
}
}
</script>
<style lang="scss" scoped>
.choose-list {
display: flex;
flex-wrap: wrap;
}
.choose-item {
margin: 10px;
cursor: pointer;
}
</style>
<template>
<app-card>
<app-list v-bind="tableOptions" ref="list">
<template #header-aside>
<el-button type="primary" icon="el-icon-plus" @click="handleCreate">添加项目</el-button>
</template>
<template v-slot:table-role="{ row }">
<el-tag>{{ row.role_name }}</el-tag>
</template>
<template v-slot:table-status="{ row }">
<el-switch
v-model="row.status"
:active-value="1"
:inactive-value="2"
active-text="启用"
inactive-text="停用"
@change="handleStatus(row)"
></el-switch>
</template>
<template v-slot:table-x="{ row }">
<el-button type="primary" plain @click="handleUpdate(row)">编辑</el-button>
</template>
</app-list>
<!-- 创建/编辑 -->
<editform
:visible.sync="visible"
:isEdit="isEdit"
:data="editRaw"
@success="handleSuccess"
v-if="visible"
></editform>
</app-card>
</template>
<script>
// 接口
import { getProjectList, deleteProject, updateProjectStatus } from '../api'
export default {
components: {
Editform: () => import('../components/Editform.vue')
},
data() {
return {
visible: false,
isEdit: false, // 是否是编辑状态
editRaw: {} // 编辑的数据
}
},
computed: {
// 列表配置
tableOptions() {
return {
remote: {
httpRequest: getProjectList,
params: { id: '', name: '', tag: '' }
},
filters: [
{
type: 'input',
prop: 'id',
placeholder: '项目ID'
},
{
type: 'input',
prop: 'name',
placeholder: '项目名称'
},
{
type: 'input',
prop: 'tag',
placeholder: '项目标识'
}
],
columns: [
{ label: '项目ID', prop: 'id' },
{ label: '项目名称', prop: 'name' },
{ label: '项目标识', prop: 'tag' },
{
label: '创建人',
prop: 'created_by.realname',
computed({ row }) {
return row.created_by.realname || row.created_by.username
}
},
{ label: '创建时间', prop: 'created_at' },
{ label: '状态', prop: 'status', slots: 'table-status' },
{ label: '操作', slots: 'table-x', align: 'right', width: '80', fixed: 'right' }
]
}
}
},
methods: {
// 创建成功刷新列表
handleSuccess() {
this.$refs.list.refetch()
},
// 创建
handleCreate() {
this.isEdit = false
this.editRaw = {}
this.visible = true
},
// 编辑
handleUpdate(row) {
this.isEdit = true
this.editRaw = row
this.visible = true
},
// 删除
onRemove(row) {
this.$confirm('项目删除请谨慎操作,确定删除?', '删除项目', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.handleRemove(row)
})
},
// 删除
handleRemove(row) {
deleteProject({ id: row.id }).then(res => {
this.$message({ type: 'success', message: '删除成功' })
this.$refs.list.refetch()
})
},
// 状态改变
handleStatus(row) {
updateProjectStatus({ id: row.id, status: row.status }).then(res => {
this.$message({ type: 'success', message: '修改成功' })
})
}
}
}
</script>
......@@ -4,58 +4,58 @@ import httpRequest from '@/utils/axios'
* 获取角色列表
*/
export function getRoleList(params) {
return httpRequest.get('/api/xedu/admin/v1/roles', { params })
return httpRequest.get('/api/xedu/admin/v2/roles', { params })
}
/**
* 获取角色详情
*/
export function getRole(params) {
return httpRequest.get(`/api/xedu/admin/v1/role/${params.id}`, { params })
return httpRequest.get(`/api/xedu/admin/v2/role/${params.id}`, { params })
}
/**
* 创建角色
*/
export function createRole(data) {
return httpRequest.post('/api/xedu/admin/v1/role', data)
return httpRequest.post('/api/xedu/admin/v2/role', data)
}
/**
* 修改角色
*/
export function updateRole(data) {
return httpRequest.put(`/api/xedu/admin/v1/role/${data.id}`, data)
return httpRequest.put(`/api/xedu/admin/v2/role/${data.id}`, data)
}
/**
* 删除角色
*/
export function deleteRole(data) {
return httpRequest.delete(`/api/xedu/admin/v1/role/${data.id}`, data)
return httpRequest.delete(`/api/xedu/admin/v2/role/${data.id}`, data)
}
/**
* 获取权限列表
*/
export function getPermissionList(params) {
return httpRequest.get('/api/xedu/admin/v1/permissions', { params })
return httpRequest.get('/api/xedu/admin/v2/permissions', { params })
}
/**
* 获取角色所有权限
*/
export function getRolePermissions(params) {
return httpRequest.get(`/api/xedu/admin/v1/assign/${params.role_id}/permissions`, { params })
return httpRequest.get(`/api/xedu/admin/v2/assign/${params.role_id}/permissions`, { params })
}
/**
* 更新角色权限
*/
export function updateRolePermissions(data) {
return httpRequest.post('/api/xedu/admin/v1/assign/permissions-to-role', data)
return httpRequest.post('/api/xedu/admin/v2/assign/permissions-to-role', data)
}
/**
* 获取课程列表
*/
export function getCourseList(params) {
return httpRequest.get('/api/xedu/admin/v1/courses', { params })
return httpRequest.get(`/api/xedu/admin/v2/courses/${params.project_tag}`, { params })
}
......@@ -17,6 +17,7 @@
<script>
import { createRole, updateRole } from '../api.js'
import { pick } from 'lodash'
export default {
props: {
isEdit: { type: Boolean, default: false },
......@@ -52,20 +53,21 @@ export default {
// 确定
onPrimary() {
this.$refs.form.validate().then(() => {
this.isEdit ? this.edit() : this.create()
const params = pick(this.form, ['id', 'name', 'desc'])
this.isEdit ? this.edit(params) : this.create(params)
})
},
// 添加角色
create() {
createRole(this.form).then(res => {
create(params) {
createRole(params).then(res => {
this.$message.success('添加成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
})
},
// 编辑角色
edit() {
updateRole(this.form).then(res => {
edit(params) {
updateRole(params).then(res => {
this.$message.success('修改成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
......
......@@ -56,6 +56,11 @@ export default {
courses: [] // 所有课程
}
},
computed: {
activeProject() {
return this.$store.state.activeProject || {}
}
},
async beforeMount() {
// 获取课程列表
this.getCourses()
......@@ -73,7 +78,8 @@ export default {
getPermissions() {
return getPermissionList({ is_format: 1 }).then(res => {
// 移除空数组
this.permissions = JSON.parse(JSON.stringify(res.data).replaceAll(',"children":[]', ''))
const permissions = JSON.parse(JSON.stringify(res.data).replaceAll(',"children":[]', ''))
this.permissions = Array.isArray(permissions) ? permissions : []
this.options = this.permissions.reduce((result, item) => {
const index = result.findIndex(i => i.system_tag === item.system_tag)
if (index !== -1) {
......@@ -85,8 +91,8 @@ export default {
},
// 获取课程列表
getCourses() {
getCourseList().then(res => {
this.courses = res.data || []
getCourseList({ project_tag: this.activeProject.tag }).then(res => {
this.courses = res.data.items || []
})
},
// 获取当前角色的权限
......
......@@ -4,40 +4,47 @@ import httpRequest from '@/utils/axios'
* 获取机构列表
*/
export function getOrgList(params) {
return httpRequest.get('/api/xedu/admin/v1/organizations', { params })
return httpRequest.get('/api/xedu/admin/v2/organizations', { params })
}
/**
* 获取机构详情
*/
export function getOrg(params) {
return httpRequest.get(`/api/xedu/admin/v1/organization/${params.id}`, { params })
return httpRequest.get(`/api/xedu/admin/v2/organization/${params.id}`, { params })
}
/**
* 创建机构
*/
export function createOrg(data) {
return httpRequest.post('/api/xedu/admin/v1/organization', data)
return httpRequest.post('/api/xedu/admin/v2/organization', data)
}
/**
* 修改机构
*/
export function updateOrg(data) {
return httpRequest.put(`/api/xedu/admin/v1/organization/${data.id}`, data)
return httpRequest.put(`/api/xedu/admin/v2/organization/${data.id}`, data)
}
/**
* 删除机构
*/
export function deleteOrg(data) {
return httpRequest.delete(`/api/xedu/admin/v1/organization/${data.id}`, data)
return httpRequest.delete(`/api/xedu/admin/v2/organization/${data.id}`, data)
}
/**
* 获取角色列表
*/
export function getRoleList(params) {
return httpRequest.get('/api/xedu/admin/v1/roles', { params })
return httpRequest.get('/api/xedu/admin/v2/roles', { params })
}
/**
* 获取所有机构列表
*/
export function getAllOrgList(params) {
return httpRequest.get(`/api/xedu/admin/v2/organization/children/${params.project_id}`, { params })
}
......@@ -24,7 +24,18 @@
</el-select>
</el-form-item>
<el-form-item label="有效期" prop="validity_date">
<el-date-picker v-model="form.validity_date" type="date" value-format="yyyy-MM-dd" :picker-options="pickerOptions" placeholder="请选择该机构有效期" />
<el-date-picker
v-model="form.validity_date"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
placeholder="请选择该机构有效期"
/>
</el-form-item>
<el-form-item label="二级机构" prop="children_ids">
<el-select v-model="form.children_ids" multiple clearable placeholder="请选择二级机构" style="width: 100%">
<el-option v-for="item in orgList" :label="item.name" :value="item.id" :key="item.id" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
......@@ -35,7 +46,8 @@
</template>
<script>
import { createOrg, updateOrg, getRoleList } from '../api.js'
import { createOrg, updateOrg, getRoleList, getAllOrgList } from '../api.js'
import { pick } from 'lodash'
export default {
props: {
isEdit: { type: Boolean, default: false },
......@@ -50,7 +62,8 @@ export default {
contact_information: '',
content_permissions: '',
role_id: '',
validity_date: ''
validity_date: '',
children_ids: []
},
rules: {
login_mobile: [{ required: true, pattern: /^1[3-9]\d{9}$/, message: '请输入登录手机号', trigger: 'blur' }],
......@@ -58,7 +71,8 @@ export default {
contact_name: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
contact_information: [{ required: true, message: '请输入联系方式', trigger: 'blur' }],
content_permissions: [{ required: true, message: '请选择机构内容权限', trigger: 'change' }],
role_id: [{ required: true, message: '请选择机构角色', trigger: 'change' }]
role_id: [{ required: true, message: '请选择机构角色', trigger: 'change' }],
validity_date: [{ required: true, message: '请选择机构有效期', trigger: 'change' }]
},
contentPermission: [
{ label: '付费内容', value: 1 },
......@@ -69,31 +83,45 @@ export default {
return time.getTime() < Date.now()
}
},
roleList: [] // 角色列表
roleList: [], // 角色列表
orgList: [] // 机构列表
}
},
watch: {
data: {
immediate: true,
handler(data) {
this.form = Object.assign({}, this.form, data)
const ids = data.children ? data.children.map(item => item.id) : []
this.form = Object.assign({}, this.form, data, { children_ids: ids })
}
}
},
computed: {
title() {
return this.isEdit ? '编辑机构' : '添加机构'
},
activeProject() {
return this.$store.state.activeProject || {}
}
},
beforeMount() {
this.getRoleList()
this.getAllOrgList()
},
methods: {
// 获取角色列表
getRoleList() {
getRoleList({ limit: 100 }).then(res => {
this.roleList = res.data.data
})
},
// 获取所有机构列表
getAllOrgList() {
getAllOrgList({ project_id: this.activeProject.id, current_id: this.data.id }).then(res => {
const orgList = Array.isArray(res.data) ? res.data : []
this.orgList = orgList.concat(this.data.children || [])
})
},
// 取消
onCancel() {
this.$emit('update:visible', false)
......@@ -101,20 +129,30 @@ export default {
// 确定
onPrimary() {
this.$refs.form.validate().then(() => {
this.isEdit ? this.edit() : this.create()
const params = pick(this.form, [
'id',
'login_mobile',
'name',
'contact_name',
'contact_information',
'role_id',
'validity_date',
'children_ids'
])
this.isEdit ? this.edit(params) : this.create(params)
})
},
// 添加机构
create() {
createOrg(this.form).then(res => {
create(params) {
createOrg(params).then(res => {
this.$message.success('添加成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
})
},
// 编辑机构
edit() {
updateOrg(this.form).then(res => {
edit(params) {
updateOrg(params).then(res => {
this.$message.success('编辑成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
......
<template>
<app-card :title="detail.name" v-loading="loading">
<template #header-aside>
<el-button type="primary" @click="visible = true">编辑</el-button>
</template>
<el-descriptions :column="1" size="medium">
<!-- <el-descriptions-item label="机构名称">{{ detail.name }}</el-descriptions-item> -->
<el-descriptions-item label="联系人">{{ detail.contact_name }}</el-descriptions-item>
<el-descriptions-item label="联系方式">{{ detail.contact_information }}</el-descriptions-item>
<!-- <el-descriptions-item label="机构内容权限">
<div>
<app-card :title="detail.name" v-loading="loading">
<template #header-aside>
<el-button type="primary" @click="visible = true">编辑</el-button>
</template>
<el-descriptions :column="1" size="medium">
<!-- <el-descriptions-item label="机构名称">{{ detail.name }}</el-descriptions-item> -->
<el-descriptions-item label="联系人">{{ detail.contact_name }}</el-descriptions-item>
<el-descriptions-item label="联系方式">{{ detail.contact_information }}</el-descriptions-item>
<!-- <el-descriptions-item label="机构内容权限">
<el-tag>{{ contentPermissionName(detail.content_permissions) }}</el-tag>
</el-descriptions-item> -->
<el-descriptions-item label="机构角色">
<el-tag>{{ detail.role_name }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="有效期">
{{ detail.validity_date }}
<el-tag v-if="detail.is_valid">未过期</el-tag>
<el-tag type="danger" v-else>已过期</el-tag>
</el-descriptions-item>
</el-descriptions>
<!-- 编辑 -->
<editform
:visible.sync="visible"
:isEdit="true"
:data="detail"
@success="handleUpdateSuccess"
v-if="visible"
></editform>
</app-card>
<el-descriptions-item label="机构角色">
<el-tag>{{ detail.role_name }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="有效期">
{{ detail.validity_date }}
<el-tag v-if="detail.is_valid">未过期</el-tag>
<el-tag type="danger" v-else>已过期</el-tag>
</el-descriptions-item>
</el-descriptions>
<!-- 编辑 -->
<editform
:visible.sync="visible"
:isEdit="true"
:data="detail"
@success="handleUpdateSuccess"
v-if="visible"
></editform>
</app-card>
<app-card title="二级机构">
<app-list v-bind="tableOptions" ref="list">
<template v-slot:table-status="{ row }">
<el-tag v-if="row.is_valid">未过期</el-tag>
<el-tag type="danger" v-else>已过期</el-tag>
</template>
<template v-slot:table-x="{ row }">
<router-link :to="{ path: '/school/view', query: { id: row.id } }">
<el-button plain>查看</el-button>
</router-link>
</template>
</app-list>
</app-card>
</div>
</template>
<script>
......@@ -47,6 +62,29 @@ export default {
computed: {
id() {
return this.$route.query.id
},
tableOptions() {
return {
columns: [
{ label: '机构ID', prop: 'id' },
{ label: '机构名称', prop: 'name' },
{
label: '创建人',
prop: 'created_by.realname',
computed({ row }) {
return row.created_by.realname || row.created_by.username
}
},
{ label: '创建时间', prop: 'created_at' },
{
label: '状态',
prop: 'is_valid',
slots: 'table-status'
},
{ label: '操作', slots: 'table-x', align: 'right', width: '160', fixed: 'right' }
],
data: this.detail.children || []
}
}
},
beforeMount() {
......
......@@ -12,15 +12,21 @@
<el-tag type="danger" v-else>已过期</el-tag>
</template>
<template v-slot:table-x="{ row }">
<router-link :to="{ path: 'school/view', query: { id: row.id } }" target="_blank" style="margin-right: 10px">
<router-link :to="{ path: '/school/view', query: { id: row.id } }" target="_blank" style="margin-right: 10px">
<el-button plain>查看</el-button>
</router-link>
<el-button type="primary" plain @click="handleUpdate(row)">编辑</el-button>
<el-button type="danger" plain @click="onRemove(row)">删除</el-button>
<!-- <el-button type="danger" plain @click="onRemove(row)">删除</el-button> -->
</template>
</app-list>
<!-- 创建/编辑 -->
<editform :visible.sync="visible" :isEdit="isEdit" :data="editRaw" @success="handleSuccess" v-if="visible"></editform>
<editform
:visible.sync="visible"
:isEdit="isEdit"
:data="editRaw"
@success="handleSuccess"
v-if="visible"
></editform>
</app-card>
</template>
......@@ -103,7 +109,7 @@ export default {
prop: 'is_valid',
slots: 'table-status'
},
{ label: '操作', slots: 'table-x', align: 'right', width: '220', fixed: 'right' }
{ label: '操作', slots: 'table-x', align: 'right', width: '160', fixed: 'right' }
]
}
}
......
import Vue from 'vue'
import VueRouter from 'vue-router'
import beforeEnter from '@/utils/beforeEnter'
Vue.use(VueRouter)
......@@ -10,4 +11,6 @@ const router = new VueRouter({
routes
})
router.beforeEach(beforeEnter)
export default router
import Vue from 'vue'
import Vuex from 'vuex'
import { getUser, logout, getPermissions } from '@/api/base'
import { getUser, logout, getPermissions, getAllProjects } from '@/api/base'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
user: {},
permissions: [] // 权限列表
permissions: [], // 权限列表
projects: [], // 项目列表
activeProject: {} // 当前激活的项目
},
mutations: {
setUser(state, user) {
......@@ -15,9 +17,31 @@ const store = new Vuex.Store({
},
setPermissions(state, permissions) {
state.permissions = permissions
},
setProjects(state, projects) {
state.projects = projects
},
setActiveProjedct(state, project = {}) {
state.activeProject = project
localStorage.setItem('project_id', project.id || '')
}
},
actions: {
// 获取所有项目列表
getAllProjects({ commit }) {
getAllProjects().then(res => {
const projects = res.data
const localProjectId = localStorage.getItem('project_id')
// 当前激活的项目
if (localProjectId) {
const activeProject = projects.find(item => item.id === localProjectId) || {}
commit('setActiveProjedct', activeProject)
}
// 所有项目列表
commit('setProjects', projects)
})
},
// 获取权限列表
getPermissions({ commit }) {
getPermissions({ type: 2 }).then(res => {
if (res.data && res.data.items) {
......@@ -57,6 +81,15 @@ const store = new Vuex.Store({
}
}
})
const localProjectId = localStorage.getItem('project_id')
// 当前激活的项目
if (localProjectId) {
store.commit('setActiveProjedct', { id: localProjectId })
}
// 初始化获取权限列表
store.dispatch('getPermissions')
// 初始化获取项目列表
store.dispatch('getAllProjects')
export default store
......@@ -2,7 +2,7 @@ import axios from 'axios'
import queryString from 'query-string'
import { Message } from 'element-ui'
import router from '../router'
import store from '../store'
const httpRequest = axios.create({
timeout: 60000,
withCredentials: true
......@@ -12,6 +12,9 @@ const httpRequest = axios.create({
// 请求拦截
httpRequest.interceptors.request.use(
function (config) {
// 设置项目
config.params = Object.assign({ project_id: store.state.activeProject.id }, config.params)
config.data = Object.assign({ project_id: store.state.activeProject.id }, config.data)
// 权限接口单独签名
// https://gitlab.ezijing.com/root/api-documents/-/blob/master/ezijing_permissions/%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81.md
if (/^\/api\/permissions/.test(config.url)) {
......
......@@ -31,5 +31,11 @@ export default async function (to, from, next) {
return
}
// 选择项目
const hasProjectId = !!store.state.activeProject.id
if ((!Object.hasOwnProperty.call(to.meta, 'requireProjectId') || to.meta.requireProjectId) && !hasProjectId) {
next('/choose')
return
}
next()
}
......@@ -2,31 +2,39 @@ import fs from 'fs'
import path from 'path'
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
import eslint from '@rollup/plugin-eslint'
export default defineConfig({
base: process.env.BUILD_ENV === 'prod' ? 'https://webapp-pub.ezijing.com/website/prod/x-school-admin/' : '/',
plugins: [eslint({ include: '**/*.+(vue|js|jsx|ts|tsx)' }), createVuePlugin()],
server: {
open: true,
host: 'dev.ezijing.com',
https: {
key: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.key')),
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
import checker from 'vite-plugin-checker'
export default defineConfig(({ mode }) => {
return {
base: mode === 'prod' ? 'https://webapp-pub.ezijing.com/website/prod/x-school-admin/' : '/',
plugins: [
checker({
eslint: { lintCommand: 'eslint "./src/**/*.{vue,js,jsx,ts,tsx}"' }
}),
createVuePlugin()
],
server: {
open: true,
host: 'dev.ezijing.com',
https: {
key: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.key')),
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
},
proxy: {
'/api': 'https://x-school-admin.ezijing.com'
}
},
resolve: {
alias: [
{
find: '@',
replacement: path.resolve(__dirname, 'src')
}
]
},
proxy: {
'/api': 'https://x-school-admin2.ezijing.com'
css: {
// 禁用SASS警告提醒
preprocessorOptions: { scss: { quietDeps: true, charset: false } }
}
},
resolve: {
alias: [
{
find: '@',
replacement: path.resolve(__dirname, 'src')
}
]
},
css: {
// 禁用SASS警告提醒
preprocessorOptions: { scss: { quietDeps: true } }
}
})
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论