项目应用首页

This commit is contained in:
yin fuxian 2024-04-11 18:17:48 +08:00
parent 894795616c
commit 3202aa73b4
10 changed files with 533 additions and 11 deletions

2
sf-ui/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/node_modules
/dist

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询应用列列表
export function getListApi(query) {
return request({
url: '/index/list/list',
method: 'get',
params: query
})
}
// 查询应用列详细
export function getListDetail(id) {
return request({
url: '/index/list/' + id,
method: 'get'
})
}
// 新增应用列
export function addList(data) {
return request({
url: '/index/list',
method: 'post',
data: data
})
}
// 修改应用列
export function updateList(data) {
return request({
url: '/index/list',
method: 'put',
data: data
})
}
// 删除应用列
export function delList(id) {
return request({
url: '/index/list/' + id,
method: 'delete'
})
}

View File

@ -1,5 +1,8 @@
<template>
<div class="navbar">
<!-- <div style="float: left; line-height: 50px;" class="sidebar-logo-container">
<Logo :collapse="true" />
</div> -->
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/>
@ -9,19 +12,19 @@
<template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
<el-tooltip content="源码地址" effect="dark" placement="bottom">
<!-- <el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip content="文档地址" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip>
</el-tooltip> -->
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<!-- <el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>
</el-tooltip> -->
</template>
@ -48,6 +51,7 @@
<script>
import { mapGetters } from 'vuex'
import Logo from "../components/Sidebar/Logo";
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
@ -59,6 +63,7 @@ import RuoYiDoc from '@/components/RuoYi/Doc'
export default {
components: {
Logo,
Breadcrumb,
TopNav,
Hamburger,

View File

@ -111,7 +111,7 @@ export default {
value: val
})
if (!val) {
this.$store.dispatch('app/toggleSideBarHide', false);
// this.$store.dispatch('app/toggleSideBarHide', false);
this.$store.commit("SET_SIDEBAR_ROUTERS", this.$store.state.permission.defaultRoutes);
}
}

View File

@ -1,5 +1,6 @@
export { default as AppMain } from './AppMain'
export { default as Navbar } from './Navbar'
export { default as NavbarNew } from './NavbarNew'
export { default as Settings } from './Settings'
export { default as Sidebar } from './Sidebar/index.vue'
export { default as TagsView } from './TagsView/index.vue'

View File

