feat: 完成用户表单的CURD基本操作

This commit is contained in:
gis-xh 2022-07-29 03:07:13 +08:00
parent d12c14f26f
commit 0736cdee4a
11 changed files with 489 additions and 6 deletions

View File

@ -1,5 +1,5 @@
{
"name": "myVue_3.2",
"name": "my-vue-3.2",
"version": "0.1.0",
"private": true,
"scripts": {
@ -11,7 +11,9 @@
"dependencies": {
"@element-plus/icons-vue": "^2.0.6",
"axios": "^0.27.2",
"cesium": "^1.95.0",
"core-js": "^3.8.3",
"dayjs": "^1.11.4",
"driver.js": "^0.9.8",
"element-plus": "1.3.0-beta.5",
"lint-staged": "13.0.3",

View File

@ -4,4 +4,9 @@
<script setup></script>
<style lang="scss"></style>
<style lang="scss">
// .el-message
.el-message-box__status {
position: absolute !important;
}
</style>

38
src/api/user.js Normal file
View File

@ -0,0 +1,38 @@
import request from './request'
export const getUser = (params) => {
return request({
url: '/users',
params
})
}
export const changeUserState = (uid, type) => {
return request({
url: `users/${uid}/state/${type}`,
method: 'put'
})
}
export const addUser = (data) => {
return request({
url: 'users',
method: 'post',
data
})
}
export const editUser = (data) => {
return request({
url: `users/${data.id}`,
method: 'put',
data
})
}
export const deleteUser = (id) => {
return request({
url: `users/${id}`,
method: 'delete'
})
}

View File

@ -8,6 +8,9 @@ import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import '@/router/premission'
import i18n from './i18n/i18nIndex'
import * as Cesium from '../node_modules/cesium/Source/Cesium'
import '../node_modules/cesium/Source/Widgets/widgets.css'
import filters from './utils/filters'
const app = createApp(App)
SvgIcon(app)
@ -17,3 +20,11 @@ app.use(store).use(router).use(i18n).mount('#app')
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 全局引入时间过滤设置
filters(app)
// 全局引入 Cesium
app.config.globalProperties.$Cesium = Cesium
Cesium.Ion.defaultAccessToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIzZjhhMGMyNy0xOGJhLTQyNDItODdjMC1kYzdhZjU5M2RlNTYiLCJpZCI6MTAyNzI1LCJpYXQiOjE2NTg5MTQwMTV9.V8wOhhVUW0PvDJq7KIlzieoWhtZcbWXeYnrY2iZoJl8'

22
src/utils/filters.js Normal file
View File

@ -0,0 +1,22 @@
const dayjs = require('dayjs')
//
const filterTimes = (val, format = 'YYYY-MM-DD') => {
if (!isNull(val)) {
val = parseInt(val) * 1000
return dayjs(val).format(format)
} else {
return '--'
}
}
// 判断外来的值是否为空
export const isNull = (date) => {
if (!date) return true
if (JSON.stringify(date) === '{}') return true
if (JSON.stringify(date) === '[]') return true
}
export default (app) => {
app.config.globalProperties.$filters = {
filterTimes
}
}

View File

@ -0,0 +1,43 @@
<template>
<div class="cesiumContainer"></div>
</template>
<script setup>
import {
Viewer,
createWorldTerrain,
createOsmBuildings,
Cartesian3,
Math
} from 'cesium'
// Your access token can be found at: https://cesium.com/ion/tokens.
// This is the default access token
// Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
const viewer = new Viewer('cesiumContainer', {
terrainProvider: createWorldTerrain()
})
// Add Cesium OSM Buildings, a global 3D buildings layer.
viewer.scene.primitives.add(createOsmBuildings())
// Fly the camera to San Francisco at the given longitude, latitude, and height.
viewer.camera.flyTo({
destination: Cartesian3.fromDegrees(-122.4175, 37.655, 400),
orientation: {
heading: Math.toRadians(0.0),
pitch: Math.toRadians(-15.0)
}
})
</script>
<style lang="scss">
.cesiumContainer {
width: auto;
height: auto;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>

View File

@ -1,7 +1,12 @@
<template>
<div>reports</div>
<!-- <my-map /> -->
<!-- <Testmap /> -->
</template>
<script setup></script>
<script setup>
// import myMap from './myMap.vue'
// import Testmap from './cesium/testMap.vue'
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,144 @@
<template>
<el-dialog
:model-value="dialogVisible"
:title="dialogTitle"
width="30%"
@close="handleClose"
>
<el-form
ref="ruleFormRef"
:model="ruleForm"
:rules="rules"
label-width="120px"
status-icon
>
<el-form-item label="用户名" prop="username">
<el-input v-model="ruleForm.username" />
</el-form-item>
<el-form-item
label="密码"
prop="password"
v-if="dialogTitle === '添加用户'"
>
<el-input v-model="ruleForm.password" type="password" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="ruleForm.email" />
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="ruleForm.mobile" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { defineEmits, ref, defineProps, watch } from 'vue'
// import { defineEmits, ref, defineProps } from 'vue'
import { addUser, editUser } from '@/api/user'
import i18n from '@/i18n/i18nIndex'
import { ElMessage } from 'element-plus'
const props = defineProps({
dialogTitle: {
type: String,
default: '',
required: true
},
dialogTableValue: {
type: Object,
default: () => {}
}
})
const ruleFormRef = ref(null)
const ruleForm = ref({
username: '',
password: '',
email: '',
mobile: ''
})
const rules = ref({
username: [
{
required: true,
message: '请输入用户名。',
trigger: 'blur'
}
],
password: [
{
required: true,
message: '请输入用户密码。',
trigger: 'blur'
}
],
email: [
{
required: true,
message: '请输入用户邮箱。',
trigger: 'blur'
},
{
type: 'email',
message: '请输入正确的邮箱地址。',
trigger: ['blur', 'change']
}
],
mobile: [
{
required: true,
message: '请输入用户手机号。',
trigger: 'blur'
}
]
})
//
watch(
() => props.dialogTableValue,
() => {
// console.log(props.dialogTableValue)
ruleForm.value = props.dialogTableValue
},
{ deep: true, immediate: true }
)
const emits = defineEmits(['update:modelValue', 'initUserList'])
const handleClose = () => {
emits('update:modelValue', false)
}
//
const handleConfirm = () => {
ruleFormRef.value.validate(async (valid) => {
if (valid) {
props.dialogTitle === '添加用户'
? await addUser(ruleForm.value)
: await editUser(ruleForm.value)
ElMessage({
// showClose: true,
message: i18n.global.t('message.updeteSuccess'),
type: 'success'
})
emits('initUserList')
handleClose()
} else {
ElMessage({
message: '请检查输入内容。',
type: 'error'
})
return false
}
})
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,35 @@
export const options = [
// {
// label: 'id',
// prop: 'id'
// },
{
label: 'username',
prop: 'username'
},
{
label: 'email',
prop: 'email'
},
{
label: 'mobile',
prop: 'mobile'
},
{
label: 'role_name',
prop: 'role_name'
},
{
label: 'mg_state',
prop: 'mg_state'
},
{
label: 'create_time',
prop: 'create_time'
},
{
label: 'action',
prop: 'action',
width: 200
}
]

View File

@ -1,7 +1,175 @@
<template>
<div>users</div>
<el-card>
<!-- 顶部搜索 -->
<el-row :gutter="20" class="header">
<el-col :span="7">
<el-input
:placeholder="$t('table.placeholder')"
clearable
v-model="queryFrom.query"
>
</el-input>
</el-col>
<el-button type="primary" :icon="Search" @click="initGetUsersList">
{{ $t('table.search') }}
</el-button>
<el-button type="primary" @click="handleDialogValue()">
{{ $t('table.adduser') }}
</el-button>
</el-row>
<!-- 表格内容 -->
<el-table :data="tableData" stripe style="width: 100%">
<el-table-column
:width="item.width"
:prop="item.prop"
:label="$t(`table.${item.label}`)"
v-for="(item, index) in options"
:key="index"
>
<template v-slot="{ row }" v-if="item.prop === 'mg_state'">
<el-switch v-model="row.mg_state" @change="changeState(row)" />
</template>
<template v-slot="{ row }" v-else-if="item.prop === 'create_time'">
{{ $filters.filterTimes(row.create_time) }}
</template>
<template #default="{ row }" v-else-if="item.prop === 'action'">
<el-button
type="primary"
:icon="Edit"
circle
@click="handleDialogValue(row)"
/>
<el-button
type="danger"
:icon="Delete"
circle
@click="delUser(row)"
/>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="queryFrom.pagenum"
v-model:page-size="queryFrom.pagesize"
:page-sizes="[2, 5, 10, 15]"
:small="small"
:disabled="disabled"
:background="background"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
class="footer"
/>
</el-card>
<Dialog
v-model="dialogVisible"
:dialogTitle="dialogTitle"
v-if="dialogVisible"
@initUserList="initGetUsersList"
:dialogTableValue="dialogTableValue"
/>
</template>
<script></script>
<script setup>
import { ref } from 'vue'
import { Search, Edit, Delete } from '@element-plus/icons-vue'
import { getUser, changeUserState, deleteUser } from '@/api/user'
import { options } from './userOptions'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useI18n } from 'vue-i18n'
import Dialog from './components/dialogIndex.vue'
import { isNull } from '@/utils/filters'
<style lang="scss" scoped></style>
const i18n = useI18n()
const queryFrom = ref({
query: '',
pagenum: 1,
pagesize: 2
})
const total = ref(0)
const dialogVisible = ref(false)
const dialogTitle = ref('')
const dialogTableValue = ref({})
const tableData = ref([])
const initGetUsersList = async () => {
const res = await getUser(queryFrom.value)
// console.log(res)
total.value = res.total
tableData.value = res.users
}
initGetUsersList()
//
const handleSizeChange = (pageSize) => {
queryFrom.value.pagenum = 1
queryFrom.value.pagesize = pageSize
initGetUsersList()
}
const handleCurrentChange = (pageNum) => {
queryFrom.value.pagenum = pageNum
initGetUsersList()
}
//
const changeState = async (info) => {
await changeUserState(info.id, info.mg_state)
ElMessage({
// showClose: true,
message: i18n.t('message.updeteSuccess'),
type: 'success'
})
}
//
const handleDialogValue = (row) => {
if (isNull(row)) {
dialogTitle.value = '添加用户'
dialogTableValue.value = {}
} else {
dialogTitle.value = '编辑用户'
dialogTableValue.value = JSON.parse(JSON.stringify(row))
}
dialogVisible.value = true
}
const delUser = (row) => {
ElMessageBox.confirm('是否确认删除该用户?', '警告', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
//
.then(async () => {
await deleteUser(row.id)
ElMessage({
type: 'success',
message: '删除成功。'
})
initGetUsersList()
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消删除。'
})
})
}
</script>
<style lang="scss" scoped>
.header {
padding-bottom: 16px;
box-sizing: border-box;
}
.footer {
padding-top: 16px;
box-sizing: border-box;
text-align: right;
}
</style>

View File

@ -2610,6 +2610,11 @@ case-sensitive-paths-webpack-plugin@^2.3.0:
resolved "https://registry.npmmirror.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==
cesium@^1.95.0:
version "1.95.0"
resolved "https://registry.npmmirror.com/cesium/-/cesium-1.95.0.tgz#8a9036c58b9818406586259d3720a05f24e87a69"
integrity sha512-59U0lZD/wmSJa4t9FcK1/sp6PyCpx7h8c4giLd8VM7LJDL6w0G0o4QGlZ4TSJTBe4VIClf+qPDUf47wyBu4YoA==
chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.npmmirror.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
@ -3187,6 +3192,11 @@ dayjs@^1.10.7:
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.3.tgz#4754eb694a624057b9ad2224b67b15d552589258"
integrity sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==
dayjs@^1.11.4:
version "1.11.4"
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.4.tgz#3b3c10ca378140d8917e06ebc13a4922af4f433e"
integrity sha512-Zj/lPM5hOvQ1Bf7uAvewDaUcsJoI6JmNqmHhHl3nyumwe0XHwt8sWdOVAPACJzCebL8gQCi+K49w7iKWnGwX9g==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"