用户,角色,图形,三方登录,

This commit is contained in:
liaoboping 2025-09-07 19:04:14 +08:00
parent 4965a21068
commit 1ce6f2140f
20 changed files with 530 additions and 896 deletions

View File

@ -2,5 +2,4 @@ NODE_ENV=development
VUE_APP_PREVIEW=true
VUE_APP_API_BASE_URL=/api
VUE_APP_API_URL=http://192.168.0.189:8099
VUE_APP_WEBSOCKET_URL
=ws://192.168.0.96:9001
VUE_APP_WEBSOCKET_URL=ws://192.168.0.96:9001

5
.env.production Normal file
View File

@ -0,0 +1,5 @@
NODE_ENV=production
VUE_APP_PREVIEW=true
VUE_APP_API_BASE_URL=/api
VUE_APP_API_URL=http://127.0.0.1:8099
VUE_APP_WEBSOCKET_URL=ws://127.0.0.1:9001

2
public/config.js vendored
View File

@ -2,4 +2,6 @@ window._CONFIG = {
ImageryProviderUrl: '/map/mapWX/{z}/{x}/{y}.jpg',
RoadProviderUrl: '',
TerrainProviderUrl: '/map/mapDem/',
thirdLoginUrl: 'http://127.0.0.1:8080/thirdLogin',
clientId: '0123456789',
}