@ -24,11 +24,15 @@ router.beforeEach((to, from, next) => {
// 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(() => {
isRelogin.show = false
store.dispatch('GenerateRoutes').then(accessRoutes => {
// 根据roles权限生成可访问的路由表
router.addRoutes(accessRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
})
if (to.path === '/index') {
next()
} else {
store.dispatch('GenerateRoutes').then(accessRoutes => {
// 根据roles权限生成可访问的路由表
router.addRoutes(accessRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
})
}
}).catch(err => {
store.dispatch('LogOut').then(() => {
Message.error(err)

View File

@ -68,7 +68,7 @@ export const constantRoutes = [
children: [
{
path: 'index',
component: () => import('@/views/index'),
component: () => import('@/views/indexNew'),
name: 'Index',
meta: { title: '首页', icon: 'dashboard', affix: true }
}

View File

@ -0,0 +1,115 @@
<template>
<el-row v-loading="loading" :gutter="20">
<el-col v-for="item in list" :key="item.id" :span="8" class="card-col">
<el-card :body-style="{ padding: '15px 0 0 0' }" shadow="hover">
<div class="card-conainer">
<div class="card-head">
<el-link :underline="false" @click="$emit('del', item)">删除</el-link>
</div>
<div class="card-center">
<image-preview :src="item.picture" :width="60" :height="60"/>
<!-- <el-avatar
class="icon"
:src="'/dev-api/'+item.picture"
fit="cover"
:size="100"
/> -->
<div class="content ml20">
<div class="title">{{item.appName}}</div>
<div class="time">{{item.createTime}}</div>
</div>
</div>
<p class="desc">{{item.appDesc}}</p>
</div>
<div class="card-foot">
<el-button class="card-btn" @click="$emit('update', item)">编辑</el-button>
<el-divider class="card-divider" direction="vertical"></el-divider>
<el-button class="card-btn" @click="$emit('enter', item)">进入</el-button>
</div>
</el-card>
</el-col>
</el-row>
</template>
<script>
export default {
props: {
list: {
type: Array,
default: () => []
},
loading: {
type: Boolean,
default: false
}
},
data() {
return {
defImg: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.card-col {
margin-bottom: 20px;
}
.card-conainer {
padding: 0 20px;
.card-head {
display: flex;
justify-content: flex-end;
}
.card-center {
display: flex;
.el-image {
width: 60px;
border-radius: 50%;
}
.content {
flex: 1;
display: flex;
flex-flow: column;
justify-content: space-evenly;
}
.title {
font-size: 16px;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.time {
font-size: 14px;
color: #666;
}
}
.desc {
font-size: 14px;
color: #999;
height: 38px;
display: -webkit-box; /* 兼容webkit内核浏览器 */
-webkit-line-clamp: 2; /* 最多显示两行 */
-webkit-box-orient: vertical; /* 设置或限制在一个块状元素显示的内容的排列方式 */
overflow: hidden; /* 隐藏超出部分 */
text-overflow: ellipsis; /* 显示省略号 */
}
}
.card-foot {
display: flex;
border-top: 1px solid #DCDFE6;
.card-btn {
flex: 1;
border: none;
border-radius: 0;
height: 50px;
}
.card-divider {
height: 50px;
margin: 0;
}
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<el-table v-loading="loading" :data="list">
<el-table-column type="index" width="55" align="center" />
<el-table-column label="项目名" width="300" prop="appName" :show-overflow-tooltip="true" />
<el-table-column label="项目图片" width="100" prop="picture">
<template slot-scope="scope">
<image-preview :src="scope.row.picture" :width="50" :height="50"/>
</template>
</el-table-column>
<el-table-column label="项目描述" prop="appDesc" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" width="200" prop="createTime" :show-overflow-tooltip="true" />
<el-table-column label="操作" width="200" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="$emit('enter', scope.row)"
>进入</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="$emit('update', scope.row)"
>编辑</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="$emit('del', scope.row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
props: {
list: {
type: Array,
default: () => []
},
loading: {
type: Boolean,
default: false
},
},
data() {
return {
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,291 @@
<template>
<div class="app-container home">
<div class="home-header">
<div class="home-header-left">
<h1>项目列表</h1>
</div>
<div class="home-header-right">
<el-input
v-model="queryParams.appName"
class="search-input mr10"
placeholder="请输入关键字"
clearable
@keyup.enter.native="getList"
>
<el-button slot="append" icon="el-icon-search" @click="getList"></el-button>
</el-input>
<el-button-group class="mr10">
<el-button :type="curType === 'card' ? 'primary' : 'default'" icon="el-icon-postcard" @click="checkType('card')">卡片</el-button>
<el-button :type="curType === 'list' ? 'primary' : 'default'" icon="el-icon-notebook-2" @click="checkType('list')">列表</el-button>
</el-button-group>
<el-button type="primary" @click="handleAdd(null)">新增项目</el-button>
</div>
</div>
<!-- <transition name="slide-fade"> -->
<component :is="curType === 'card' ? 'CardView' : 'ListView'"
:list="list"
:loading="loading"
@update="handleAdd"
@del="handleDelete"
@enter="handleEnter"
/>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- </transition> -->
<el-dialog :title="dialogTitle" :visible.sync="dialogFormVisible" center :before-close="dialogBeforeClose">
<el-form ref="form" :model="editForm" :rules="rules">
<el-form-item label="应用名称" label-width="120px" prop="appName">
<el-input v-model="editForm.appName" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="应用描述" label-width="120px" prop="appDesc">
<el-input v-model="editForm.appDesc" autocomplete="off" type="textarea" :rows="3"></el-input>
</el-form-item>
<el-form-item label="上传图片" label-width="120px" prop="picture">
<ImageUpload v-model="editForm.picture" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogClose"> </el-button>
<el-button type="primary" :loading="submitLoading" @click="submitForm"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import path from 'path'
import { isExternal } from '@/utils/validate'
import CardView from './components/home/card';
import ListView from './components/home/list';
import { getListApi, getListDetail, delList, addList, updateList } from "@/api/system/application";
export default {
name: "Index",
components: {
CardView,
ListView,
},
data() {
return {
loading: false,
curType: 'card',
queryParams: {
pageNum: 1,
pageSize: 10,
},
total: 0,
list: [],
dialogFormVisible: false,
dialogTitle: '新增应用',
//
rules: {
appName: [
{ required: true, message: "应用名称不能为空", trigger: "blur" }
],
appDesc: [
{ required: true, message: "应用描述不能为空", trigger: "blur" }
],
},
editForm: {
id: null,
appName: '',
appDesc: '',
picture: '',
},
submitLoading: false,
}
},
computed: {
routes() {
return this.$store.state.permission.addRoutes;
},
},
created() {
this.$store.dispatch('app/toggleSideBarHide', true);
this.getList();
},
watch: {
$route(route) {
this.$store.dispatch('app/toggleSideBarHide', route.path === '/index');
}
},
methods: {
/** 查询应用列列表 */
getList() {
this.loading = true;
getListApi(this.queryParams).then(response => {
console.log(response)
this.list = response.rows;
this.total = response.total;
this.loading = false;
}).catch(() => {
this.loading = false;
});
},
checkType(type) {
this.curType = type;
},
dialogBeforeClose(done) {
this.$refs.form.resetFields();
done();
},
dialogClose() {
this.$refs.form.resetFields();
this.dialogFormVisible = false;
},
// getList(params) {
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// const num = Math.floor(Math.random() * 10);
// const ls = new Array(num).fill(0).map((v,i) => {
// return {
// id: Math.random(),
// name: `${i}`,
// desc: `${i}${i}${i}`,
// createTime: `2024-04-${i + 1}`,
// img: "https://img.yzcdn.cn/vant/cat.jpeg",
// };
// });
// return resolve({
// code: 200,
// data: {
// list: ls,
// total: 86,
// }
// });
// }, 1000);
// });
// },
async handleEnter(row) {
// TODO
// id使
let routes = this.routes;
if (this.routes.length === 0) {
routes = await this.$store.dispatch('GenerateRoutes');
this.$router.addRoutes(routes)
}
const [first, secound] = routes;
const route = this.resolvePath(first, first.path);
this.$router.push(route);
},
resolvePath(route, basepath) {
if (isExternal(basepath)) {
return basepath;
}
const childRoute = route.children && route.children[0];
if (childRoute) {
return path.resolve(basepath, childRoute.path);
}
return path.resolve(basepath);
},
handleAdd(row) {
if (!row) {
this.editForm = {
id: null,
appName: '',
appDesc: '',
picture: '',
}
this.dialogTitle = '新增应用';
} else {
this.editForm = {
id: row.id,
appName: row.appName,
appDesc: row.appDesc,
picture: row.picture,
}
this.dialogTitle = '编辑应用';
}
this.dialogFormVisible = true;
},
async handleDelete(row) {
this.$confirm('此操作将永久删除该应用, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
instance.confirmButtonLoading = true;
this.delFunc(row.id).then(done).finally(() => {
instance.confirmButtonLoading = false;
})
} else {
done();
}
}
});
},
async delFunc(id) {
try {
const res = await delList(id);
this.$message.success('删除成功');
this.getList();
return res;
} catch(e) {
this.$message.error('删除失败');
return Promise.reject(e);
}
},
/** 提交按钮 */
async submitForm() {
await this.$refs["form"].validate();
const data = Object.assign({},this.editForm);
const request = data.id ? updateList : addList;
const msg = data.id ? '修改' : '新增';
this.submitLoading = true;
try {
const { code } = await request(data);
this.$modal.msgSuccess(`${msg}成功!`);
this.submitLoading = false;
this.getList();
this.dialogClose();
} catch (error) {
this.$modal.msgSuccess(`${msg}成功!`);
this.submitLoading = false;
}
},
}
}
</script>
<style lang="scss" scoped>
.top-btn {
display: flex;
justify-content: flex-end;
}
.home-header {
display: flex;
justify-content: space-between;
align-items: center;
.search-input {
width: 240px;
}
}
/* slide-fade 过渡效果的 CSS 类定义 */
.slide-fade-enter-active,
.slide-fade-leave-active {
transition: all 0.8s ease;
}
.slide-fade-leave-active {
position: absolute;
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(-100%); /* 左滑出效果,若需右滑入则改为 translateX(100%) */
opacity: 0;
}
.slide-fade-enter-to,
.slide-fade-leave-from {
transform: translateX(0);
opacity: 1;
}
</style>