BIN
src/assets/images/blank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -31,21 +31,21 @@ export default {
immediate: { type: Boolean, default: true },
allowEmpty: { type: [Boolean, Array], default: true },
},
data () {
data() {
return {
originData: [],
}
},
computed: {
_value: {
get () {
get() {
return this.value
},
set (val) {
set(val) {
this.$emit('input', val)
},
},
getListeners () {
getListeners() {
const listeners = {}
for (const key in this.$listeners) {
if (key === 'change') continue
@ -53,40 +53,40 @@ export default {
}
return listeners
},
selectMode () {
selectMode() {
return this.multiple ? 'multiple' : ''
},
options () {
options() {
return this.originData.map((o) => ({
value: o[this.valueKey],
label: o[this.labelKey],
disabled: o.disabled,
}))
},
getText () {
getText() {
if (this.multiple) {
return (this._value || []).map((v) => this.options.find((o) => o.value === v)?.label).join(',')
} else {
return this.options.find((o) => o.value === this._value)?.label
}
},
getOriginItem () {
getOriginItem() {
return (this._value || []).map((v) => this.originData.find((d) => d[this.valueKey] === v))
},
selectConf () {
selectConf() {
return {
...defaultSelectConfig,
...this.$attrs,
}
},
},
created () {
created() {
if (this.immediate) {
this.getOptions(true)
}
},
methods: {
async getOptions (visible) {
async getOptions(visible) {
if (!visible) return
try {
const res = await this.dataSource()
@ -100,10 +100,10 @@ export default {
this.originData = []
}
},
filterOption (input, selectVm) {
filterOption(input, selectVm) {
return selectVm.componentOptions.children[0]?.text.toLowerCase().includes(input.toLowerCase()) || false
},
handleChange (v) {
handleChange(v) {
this.$nextTick(() => {
this.$emit(
'change',
@ -117,7 +117,7 @@ export default {
)
})
},
commitAction (action, payload = true) {
commitAction(action, payload = true) {
switch (action) {
case 'get':
this.getOptions(payload)

View File

@ -48,11 +48,9 @@ export default {
},
},
getItem() {
console.log('----', this.treeData, this._value)
return this.findInTree(this.treeData, this._value)
},
getText() {
console.log('----', this.getItem)
return this.getItem && this.getItem[this.labelKey]
},
getListeners() {

View File

@ -0,0 +1,67 @@
<template>
<div class="image-to-base64">
<a-upload-dragger action="#" accept="image/*" :customRequest="customRequest" :showUploadList="false">
<p class="ant-upload-drag-icon">
<a-icon type="inbox" />
</p>
<p class="ant-upload-text">点击或者拖入图片以上传</p>
</a-upload-dragger>
<img class="image-preview" :src="imageSrc" alt="" />
</div>
</template>
<script>
import BlankPNG from '@/assets/images/blank.png'
export default {
props: {
value: { validator: (v) => !v || typeof v === 'string', required: true },
},
data() {
return {
blankImageSrc: BlankPNG,
}
},
computed: {
imageSrc: {
get() {
return this.value || this.blankImageSrc
},
set(v) {
this.$emit('input', v)
},
},
},
methods: {
customRequest({ file }) {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (e) => {
this.imageSrc = e.target.result
}
},
},
}
</script>
<style lang="less" scoped>
.image-to-base64 {
height: 201px;
display: flex;
> img {
flex: 1;
margin-left: 16px;
object-fit: contain;
background: #fafafa;
border: 1px dashed #d9d9d9;
border-radius: 2px;
}
}
::v-deep {
.ant-upload.ant-upload-drag {
.ant-upload {
padding: 32px 64px;
}
}
}
</style>

View File

@ -7,6 +7,7 @@ import AntQueryTable from './Layout/AntQueryTable.vue'
import AntOriginSelect from './Form/AntOriginSelect.vue'
import AntOriginTreeSelect from './Form/AntOriginTreeSelect.vue'
import DurationPicker from './Form/DurationPicker.vue'
import Image2Base64 from './Form/Image2Base64.vue'
import WangEditor from './WangEditor/Index.vue'
@ -28,6 +29,7 @@ export default {
Vue.component('AntOriginSelect', AntOriginSelect)
Vue.component('AntOriginTreeSelect', AntOriginTreeSelect)
Vue.component('DurationPicker', DurationPicker)
Vue.component('Image2Base64', Image2Base64)
Vue.component('WangEditor', WangEditor)

View File

@ -174,6 +174,11 @@ export const constantRouterMap = [
name: 'login',
component: () => import(/* webpackChunkName: "user" */ '@/views/user/Login'),
},
{
path: 'thirdLogin',
name: 'thirdLogin',
component: () => import(/* webpackChunkName: "user" */ '@/views/user/ThirdLogin'),
},
{
path: 'register',
name: 'register',

View File

@ -10,7 +10,7 @@ import store from './store'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const allowList = ['login', 'register', 'registerResult'] // no redirect allowList
const allowList = ['thirdLogin', 'login', 'register', 'registerResult'] // no redirect allowList
const loginRoutePath = '/user/login'
const defaultRoutePath = '/simulationScene'

View File

@ -76,7 +76,6 @@ const rootRouter = {
// })
// }
export const generatorDynamicRouter = token => {
console.log('generatorDynamicRoute111111r')
return new Promise((resolve, reject) => {
loginService
.getCurrentUserNav()
@ -113,7 +112,6 @@ export const generatorDynamicRouter = token => {
export const generator = (routerMap, parent) => {
return routerMap.map(item => {
const { title, show, hideChildren, hiddenHeaderContent, target, icon } = item || item.meta || {}
console.log('xxxxxxxddddd', `${(parent && parent.path) || ''}/${item.key}`)
const currentRouter = {
// 如果路由设置了 path则作为默认 path否则 路由地址 动态拼接生成如 /dashboard/workplace
path: item.path || `${(parent && parent.path) || ''}/${item.key}`,

View File

@ -53,7 +53,6 @@ const user = {
return new Promise((resolve, reject) => {
getInfo().then(response => {
const result = response.data
console.log('result', result)
if (result && result.id) {
localStorage.setItem('userId',result.id)
localStorage.setItem('uRealName', result.nickName)
@ -67,12 +66,9 @@ const user = {
per.actionList = action
}
})
console.log('xxxxxxxxxxxxxxxx')
// role.permissionList = role.permissions.map(permission => { return permission })
console.log('xxxxxxxxxxxxxxxx')
commit('SET_ROLES', result.roles)
commit('SET_INFO', result)
console.log('xxxxxxxxxxxxxxxx')
} else {
reject(new Error('getInfo: roles must be a non-null array !'))
}

View File

@ -0,0 +1,11 @@
export default () => {
const redirectUri = window.location.origin + window.location.pathname
window.location.href =
window._CONFIG.thirdLoginUrl +
'?response_type=code&active_type=user&state=' +
Math.random().toString(16).slice(2) +
'&client_id=' +
window._CONFIG.clientId +
'&redirect_uri=' +
btoa(encodeURI(redirectUri))
}

View File

@ -1,100 +0,0 @@
<template>
<div>
<div id="modal">
<a-modal :visible="visible" get-container="#modal" @cancel="close" :title="formTitile">
<a-form-model
ref="elForm"
:model="formData"
:rules="rules"
:label-col="{ span: 4, offset: 0 }"
:wrapper-col="{ span: 20, offset: 0 }"
layout="horizontal">
<a-form-model-item label="角色名称" prop="roleName">
<a-input v-model="formData.roleName" placeholder="请输入角色名称" :style="{width: '100%'}" allow-clear>
</a-input>
</a-form-model-item>
<a-form-model-item label="状态">
<a-radio-group v-model="formData.status">
<a-radio
v-for="(item, index) in statusOptions"
:key="index"
:value="item.value"
:disabled="item.disabled">{{ item.label }}</a-radio>
</a-radio-group>
</a-form-model-item>
</a-form-model>
<div slot="footer">
<a-button @click="close">关闭</a-button>
<a-button type="primary" @click="handelConfirm">确定</a-button>
</div>
</a-modal>
</div>
</div>
</template>
<script>
export default {
inheritAttrs: false,
components: {},
props: [],
data() {
return {
rules: {
roleName: [{
required: true,
message: '请输入角色名称',
trigger: 'blur'
}],
},
statusOptions: [{
'label': '正常',
'value': 0
}, {
'label': '停用',
'value': 1
}],
}
},
props: {
visible: {
type: Boolean,
default: false
},
formTitile: {
type: String,
default: ''
},
formData: {
type: Object,
default: () => {}
}
},
computed: {},
watch: {},
created() {},
mounted() {},
methods: {
onOpen() {
this.visible = true
},
close() {
this.$refs['elForm'].resetFields()
this.$emit('close')
},
handelConfirm() {
this.$refs['elForm'].validate(valid => {
if (!valid) {
this.vueMessage('warning','请查看是否有必填项漏填或错填')
} else {
}
})
},
vueMessage(type,msgText) {
this.$message[type](msgText)
}
}
}
</script>
<style>
</style>

View File

@ -1,253 +0,0 @@
<template>
<a-modal :visible="visible" @cancel="close" :width="908" :title="formTitile">
<a-form-model
ref="elForm"
:model="formData"
:rules="rules"
:label-col="{ span: 3, offset: 0 }"
:wrapper-col="{ span: 21, offset: 0 }"
layout="horizontal">
<a-form-model-item label="用户名" prop="userName">
<a-input v-model="formData.userName" placeholder="请输入用户名" :style="{width: '100%'}" allow-clear>
</a-input>
</a-form-model-item>
<a-form-model-item label="密码" prop="passWord" v-if="!formData.id">
<a-input-password
v-model="formData.passWord"
placeholder="请输入密码"
:style="{width: '100%'}"
allow-clear></a-input-password>
</a-form-model-item>
<a-form-model-item label="姓名" prop="realName">
<a-input v-model="formData.realName" placeholder="请输入姓名" :style="{width: '100%'}" allow-clear>
</a-input>
</a-form-model-item>
<!-- <a-form-model-item label="性别" prop="sex">
<a-radio-group v-model="formData.sex">
<a-radio
v-for="(item, index) in sexOptions"
:key="index"
:value="item.value"
:disabled="item.disabled">{{ item.label }}</a-radio>
</a-radio-group>
</a-form-model-item> -->
<!-- <a-form-model-item label="手机号码" prop="phoneNumber">
<a-input
v-model="formData.phoneNumber"
placeholder="请输入手机号码"
:style="{width: '100%'}"
allow-clear>
</a-input>
</a-form-model-item> -->
<!-- <a-form-model-item label="邮箱" prop="email">
<a-input v-model="formData.email" placeholder="请输入邮箱" :style="{width: '100%'}" allow-clear>
</a-input>
</a-form-model-item> -->
<a-form-model-item label="是否为管理员" prop="isAdmin">
<a-select
v-model="formData.isAdmin"
placeholder="请选择是否为管理员"
allow-clear
:style="{width: '100%'}">
<a-select-option :value="1"></a-select-option>
<a-select-option :value="0"></a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="第三方用户角色" prop="thirdRole">
<a-select
v-model="formData.thirdRole"
placeholder="请选择第三方用户角色"
allow-clear
:style="{width: '100%'}">
<a-select-option value="0">教员</a-select-option>
<a-select-option value="1">训练员</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="工作单位" prop="company">
<a-input v-model="formData.company" placeholder="请输入工作单位" :style="{width: '100%'}" allow-clear>
</a-input>
</a-form-model-item>
<a-form-model-item label="职务职称" prop="positional">
<a-input v-model="formData.positional" placeholder="请输入职务职称" :style="{width: '100%'}" allow-clear>
</a-input>
</a-form-model-item>
<a-form-model-item label="专业方向" prop="specialDirect">
<a-input v-model="formData.specialDirect" placeholder="请输入专业方向" :style="{width: '100%'}" allow-clear>
</a-input>
</a-form-model-item>
<!-- <a-form-model-item label="角色分配" prop="roles">
<a-select
v-model="formData.roles"
placeholder="请选择角色"
mode="multiple"
allow-clear
:style="{width: '100%'}">
<a-select-option
v-for="(item, index) in rolesOptions"
:key="index"
:value="item.id"
:disabled="item.disabled">{{ item.name }}</a-select-option>
</a-select>
</a-form-model-item> -->
<!-- <a-form-model-item label="头像" prop="avatar">
<a-upload
ref="avatar"
:file-list="avatarfileList"
:action="avatarAction"
:before-upload="avatarBeforeUpload"
list-type="picture-card">
<div>
<a-icon type="plus" />
<div class="ant-upload-text">点击上传</div>
</div>
</a-upload>
</a-form-model-item> -->
</a-form-model>
<div slot="footer">
<a-button @click="close">关闭</a-button>
<a-button type="primary" @click="handelConfirm">确定</a-button>
</div>
</a-modal>
</template>
<script>
import {
getAction,
getRoleList,
postAction,
postAction1,
putAction
} from '@/api/manage'
export default {
inheritAttrs: false,
components: {},
props: [],
data() {
return {
rules: {
userName: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
}],
password: [{
required: true,
message: '请输入密码',
trigger: 'blur'
}],
nickName: [],
sex: [],
phoneNumber: [
{
pattern: /^1[3-9]\d{9}$/,
message: '手机号格式错误',
trigger: 'blur'
}
],
email: [
{
pattern: /^[a-zA-Z0-9_-]+@([a-zA-Z0-9]+\.)+(com|cn|net|org)$/,
message: '邮箱格式错误',
trigger: 'blur'
}
],
roles: [],
},
avatarAction: 'https://jsonplaceholder.typicode.com/posts/',
avatarfileList: [],
sexOptions: [{
'label': '男',
'value': 0
}, {
'label': '女',
'value': 1
}],
rolesOptions: [],
}
},
props: {
visible: {
type: Boolean,
default: false
},
formTitile: {
type: String,
default: ''
},
formData: {
type: Object,
default: () => {}
}
},
computed: {},
watch: {
visible(val) {
if(val) {
this.getRoleList()
console.log(666)
}
}
},
created() {},
mounted() {},
methods: {
getRoleList() {
console.log(getAction,'geo')
getAction('/cssystem/role/getList',{}).then((res) => {
if(res.code == 200) {
this.rolesOptions = res.data
}
})
},
close() {
this.$refs['elForm'].resetFields()
this.$emit('close')
},
handelConfirm() {
this.$refs['elForm'].validate(valid => {
if (!valid) {
this.vueMessage('warning','请查看是否有必填项漏填或错填')
} else {
if(this.formData.id) {
//
putAction('/cssystem/user/edit',{
...this.formData
}).then((res) => {
if(res.code == 200) {
this.vueMessage('success', '修改成功')
this.close()
} else {
this.vueMessage('error', res.message)
}
})
} else {
//
postAction('/cssystem/user/create',{
...this.formData
}).then((res) => {
if(res.code == 200) {
this.vueMessage('success', '添加成功')
this.close()
} else {
this.vueMessage('error', res.message)
}
})
}
}
})
},
avatarBeforeUpload(file) {
const isRightSize = file.size / 1024 / 1024 < 2
if (!isRightSize) {
this.$message.error('文件大小超过 2MB')
}
return isRightSize
},
vueMessage(type,msgText) {
this.$message[type](msgText)
}
}
}
</script>
<style>
</style>

View File

@ -1,258 +1,108 @@
<template>
<page-header-wrapper>
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="48">
<a-col :xl="8" :lg="8">
<a-form-item label="关键字">
<a-input placeholder="请输入" v-model="queryParam.filter" />
</a-form-item>
</a-col>
<a-col :xl="8" :lg="8">
<span class="table-page-search-submitButtons">
<a-button type="primary" @click="getList">查询</a-button>
<a-button style="margin-left: 8px" @click="resetList">重置</a-button>
</span>
</a-col>
<a-col :xl="8" :lg="8">
<!-- <a-button type="primary" icon="plus" style="float: right" @click="handleAdd">新建</a-button> -->
</a-col>
</a-row>
</a-form>
</div>
<a-table
bordered
rowKey="id"
size="small"
:columns="columns"
:dataSource="loadData"
:pagination="paginationProps"
:loading="loadingTable"
@change="handleTableChange"
<a-card class="my-card">
<AntQueryTable
ref="role-table"
height="100%"
:queryConfig="queryConfig"
:tableConfig="tableConfig"
:pageConfig="pageConfig"
:showTool="showTool"
>
<span slot="index" slot-scope="text, record, index">{{ index + 1 }}</span>
<template slot="status" slot-scope="text">
<a-tag :color="text | statusColorFilter">{{ text | statusFilter }}</a-tag>
<template #toolbar-left>
<a-button icon="plus" type="primary" style="margin-right: 10px" @click="handleOpenAddModal">新增</a-button>
</template>
<span slot="createTime" slot-scope="text">{{ moment(text).format('YYYY-MM-DD') }}</span>
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)"> <a-icon type="form" /></a>
<!-- <a-divider type="vertical" />
<template v-if="record.status === 0">
<a href="javascript:;" @click="handleChangeStatus(record, 1)"><a-icon type="lock" /></a>
<a-divider type="vertical" />
</template>
<template v-if="record.status === 1">
<a href="javascript:;" @click="handleChangeStatus(record, 0)"><a-icon type="unlock" /></a>
<a-divider type="vertical" />
</template>
<a-popconfirm title="确定要删除该角色吗?" ok-text="确定" cancel-text="取消" @confirm="remove(record)">
<a href="javascript:;"><a-icon type="delete" /></a>
</a-popconfirm>
<a-divider type="vertical" />
<a href="javascript:;" @click="handlePermission(record)"><a-icon type="setting" /></a> -->
<a-divider type="vertical" />
<a href="javascript:;" @click="handlePermission(record)"><a-icon type="setting" /></a>
</span>
</a-table>
<role-form :visible="roleVisible" :id="currentRoleId" @cancel="roleFormHandleCancel" @ok="roleFormHandleOk" />
<role-permission-setting
:visible="rolePermissionVisible"
:id="currentRoleId"
@cancel="rolePermissionHandleCancel"
@ok="rolePermissionHandleOk"
/>
<template #tablecell-action="{ record }">
<a-button size="small" type="primary" @click="handleOpenEditModal(record)">编辑</a-button>
<a-button size="small" type="danger" @click="handleDelete(record)" style="margin-left: 15px">删除</a-button>
</template>
</AntQueryTable>
</a-card>
<AntFormModal
:visible.sync="AEModal.visible"
:title="AEModal.title"
:formItems="AEModal.formItems"
:formRules="AEModal.formRules"
:formData="AEModal.formData"
:onSubmit="handleSubmitAE"
@success="handleSubmitAESuccess"
>
</AntFormModal>
</page-header-wrapper>
</template>
<script>
import { changeStatus, getList, remove } from '@/api/system/role'
import moment from 'moment'
import RoleForm from './modules/RoleForm.vue'
import RolePermissionSetting from './modules/RolePermissionSetting.vue'
import { getAction } from '@/api/manage'
const STATUS = {
0: { title: '启用', color: '#87d068' },
1: { title: '禁用', color: '#f50' }
}
const columns = [
{
title: '#',
dataIndex: 'id',
align: 'center',
scopedSlots: { customRender: 'index' },
width: 80
},
{
title: '角色名称',
align: 'left',
dataIndex: 'name'
},
// {
// title: '',
// dataIndex: 'sortCode',
// align: 'center',
// width: 80
// },
// {
// title: '',
// dataIndex: 'deleteMark',
// align: 'center',
// width: 80
// },
// {
// title: '',
// dataIndex: 'status',
// align: 'center',
// scopedSlots: { customRender: 'status' },
// width: 80
// },
// {
// title: '',
// dataIndex: 'createTime',
// align: 'center',
// scopedSlots: { customRender: 'createTime' },
// width: 120
// },
{
title: '操作',
width: 80,
dataIndex: 'action',
align: 'center',
scopedSlots: { customRender: 'action' },
fixed: 'right'
}
]
import { deleteAction, getAction, postAction, putAction } from '@/api/manage'
export default {
name: 'RoleList',
components: { RoleForm, RolePermissionSetting },
data () {
name: 'Role',
data() {
return {
moment,
labelCol: {
xs: { span: 24 },
sm: { span: 5 }
queryConfig: {
items: [{ label: '关键字', prop: 'filter' }],
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
tableConfig: {
table: { rowKey: 'id' },
query: (params) => getAction('/system/role/getList', params),
columns: [
{ dataIndex: 'serial' },
{ title: '角色名称', dataIndex: 'roleName', width: 'auto' },
{ title: '排序', dataIndex: 'sortCode', width: 'auto' },
{ dataIndex: 'action' },
],
},
queryParam: {}, //
columns, //
loadData: [], // Promise
selectedRowKeys: [],
selectedRows: [],
loadingTable: false,
paginationProps: {
defaultPageSize: 20,
showSizeChanger: true,
showQuickJumper: true,
// pageSizeOptions: [10, 20, 50, 100, 500],
showTotal: total => {
return `${total}`
},
onShowSizeChange: (current, pageSize) => (this.pageSize = pageSize)
pageConfig: true,
showTool: true,
AEModal: {
visible: false,
title: '',
mode: '',
formItems: [
{ label: '角色名称', prop: 'roleName' },
{ label: '排序', prop: 'sortCode', options: { type: 'number' } },
],
formRules: {},
formData: {},
},
roleVisible: false,
currentRoleId: '',
rolePermissionVisible: false
}
},
filters: {
statusColorFilter (key) {
return STATUS[key].color
},
statusFilter (key) {
return STATUS[key].title
}
},
created () {
this.getList()
},
methods: {
resetList () {
this.queryParam = {}
this.getList()
handleOpenAddModal() {
this.AEModal.title = '新增角色'
this.AEModal.mode = 'add'
this.AEModal.formData = {}
this.AEModal.visible = true
},
getList (parameter = {}) {
const pageParams = { ...parameter, ...this.queryParam }
this.loadingTable = true
getAction('/cssystem/role/getList', pageParams).then(res => {
// const pagination = { ...this.paginationProps }
// pagination.total = res.data.totalCount
this.loadData = res.data
// this.paginationProps = pagination
this.loadingTable = false
})
handleOpenEditModal(record) {
this.AEModal.title = '编辑角色'
this.AEModal.mode = 'edit'
this.AEModal.formData = { ...record }
this.AEModal.visible = true
},
handleAdd () {
this.currentRoleId = ''
this.roleVisible = true
},
roleFormHandleCancel () {
this.roleVisible = false
},
roleFormHandleOk () {
this.roleVisible = false
this.getList()
},
remove (record) {
const params = { roleId: record.id }
remove(params).then(res => {
if (res) {
this.$message.success('删除角色成功')
this.getList()
} else {
this.$message.error('删除角色失败')
}
})
},
handleTableChange (pagination, filters, sorter) {
const parameter = {}
if (sorter) {
if (sorter.order === 'ascend') {
parameter.SortName = sorter.field + ' asc'
}
if (sorter.order === 'descend') {
parameter.SortName = sorter.field + ' desc'
}
handleSubmitAE(formData) {
if (this.AEModal.mode === 'add') {
return postAction('/system/role/add', formData)
}
if (this.AEModal.mode === 'edit') {
return putAction('/system/role/edit', formData)
}
parameter.pageSize = pagination.pageSize
parameter.pageNum = pagination.current
this.getList(parameter)
},
handleEdit (record) {
this.roleVisible = true
this.currentRoleId = record.id
console.log('record', record)
handleSubmitAESuccess() {
this.$refs['role-table'].commitAction('query')
},
handleChangeStatus (record, status) {
const params = { roleId: record.id, status: status }
changeStatus(params).then(res => {
if (res) {
this.$message.success('操作成功')
this.getList()
} else {
this.$message.error('操作失败')
}
})
async handleDelete(record) {
try {
await this.$confirm({ title: '温馨提示', content: '确定要删除该角色吗?' })
const res = await deleteAction('/system/role/remove?roleId=' + record.id)
this.$message.success(res.message)
this.$refs['role-table'].commitAction('query')
} catch (error) {
console.log(error)
}
},
handlePermission (record) {
this.currentRoleId = record.id
this.rolePermissionVisible = true
},
rolePermissionHandleCancel () {
this.rolePermissionVisible = false
},
rolePermissionHandleOk () {
this.rolePermissionVisible = false
}
}
},
}
</script>
<style lang="less" scoped></style>
<style lang="less" scoped>
</style>

View File

@ -1,292 +1,131 @@
<template>
<page-header-wrapper>
<a-card>
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="queryData">
<div class="shaixuan_float_left">
<a-form-item label="关键字">
<a-input placeholder="请输入" v-model="queryParam.filter" />
</a-form-item>
</div>
<div class="shaixuan_float_left">
<a-form-item>
<a-button type="primary" @click="queryData">查询</a-button>
<a-button style="margin-left: 8px" @click="resetQuery">重置</a-button>
</a-form-item>
</div>
<div style="clear: both"></div>
</a-form>
</div>
<div class="table-operator">
<a-button icon="plus" type="primary" style="margin-right: 10px" @click="handleAdd">新增</a-button>
<a-upload action="" :customRequest="handleImport" accept=".xlsx,.xls" :showUploadList="false">
<a-button icon="import" type="primary" style="margin-right: 10px">导入</a-button>
</a-upload>
</div>
<a-table :columns="tableColumn" :dataSource="tableData" :pagination="pagination" :scroll="{ x: true }" bordered>
<span slot="serial" slot-scope="text, record, index">
{{ index + 1 }}
</span>
<template slot="isAdmin" slot-scope="text">
<span v-if="text == 1"></span>
<span v-if="text == 0"></span>
<a-card class="my-card">
<AntQueryTable
ref="user-table"
height="100%"
:queryConfig="queryConfig"
:tableConfig="tableConfig"
:pageConfig="pageConfig"
:showTool="showTool"
>
<template #toolbar-left>
<a-button icon="plus" type="primary" style="margin-right: 10px" @click="handleOpenAddModal">新增</a-button>
</template>
<template slot="thirdRole" slot-scope="text">
<span v-if="text == 0">教员</span>
<span v-if="text == 1">训练员</span>
</template>
<template slot="optionColumn" slot-scope="text, record">
<a-button size="small" type="primary" @click="handleEdit(record)" style="margin-left: 15px">编辑</a-button>
<template #tablecell-action="{ record }">
<a-button size="small" type="primary" @click="handleOpenEditModal(record)">编辑</a-button>
<a-button size="small" type="danger" @click="handleDelete(record)" style="margin-left: 15px">删除</a-button>
<a-button size="small" type="primary" @click="handleResetpwdCpp(record)" style="margin-left: 15px">
重置密码
</a-button>
</template>
</a-table>
</AntQueryTable>
</a-card>
<AEuser :visible="aeuser.visible" :formTitile="aeuser.title" :formData="aeuser.formData" @close="closeAEuser" />
<AntFormModal
:visible.sync="AEModal.visible"
:title="AEModal.title"
:formItems="AEModal.formItems"
:formRules="AEModal.formRules"
:formData="AEModal.formData"
:onSubmit="handleSubmitAE"
@success="handleSubmitAESuccess"
>
</AntFormModal>
</page-header-wrapper>
</template>
<script>
import { deleteAction, getAction, postAction, putAction1 } from '@/api/manage'
import AEuser from './modules/AEuser.vue'
import { deleteAction, getAction, postAction, putAction } from '@/api/manage'
export default {
name: 'User',
components: {
AEuser,
},
data() {
return {
//
queryParam: {},
//
pagination: {
pageNum: 1,
pageSize: 10, //
showSizeChanger: true, //
pageSizeOptions: ['10', '20', '50', '100'], //
showTotal: (total) => `${total}`, //
onChange: this.onPageChange.bind(this), //
onShowSizeChange: this.onPageSizeChange.bind(this), // pageSize
total: 0, //
current: 0,
buildOptionText: (pageSizeOptions) => `${pageSizeOptions.value}条 / 页`,
queryConfig: {
items: [{ label: '关键字', prop: 'filter' }],
},
tableColumn: [
{
title: '序号',
scopedSlots: {
customRender: 'serial',
},
width: 60,
},
{
title: '账号',
key: 'userName',
dataIndex: 'userName',
scopedSlots: {
customRender: 'userName',
},
},
{
title: '姓名',
key: 'realName',
dataIndex: 'realName',
scopedSlots: {
customRender: 'realName',
},
},
{
title: '是否为管理员',
key: 'isAdmin',
dataIndex: 'isAdmin',
scopedSlots: {
customRender: 'isAdmin',
},
},
{
title: '第三方用户角色',
key: 'thirdRole',
dataIndex: 'thirdRole',
scopedSlots: {
customRender: 'thirdRole',
},
},
{
title: '工作单位',
key: 'company',
dataIndex: 'company',
scopedSlots: {
customRender: 'company',
},
},
{
title: '职务职称',
key: 'positional',
dataIndex: 'positional',
scopedSlots: {
customRender: 'positional',
},
},
{
title: '专业方向',
key: 'specialDirect',
dataIndex: 'specialDirect',
scopedSlots: {
customRender: 'specialDirect',
},
},
{
title: '创建人',
key: 'createUserId',
dataIndex: 'createUserId',
scopedSlots: {
customRender: 'createUserId',
},
},
{
title: '操作',
key: 'optionColumn',
dataIndex: 'optionColumn',
scopedSlots: {
customRender: 'optionColumn',
},
},
],
tableData: [],
aeuser: {
tableConfig: {
table: { rowKey: 'id' },
query: (params) => getAction('/system/user/list', params),
columns: [
{ dataIndex: 'serial' },
{ title: '账号', dataIndex: 'userName' },
{ title: '姓名', dataIndex: 'nickName' },
{ title: '角色', dataIndex: 'roleName', width: 'auto', minWidth: 160 },
{ title: '邮箱', dataIndex: 'email' },
{ title: '手机号', dataIndex: 'phoneNumber' },
{ title: '性别', dataIndex: 'sex', customRender: (text) => ['男', '女'][text] },
{ dataIndex: 'action' },
],
},
pageConfig: true,
showTool: true,
AEModal: {
visible: false,
title: '',
formData: {
userName: undefined,
passWord: undefined,
realName: undefined,
isAdmin: undefined,
deducType: undefined,
thirdRole: undefined,
company: undefined,
positional: undefined,
specialDirect: undefined,
// roles: [],
},
mode: '',
formItems: [
{ label: '账号', prop: 'userName' },
{ label: '姓名', prop: 'nickName' },
{
label: '角色',
prop: 'roles',
component: 'AntOriginSelect',
options: {
dataSource: () =>
getAction('system/role/getList', { pageSize: 999 }).then((res) => ({ data: res.data.data })),
labelKey: 'roleName',
multiple: true,
},
},
{ label: '邮箱', prop: 'email' },
{ label: '手机号', prop: 'phoneNumber' },
{
label: '性别',
prop: 'sex',
component: 'AntOriginSelect',
options: {
dataSource: () => ({
data: [
{ title: '男', id: 0 },
{ title: '女', id: 1 },
],
}),
},
},
],
formRules: {},
formData: {},
},
}
},
computed: {},
created() {},
mounted() {
this.getList()
},
methods: {
getList() {
const param = {
pageNum: this.pagination.current
? this.pagination.pageSize >= this.pagination.total
? 1
: this.pagination.current
: 1,
pageSize: this.pagination.pageSize,
...this.queryParam,
handleOpenAddModal() {
this.AEModal.title = '新增用户'
this.AEModal.mode = 'add'
this.AEModal.formData = {}
this.AEModal.visible = true
},
handleOpenEditModal(record) {
this.AEModal.title = '编辑用户'
this.AEModal.mode = 'edit'
this.AEModal.formData = { ...record }
this.AEModal.visible = true
},
handleSubmitAE(formData) {
if (this.AEModal.mode === 'add') {
return postAction('/system/user/create', formData)
}
getAction('/cssystem/user/getList', {
...param,
}).then((res) => {
this.tableData = res.data
// this.pagination.total = res.data.totalCount
// console.log(this.tableData, 'this.tableData')
})
},
// No
onPageChange(page, pageSize) {
this.pagination.current = page
this.getList(this.request_Url, this.parentId)
},
// Size
onPageSizeChange(current, pageSize) {
this.pagination.pageSize = pageSize
this.getList(this.request_Url, this.parentId)
},
queryData() {
this.getList(this.request_Url, this.parentId)
},
resetQuery() {
this.queryParam = {}
this.getList(this.request_Url, this.parentId)
},
handleAdd() {
this.aeuser.title = '新增'
this.aeuser.visible = true
},
handleEdit(record) {
this.aeuser.title = '编辑'
this.aeuser.formData = record
this.aeuser.visible = true
},
handleDelete(record) {
this.$confirm({
title: '温馨提示',
content: '确定要删除该用户吗?',
onOk: () => {
deleteAction('/cssystem/user/delete?id=' + record.id).then((res) => {
if (res.code == 200 && res.data) {
this.vueMessage('success', res.message)
this.getList()
} else {
this.vueMessage('error', res.message)
}
})
},
})
},
handleResetpwdCpp(record) {
this.$confirm({
title: '温馨提示',
content: '确定要重置密码吗?',
onOk: () => {
putAction1('/cssystem/user/reset?id=' + record.id).then((res) => {
if (res.code == 200 && res.data) {
this.vueMessage('success', res.message)
this.getList()
} else {
this.vueMessage('error', res.message)
}
})
},
})
},
vueMessage(type, msgText) {
this.$message[type](msgText)
},
closeAEuser() {
this.aeuser.title = ''
this.aeuser.visible = false
this.aeuser.formData = {
userName: undefined,
password: undefined,
nickName: undefined,
sex: 0,
phoneNumber: undefined,
email: undefined,
roles: [],
avatar: null,
if (this.AEModal.mode === 'edit') {
return putAction('/system/user/update', formData)
}
this.getList()
},
async handleImport(file) {
handleSubmitAESuccess() {
this.$refs['user-table'].commitAction('query')
},
async handleDelete(record) {
try {
const formData = new FormData()
formData.append('file', file)
await this.$http({
url: '/upload',
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
})
this.$message.success('导入成功')
this.getList()
await this.$confirm({ title: '温馨提示', content: '确定要删除该用户吗?' })
const res = await deleteAction('/system/user/delete?userId=' + record.id)
this.$message.success(res.message)
this.$refs['user-table'].commitAction('query')
} catch (error) {
console.log(error)
}

View File

@ -13,12 +13,21 @@
<template #toolbar-left>
<a-button type="primary" icon="plus" @click="handleOpenAddModal">新增</a-button>
</template>
<template #tablecell-iconBase64="{ text }">
<img :src="text" alt="" style="width: 100px; height: 70px; object-fit: contain" />
</template>
<template #tablecell-action="{ record }">
<a-button type="text-primary" icon="edit" @click="handleOpenEditModal(record)"></a-button>
<a-button type="text-danger" icon="delete" @click="handleDelete(record)"></a-button>
</template>
</AntQueryTable>
</a-card>
</Grid>
<AntFormModal
:visible.sync="AEModal.visible"
:title="AEModal.title"
width="900px"
:formConfig="{ labelCol: { span: 3 }, wrapperCol: { span: 19 } }"
:formItems="AEModal.formItems"
:formRules="AEModal.formRules"
:formData="AEModal.formData"
@ -29,6 +38,7 @@
</template>
<script>
import { deleteAction, getAction, postAction, putAction } from '@/api/manage'
export default {
name: 'Txsjk',
data() {
@ -36,36 +46,23 @@ export default {
txTable: {
queryConfig: false,
tableConfig: {
query: () => ({ data: [] }),
query: () => getAction('/icon/list'),
columns: [
{ dataIndex: 'serial' },
{ dataIndex: 'jbmc', title: '军标名称', width: 'auto' },
{ dataIndex: 'jblj', title: '军标路径', width: 'auto' },
{ dataIndex: 'tyf', title: '推演方', width: 'auto' },
{ dataIndex: 'iconName', title: '军标名称', width: 'auto', align: 'center' },
{ dataIndex: 'iconBase64', title: '军标路径', width: 'auto', align: 'center' },
{ dataIndex: 'action' },
],
},
pageConfig: false,
pageConfig: true,
showTool: true,
},
AEModal: {
visible: false,
title: '新增图形',
formItems: [
{ label: '军标名称', prop: 'jbmc' },
{ label: '军标路径', prop: 'jblj' },
{
label: '推演方',
prop: 'tyf',
component: 'AntOriginSelect',
options: {
dataSource: () => ({
data: [
{ title: '红方', id: '1' },
{ title: '蓝方', id: '2' },
],
}),
},
},
{ label: '军标名称', prop: 'iconName' },
{ label: '军标路径', prop: 'iconBase64', component: 'Image2Base64' },
],
formRules: {},
formData: {},
@ -77,9 +74,18 @@ export default {
this.AEModal.formData = {}
this.AEModal.visible = true
},
async handleOpenEditModal(record) {
try {
const res = await getAction(`/icon/${record.id}`)
this.AEModal.formData = res.data
this.AEModal.visible = true
} catch (error) {
console.log(error)
}
},
handleSubmitAE(formData) {
return this.$http({
url: '/tx/save',
url: '/icon/save',
method: 'post',
data: formData,
})
@ -87,6 +93,16 @@ export default {
handleSubmitAESuccess() {
this.$refs['tx-table'].commitAction('query')
},
async handleDelete(record) {
try {
await this.$confirm({ title: '温馨提示', content: '确定要删除该军标吗?' })
const res = await getAction('/icon/remove/' + record.id)
this.$message.success(res.message)
this.$refs['tx-table'].commitAction('query')
} catch (error) {
console.log(error)
}
},
},
}
</script>

View File

@ -290,7 +290,8 @@ export default {
})
})
*/
this.$router.push({ path: '/' })
// this.$router.push({ path: '/' })
this.$router.push({ path: '/user/thirdLogin?logged=1' })
// 1
setTimeout(() => {
this.$notification.success({

View File

@ -0,0 +1,198 @@
<template>
<div class="page-wrapper">
<img src="~@/assets/images/user/bg.jpg" alt="" />
<div class="login-wrapper">
<img
style="position: absolute; left: -10px; top: -8px; z-index: 1; width: 937px; height: 465px"
src="~@/assets/images/user/bg-login.png"
alt=""
/>
<div class="btn-wrapper">
<div v-if="!isTrainer" class="btn" @click="click">
<img src="~@/assets/images/user/btn-login.png" alt="" />
<span class="text">进入控制系统</span>
</div>
<div class="btn" @click="click">
<img src="~@/assets/images/user/btn-login.png" alt="" />
<span class="text">进入训练员系统</span>
</div>
</div>
</div>
<div v-if="userName" class="username">{{ userName }}欢迎你</div>
<div class="close-btn" @click="handleQuit()">退出</div>
</div>
</template>
<script>
import openThirdLogin from '@/utils/openThirdLogin'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import storage from 'store'
export default {
data() {
return {
userName: '',
roleName: '',
}
},
computed: {
roleNameArr() {
return this.roleName.split(',')
},
isAdmin() {
return this.roleNameArr.includes('管理员')
},
isInstructor() {
return !this.isAdmin && this.roleNameArr.includes('教员')
},
isTrainer() {
return !this.isInstructor && this.roleNameArr.includes('训练员')
},
},
async created() {
const searchParams = new URLSearchParams(window.location.search)
const searchLogged = searchParams.get('logged')
const localLogged = window.localStorage.getItem('logged')
if (searchLogged) {
window.localStorage.setItem('logged', searchLogged)
window.location.href = window.location.origin + window.location.pathname
return
} else if (localLogged) {
try {
const res = await this.$http({
url: '/auth/userInfo',
method: 'get',
})
this.userName = res.data.nickName || res.data.userName
this.roleName = res.data.roleName
} catch (error) {
console.log(error)
} finally {
window.localStorage.removeItem('logged')
}
return
}
const searchCode = searchParams.get('code')
const localCode = window.localStorage.getItem('code')
if (searchCode) {
window.localStorage.setItem('code', searchCode)
window.location.href = window.location.origin + window.location.pathname
} else if (localCode) {
try {
const tokenRes = await this.$http({
url: '/oauth2/thirdLogin',
method: 'get',
params: { code: localCode },
})
this.$store.commit('SET_TOKEN', '123')
storage.set(ACCESS_TOKEN, tokenRes.data.token, 7 * 24 * 60 * 60 * 1000)
this.$store.commit('SET_TOKEN', tokenRes.data.token)
const res = await this.$http({
url: '/auth/userInfo',
method: 'get',
})
this.userName = res.data.nickName || res.data.userName
this.roleName = res.data.roleName
} catch (error) {
console.log(error)
} finally {
window.localStorage.removeItem('code')
}
} else {
openThirdLogin()
}
},
methods: {
click() {
if (this.roleName === '管理员') {
}
if (this.roleName === '教员') {
}
if (this.roleName === '训练员') {
}
},
handleQuit () {
console.log(process.env)
},
},
}
</script>
<style lang="less" scoped>
.page-wrapper {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
}
.login-wrapper {
position: relative;
width: 917px;
height: 445px;
}
.btn-wrapper {
position: absolute;
right: 32px;
top: 220px;
z-index: 2;
transform: translateY(-50%);
}
.btn {
width: 329px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
font-weight: bolder;
font-size: 20px;
line-height: 1;
cursor: pointer;
position: relative;
}
.btn + .btn {
margin-top: 16px;
}
.text {
position: absolute;
z-index: 10;
}
img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.username {
position: absolute;
right: 130px;
top: 40px;
padding: 10px 20px;
font-size: 20px;
line-height: 1;
color: #ffffff;
}
.close-btn {
background-image: linear-gradient(0deg, #444444 0%, #848484 100%), linear-gradient(#13475d, #13475d);
background-blend-mode: normal, normal;
border: solid 1px #5f5f5f;
position: absolute;
right: 40px;
top: 40px;
padding: 10px 20px;
display: flex;
align-items: center;
justify-content: center;
color: #e81010;
font-size: 20px;
line-height: 1;
cursor: pointer;
}
</style>