feat:重构请求模块-大更新

This commit is contained in:
橙子
2023-12-11 22:14:13 +08:00
committed by Xwen
parent 27a2849619
commit 30de46b840
34 changed files with 1249 additions and 284 deletions

View File

@@ -62,6 +62,11 @@ namespace Yi.Framework.Ddd.Application
{ {
} }
public override Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
{
throw new NotImplementedException($"【{typeof(TEntity)}】实体的CrudAppService查询为具体业务通用查询几乎无实际场景请重写实现");
}
/// <summary> /// <summary>
/// 偷梁换柱 /// 偷梁换柱
/// </summary> /// </summary>
@@ -72,7 +77,7 @@ namespace Yi.Framework.Ddd.Application
{ {
await Repository.DeleteManyAsync(id); await Repository.DeleteManyAsync(id);
} }
[RemoteService(isEnabled:false)] [RemoteService(isEnabled: false)]
public override Task DeleteAsync(TKey id) public override Task DeleteAsync(TKey id)
{ {
return base.DeleteAsync(id); return base.DeleteAsync(id);

View File

@@ -1,8 +1,9 @@
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Yi.Framework.Ddd.Application.Contracts;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
{ {
public class ArticleGetListInputVo : PagedAndSortedResultRequestDto public class ArticleGetListInputVo : PagedAllResultRequestDto
{ {
public string? Content { get; set; } public string? Content { get; set; }
public string? Name { get; set; } public string? Name { get; set; }

View File

@@ -10,5 +10,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
public Guid DiscussId { get; set; } public Guid DiscussId { get; set; }
public List<ArticleGetListOutputDto>? Children { get; set; } public List<ArticleGetListOutputDto>? Children { get; set; }
public DateTime CreationTime { get; set; }
} }
} }

View File

@@ -8,5 +8,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
public string Name { get; set; } public string Name { get; set; }
public Guid DiscussId { get; set; } public Guid DiscussId { get; set; }
public Guid ParentId { get; set; } public Guid ParentId { get; set; }
public DateTime CreationTime { get; set; }
} }
} }

View File

@@ -8,5 +8,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
public string Name { get; set; } public string Name { get; set; }
public string? Logo { get; set; } public string? Logo { get; set; }
public string? Introduction { get; set; } public string? Introduction { get; set; }
public string Code { get; set; }
} }
} }

View File

@@ -1,11 +1,11 @@
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Yi.Framework.Ddd.Application.Contracts;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
{ {
public class PlateGetListInputVo : PagedAndSortedResultRequestDto public class PlateGetListInputVo : PagedAllResultRequestDto
{ {
public string? Name { get; set; } public string? Name { get; set; }
public string? Logo { get; set; } public string? Code { get; set; }
public string? Introduction { get; set; }
} }
} }

View File

@@ -8,5 +8,9 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
public string Name { get; set; } public string Name { get; set; }
public string? Logo { get; set; } public string? Logo { get; set; }
public string? Introduction { get; set; } public string? Introduction { get; set; }
public string Code { get; set; }
public DateTime CreationTime { get; set; }
} }
} }

View File

@@ -7,5 +7,8 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
public string Name { get; set; } public string Name { get; set; }
public string? Logo { get; set; } public string? Logo { get; set; }
public string? Introduction { get; set; } public string? Introduction { get; set; }
public string Code { get; set; }
public DateTime CreationTime { get; set; }
} }
} }

View File

@@ -5,5 +5,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
public string? Name { get; set; } public string? Name { get; set; }
public string? Logo { get; set; } public string? Logo { get; set; }
public string? Introduction { get; set; } public string? Introduction { get; set; }
public string? Code { get; set; }
} }
} }

View File

@@ -3,8 +3,12 @@ using Mapster;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using Yi.Framework.Bbs.Application.Contracts.Dtos.Article; using Yi.Framework.Bbs.Application.Contracts.Dtos.Article;
using Yi.Framework.Bbs.Application.Contracts.Dtos.Plate;
using Yi.Framework.Bbs.Application.Contracts.IServices; using Yi.Framework.Bbs.Application.Contracts.IServices;
using Yi.Framework.Bbs.Domain.Entities; using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Repositories; using Yi.Framework.Bbs.Domain.Repositories;
@@ -37,6 +41,19 @@ namespace Yi.Framework.Bbs.Application.Services
private IArticleRepository _articleRepository { get; set; } private IArticleRepository _articleRepository { get; set; }
private ISqlSugarRepository<DiscussEntity> _discussRepository { get; set; } private ISqlSugarRepository<DiscussEntity> _discussRepository { get; set; }
private IDiscussService _discussService { get; set; } private IDiscussService _discussService { get; set; }
public override async Task<PagedResultDto<ArticleGetListOutputDto>> GetListAsync(ArticleGetListInputVo input)
{
RefAsync<int> total = 0;
var entities = await _articleRepository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name.Contains(input.Name!))
//.WhereIF(!string.IsNullOrEmpty(input.Code), x => x.Name.Contains(input.Code!))
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
return new PagedResultDto<ArticleGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
}
/// <summary> /// <summary>
/// 获取文章全部平铺信息 /// 获取文章全部平铺信息
/// </summary> /// </summary>

View File

@@ -1,8 +1,12 @@
using SqlSugar;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Yi.Framework.Bbs.Application.Contracts.Dtos.Plate; using Yi.Framework.Bbs.Application.Contracts.Dtos.Plate;
using Yi.Framework.Bbs.Application.Contracts.IServices; using Yi.Framework.Bbs.Application.Contracts.IServices;
using Yi.Framework.Bbs.Domain.Entities; using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Ddd.Application; using Yi.Framework.Ddd.Application;
using Yi.Framework.Rbac.Application.Contracts.Dtos.Config;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Services namespace Yi.Framework.Bbs.Application.Services
{ {
@@ -12,8 +16,21 @@ namespace Yi.Framework.Bbs.Application.Services
public class PlateService : YiCrudAppService<PlateEntity, PlateGetOutputDto, PlateGetListOutputDto, Guid, PlateGetListInputVo, PlateCreateInputVo, PlateUpdateInputVo>, public class PlateService : YiCrudAppService<PlateEntity, PlateGetOutputDto, PlateGetListOutputDto, Guid, PlateGetListInputVo, PlateCreateInputVo, PlateUpdateInputVo>,
IPlateService IPlateService
{ {
public PlateService(IRepository<PlateEntity, Guid> repository) : base(repository) private ISqlSugarRepository<PlateEntity, Guid> _repository;
public PlateService(ISqlSugarRepository<PlateEntity, Guid> repository) : base(repository)
{ {
_repository= repository;
}
public override async Task<PagedResultDto<PlateGetListOutputDto>> GetListAsync(PlateGetListInputVo input)
{
RefAsync<int> total = 0;
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name.Contains(input.Name!))
.WhereIF(!string.IsNullOrEmpty(input.Code), x => x.Name.Contains(input.Code!))
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
return new PagedResultDto<PlateGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
} }
} }
} }

View File

@@ -1,11 +1,12 @@
using SqlSugar; using SqlSugar;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace Yi.Framework.Bbs.Domain.Entities namespace Yi.Framework.Bbs.Domain.Entities
{ {
[SugarTable("Article")] [SugarTable("Article")]
public class ArticleEntity : Entity<Guid>, ISoftDelete public class ArticleEntity : Entity<Guid>, ISoftDelete,IAuditedObject
{ {
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
@@ -23,6 +24,15 @@ namespace Yi.Framework.Bbs.Domain.Entities
[SugarColumn(IsIgnore = true)] [SugarColumn(IsIgnore = true)]
public List<ArticleEntity>? Children { get; set; } public List<ArticleEntity>? Children { get; set; }
public DateTime CreationTime { get; set; }
public Guid? CreatorId { get; set; }
public Guid? LastModifierId { get; set; }
public DateTime? LastModificationTime { get; set; }
} }
public static class ArticleEntityExtensions public static class ArticleEntityExtensions

View File

@@ -1,18 +1,31 @@
using SqlSugar; using SqlSugar;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Auditing;
namespace Yi.Framework.Bbs.Domain.Entities namespace Yi.Framework.Bbs.Domain.Entities
{ {
[SugarTable("Plate")] [SugarTable("Plate")]
public class PlateEntity : Entity<Guid>, ISoftDelete public class PlateEntity : Entity<Guid>, ISoftDelete,IAuditedObject
{ {
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
public string Code { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string? Logo { get; set; } public string? Logo { get; set; }
public string? Introduction { get; set; } public string? Introduction { get; set; }
public bool IsDeleted { get; set; } public bool IsDeleted { get; set; }
public DateTime CreationTime { get; set; }
public Guid? CreatorId { get; set; }
public Guid? LastModifierId { get; set; }
public DateTime? LastModificationTime { get; set; }
} }
} }

View File

@@ -55,7 +55,7 @@ namespace Yi.Abp.Web
//动态Api //动态Api
Configure<AbpAspNetCoreMvcOptions>(options => Configure<AbpAspNetCoreMvcOptions>(options =>
{ {
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly,options=>options.RemoteServiceName="default"); options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly, options => options.RemoteServiceName = "default");
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly, options => options.RemoteServiceName = "rbac"); options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly, options => options.RemoteServiceName = "rbac");
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly, options => options.RemoteServiceName = "bbs"); options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly, options => options.RemoteServiceName = "bbs");
}); });
@@ -63,7 +63,6 @@ namespace Yi.Abp.Web
//设置api格式 //设置api格式
service.AddControllers().AddNewtonsoftJson(options => service.AddControllers().AddNewtonsoftJson(options =>
{ {
// options.SerializerSettings.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss"));
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
}); });
Configure<AbpJsonOptions>(options => Configure<AbpJsonOptions>(options =>
@@ -76,7 +75,10 @@ namespace Yi.Abp.Web
}); });
//Swagger //Swagger
context.Services.AddYiSwaggerGen<YiAbpWebModule>(); context.Services.AddYiSwaggerGen<YiAbpWebModule>(options =>
{
options.SwaggerDoc("default", new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1",Description="集大成者" });
});
//跨域 //跨域
context.Services.AddCors(options => context.Services.AddCors(options =>

View File

@@ -1,2 +1,4 @@
# 接口前缀
VITE_APP_BASEAPI="/api-dev" VITE_APP_BASEAPI="/api-dev"
VITE_APP_URL="http://localhost:19001/api/app" VITE_APP_URL="http://localhost:19001/api/app"
VITE_APP_ENV_NAME = "dev"

View File

@@ -1 +1,4 @@
# 接口前缀
VITE_APP_BASEAPI="/prod-api" VITE_APP_BASEAPI="/prod-api"
VITE_APP_ENV_NAME = "production"

View File

@@ -0,0 +1,65 @@
import request from "@/config/axios/service";
/**
* 用户登录
* @param {*} data 账号密码
*/
export function userLogin(data) {
return request({
url: `/account/login`,
method: "post",
data,
});
}
/**
* 用户注册
* @param {*} data 账号密码
*/
export function userRegister(data) {
return request({
url: `/account/register`,
method: "post",
data,
});
}
/**
* 获取用户详细信息
*/
export function getUserDetailInfo() {
return request({
url: `/account`,
method: "get",
});
}
/**
* 用户退出
*/
export function userLogout() {
return request({
url: `/account/logout`,
method: "post",
});
}
/**
* 获取验证码
*/
export function getCodeImg() {
return request({
url: `/account/captcha-image`,
method: "get",
});
}
/**
* 获取短信验证码
*/
export function getCodePhone(data) {
return request({
url: `/account/captcha-phone`,
method: "post",
data,
});
}

View File

@@ -1,9 +1,9 @@
import myaxios from '@/utils/request' import request from "@/config/axios/service";
//获取配置 //获取配置
export function getAll(){ export function getAll() {
return myaxios({ return request({
url: '/config', url: "/config",
method: 'get' method: "get",
}) });
}; }

View File

@@ -0,0 +1,13 @@
export default {
"000": "操作太频繁,请勿重复请求",
401: "当前操作没有权限,请退出重试",
403: "当前操作没有权限,请退出重试",
404: "资源不存在",
417: "未绑定登录账号,请使用密码登录后绑定",
423: "演示环境不能操作,如需了解联系",
426: "用户名不存在或密码错误",
428: "验证码错误,请重新输入",
429: "请求过频繁",
479: "演示环境,没有权限操作",
default: "系统未知错误,请反馈给管理员",
};

View File

@@ -0,0 +1,34 @@
const config = {
/**
* api请求基础路径
*/
base_url: {
// 开发环境接口前缀
dev: import.meta.env.VITE_APP_BASEAPI,
// 打包生产环境接口前缀
pro: window.location.protocol + "//" + window.location.hostname + ":19001",
},
/**
* 接口请求前缀
*/
pre_interface: import.meta.env.VITE_APP_BASEAPI,
/**
* 接口成功返回状态码
*/
result_code: "0000",
/**
* 接口请求超时时间
*/
request_timeout: 60000,
/**
* 默认接口请求类型
* 可选值application/x-www-form-urlencoded multipart/form-data
*/
default_headers: "application/json",
};
export { config };

View File

@@ -0,0 +1,89 @@
import axios from "axios";
import { ElMessage } from "element-plus";
import { config } from "@/config/axios/config";
import { Session } from "@/utils/storage";
import useAuths from "@/hooks/useAuths";
const { getToken } = useAuths();
const { request_timeout } = config;
export const PATH_URL = import.meta.env.VITE_APP_BASEAPI;
// 配置新建一个 axios 实例
const service = axios.create({
baseURL: PATH_URL, // api 的 base_url
timeout: request_timeout, // 请求超时时间
headers: { "Content-Type": "application/json" },
hideerror: false, //是否在底层显示错误信息
});
// 添加请求拦截器
service.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么 token
const token = getToken();
if (token) {
config.headers["Authorization"] = `Bearer ${token}`;
}
if (Session.get("tenantId")) {
config.headers["TenantId"] = Session.get("tenantId");
}
return config;
},
(error) => {
// 对请求错误做些什么
return Promise.reject(error);
}
);
// 添加响应拦截器
service.interceptors.response.use(
(response) => {
return Promise.resolve(response);
},
(error) => {
// 对响应错误做点什么
if (error.message.indexOf("timeout") != -1) {
ElMessage({
type: "danger",
message: "网络超时",
});
} else if (error.message == "Network Error") {
ElMessage({
type: "danger",
message: "网络连接错误",
});
} else {
const res = error.response || {};
const status = Number(res.status) || 200;
const message = res.data.error.message;
if (status === 401) {
ElMessage({
type: "danger",
message,
});
return;
}
if (status !== 200) {
if (status >= 500) {
ElMessage({
type: "danger",
message: "网络开小差了,请稍后再试",
});
return Promise.reject(new Error(message));
}
// 避开找不到后端接口的提醒
if (status !== 404) {
ElMessage({
type: "danger",
message,
});
}
}
}
return Promise.reject(new Error(error));
}
);
// 导出 axios 实例
export default service;

View File

@@ -0,0 +1,138 @@
import { ElMessage, ElMessageBox } from "element-plus";
import useUserStore from "@/stores/user";
import router from "@/router";
import { Session, Local } from "@/utils/storage";
import { userLogin, getUserDetailInfo, userLogout } from "@/apis/auth";
const TokenKey = "AccessToken";
export const AUTH_MENUS = "AUTH_MENUS";
export const AUTH_USER = "AUTH_USER";
export default function useAuths(opt) {
const defaultOpt = {
loginUrl: "/login", // 登录页跳转url 默认: /login
loginReUrl: "", // 登录页登陆成功后带重定向redirect=的跳转url 默认为空
homeUrl: "/index", // 主页跳转url 默认: /index
otherQuery: {}, // 成功登录后携带的除redirect外其他参数
};
let option = {
...defaultOpt,
...opt,
};
// 获取token
const getToken = () => {
return Session.get(TokenKey);
};
// 存储token到cookies
const setToken = (token) => {
if (token == null) {
return false;
}
Session.set(TokenKey, token);
return true;
};
// 删除token
const removeToken = () => {
Session.remove(TokenKey);
return true;
};
// 退出登录
const logoutFun = async () => {
let flag = true;
try {
await userLogout().then((res) => {
ElMessage({
message: "退出成功",
type: "info",
duration: 2000,
});
});
} catch (error) {
flag = await ElMessageBox.confirm(
`退出登录失败,是否强制退出?`,
"提示",
{
confirmButtonText: "确 定",
cancelButtonText: "取 消",
type: "warning",
}
)
.then(() => {
return true;
})
.catch(() => {
//取消
return false;
});
}
if (flag) {
clearStorage();
}
};
// 清空本地存储的信息
const clearStorage = () => {
Session.clear();
Local.clear();
removeToken();
window.location.reload();
Session.set("vuex", null);
};
// 用户名密码登录
const loginFun = async (params) => {
const res = await userLogin(params);
ElMessage({
message: `您好${params.userName},登录成功!`,
type: "success",
});
loginSuccess(res);
return res;
};
// 获取用户基本信息、角色、菜单权限
const getUserInfo = async () => {
try {
let { data } = await getUserDetailInfo();
// useUserStore
// store.dispatch("updateUserInfo", result);
return data;
} catch (error) {
return {};
}
};
// 登录成功之后的操作
const loginSuccess = async (res) => {
const { token } = res.data;
setToken(token);
try {
// 存储用户信息
await getUserInfo(); // 用户信息
// 登录成功后 路由跳转
router.replace({
path: option.loginReUrl ? option.loginReUrl : option.homeUrl,
query: option.otherQuery,
});
} catch (error) {
removeToken();
return false;
}
};
return {
getToken,
setToken,
removeToken,
loginFun,
getUserInfo,
logoutFun,
clearStorage,
};
}

View File

@@ -1,65 +1,52 @@
import router from './router' import router from "./router";
import { ElMessage } from 'element-plus' import useAuths from "@/hooks/useAuths";
import NProgress from 'nprogress' import { ElMessage } from "element-plus";
import 'nprogress/nprogress.css' import NProgress from "nprogress";
import { getToken } from '@/utils/auth' import "nprogress/nprogress.css";
import { isRelogin } from '@/utils/request' import useUserStore from "@/stores/user";
import useUserStore from '@/stores/user'
NProgress.configure({ showSpinner: false }); NProgress.configure({ showSpinner: false });
const { getToken, logoutFun } = useAuths();
const whiteList = ['/login', '/auth-redirect', '/bind', '/register']; const whiteList = ["/login", "/auth-redirect", "/bind", "/register"];
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start() NProgress.start();
if (getToken()) { const hasToken = getToken();
// to.meta.title && useSettingsStore().setTitle(to.meta.title) if (hasToken) {
/* has token*/ if (to.path === "/login") {
if (to.path === '/login') { // 已经登陆跳转到首页
next({ path: '/' }) next({ path: "/" });
NProgress.done() NProgress.done();
} else { } else {
if (useUserStore().roles.length === 0) {
if (useUserStore().roles.length === 0)
{
isRelogin.show = true
// 判断当前用户是否已拉取完user_info信息 // 判断当前用户是否已拉取完user_info信息
useUserStore().getInfo().then(() => { useUserStore()
isRelogin.show = false .getInfo()
//这里不需要动态路由 .then(() => {
// usePermissionStore().generateRoutes().then(accessRoutes => { next({ ...to, replace: true });
// // 根据roles权限生成可访问的路由表
// accessRoutes.forEach(route => {
// if (!isHttp(route.path)) {
// router.addRoute(route) // 动态添加可访问路由表
// }
// })
// next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
// })
next({ ...to, replace: true })
}).catch(err => {
useUserStore().logOut().then(() => {
ElMessage.error(err)
next({ path: '/' })
}) })
}) .catch((err) => {
logoutFun.then(() => {
ElMessage.error(err);
next({ path: "/" });
});
});
} else { } else {
next() next();
} }
} }
} else { } else {
// 没有token // 没有token
if (whiteList.indexOf(to.path) !== -1) { if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,直接进入 // 在免登录白名单,直接进入
next() next();
} else { } else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 next(`/login?redirect=${to.path}&unTourist=true`); // 否则全部重定向到登录页
NProgress.done() NProgress.done();
} }
} }
}) });
router.afterEach(() => { router.afterEach(() => {
NProgress.done() NProgress.done();
}) });

View File

@@ -1,76 +1,74 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from "vue-router";
import Layout from '../layout/Index.vue' import Layout from "../layout/Index.vue";
import NotFound from '../views/error/404.vue' import NotFound from "../views/error/404.vue";
import LoginLayout from '../layout/LoginLayout.vue' import LoginLayout from "../layout/LoginLayout.vue";
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
scrollBehavior(to, from, savedPosition) { scrollBehavior(to, from, savedPosition) {
// 始终滚动到顶部 // 始终滚动到顶部
return { top: 0 } return { top: 0 };
}, },
routes: [ routes: [
{ {
name:'test', name: "test",
path: '/test', path: "/test",
component: () => import('../views/Test.vue') component: () => import("../views/Test.vue"),
}, },
{ {
path: "/loginLayout",
path: '/loginLayout', name: "loginLayout",
name: 'loginLayout',
component: LoginLayout, component: LoginLayout,
redirect: '/login' , redirect: "/login",
children :[ children: [
{ {
name:'login', name: "login",
path: '/login', path: "/login",
component: () => import('../views/Login.vue') component: () => import("../views/Login.vue"),
}, },
{ {
name:'register', name: "register",
path: '/register', path: "/register",
component: () => import('../views/Register.vue') component: () => import("../views/Register.vue"),
}, },
] ],
}, },
{ {
path: '/', path: "/",
name: 'layout', name: "layout",
component: Layout, component: Layout,
redirect: '/index' , redirect: "/index",
children :[ children: [
{ {
name:'index', name: "index",
path: '/index', path: "/index",
component: () => import('../views/Index.vue') component: () => import("../views/Index.vue"),
}, },
{ {
name:'article', name: "article",
path: '/article/:discussId/:articleId?', path: "/article/:discussId/:articleId?",
component: () => import('../views/Article.vue') component: () => import("../views/Article.vue"),
}, },
{ {
name:'discuss', name: "discuss",
path: '/discuss/:plateId?', path: "/discuss/:plateId?",
component: () => import('../views/Discuss.vue') component: () => import("../views/Discuss.vue"),
}, },
{ {
//artTypediscuss主题、article文章 //artTypediscuss主题、article文章
//operTypecreate创建、update更新 //operTypecreate创建、update更新
name:'editArt', name: "editArt",
path:'/editArt', path: "/editArt",
component:()=>import('../views/EditArticle.vue') component: () => import("../views/EditArticle.vue"),
}, },
{ {
name:'profile', name: "profile",
path:'/profile', path: "/profile",
component:()=>import('../views/profile/Index.vue') component: () => import("../views/profile/Index.vue"),
},
} ],
]
}, },
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }, { path: "/:pathMatch(.*)*", name: "NotFound", component: NotFound },
] ],
}) });
export default router export default router;

View File

@@ -1,98 +1,109 @@
import { login, logout, getInfo,register } from '@/apis/accountApi' import { login, logout, getInfo, register } from "@/apis/accountApi";
import { getToken, setToken, removeToken } from '@/utils/auth' import { getUserDetailInfo } from "@/apis/auth";
import { defineStore } from 'pinia' import useAuths from "@/hooks/useAuths";
const useUserStore = defineStore('user', import { defineStore } from "pinia";
{
state: () => ({ const { getToken, setToken, removeToken } = useAuths();
id:'',
token: getToken(), const useUserStore = defineStore("user", {
name: '游客', state: () => ({
userName:'', id: "",
icon: null, token: getToken(),
roles: [], name: "游客",
permissions: [] userName: "",
}), icon: null,
getters: { roles: [],
}, permissions: [],
actions: { }),
// 登录 getters: {},
login(userInfo) { actions: {
const userName = userInfo.userName.trim() // 登录
const password = userInfo.password login(userInfo) {
const code = userInfo.code const userName = userInfo.userName.trim();
const uuid = userInfo.uuid const password = userInfo.password;
return new Promise((resolve, reject) => { const code = userInfo.code;
login(userName, password, code, uuid).then(response => { const uuid = userInfo.uuid;
const res=response.data; return new Promise((resolve, reject) => {
login(userName, password, code, uuid)
.then((response) => {
const res = response.data;
setToken(res.token); setToken(res.token);
this.token = res.token; this.token = res.token;
resolve(response); resolve(response);
}).catch(error => {
reject(error)
}) })
}) .catch((error) => {
}, reject(error);
// 获取用户信息 });
getInfo() { });
return new Promise((resolve, reject) => { },
getInfo().then(response => { // 获取用户信息
const res=response.data; getInfo() {
const user = res.user return new Promise((resolve, reject) => {
const avatar = (user.icon == "" || user.icon == null) ? "/src/assets/logo.ico" : import.meta.env.VITE_APP_BASEAPI + "/file/"+user.icon; getUserDetailInfo()
.then((response) => {
const res = response.data;
const user = res.user;
const avatar =
user.icon == "" || user.icon == null
? "/src/assets/logo.ico"
: import.meta.env.VITE_APP_BASEAPI + "/file/" + user.icon;
if (res.roleCodes && res.roleCodes.length > 0) { // 验证返回的roles是否是一个非空数组 if (res.roleCodes && res.roleCodes.length > 0) {
this.roles = res.roleCodes // 验证返回的roles是否是一个非空数组
this.permissions = res.permissionCodes this.roles = res.roleCodes;
this.permissions = res.permissionCodes;
// this.roles = ["admin"]; // this.roles = ["admin"];
// this.permissions=["*:*:*"] // this.permissions=["*:*:*"]
} else { } else {
this.roles = ['ROLE_DEFAULT'] this.roles = ["ROLE_DEFAULT"];
} }
// this.roles = ["admin"]; // this.roles = ["admin"];
// this.permissions=["*:*:*"] // this.permissions=["*:*:*"]
this.name = user.nick this.name = user.nick;
this.icon = avatar; this.icon = avatar;
this.userName=user.userName; this.userName = user.userName;
this.id=user.id; this.id = user.id;
resolve(res) resolve(res);
}).catch(error => {
reject(error)
}) })
}) .catch((error) => {
}, reject(error);
// 退出系统 });
logOut() { });
return new Promise((resolve, reject) => { },
logout().then(() => { // 退出系统
this.token = '' logOut() {
this.roles = [] return new Promise((resolve, reject) => {
this.permissions = [] logout()
removeToken() .then(() => {
resolve() this.token = "";
}).catch(error => { this.roles = [];
reject(error) this.permissions = [];
removeToken();
resolve();
}) })
}) .catch((error) => {
}, reject(error);
// 注册 });
register(userInfo) { });
const userName = userInfo.userName.trim() },
const password = userInfo.password.trim() // 注册
const phone = userInfo.phone; register(userInfo) {
const uuid = userInfo.uuid; const userName = userInfo.userName.trim();
const code=userInfo.code; const password = userInfo.password.trim();
return new Promise((resolve, reject) => { const phone = userInfo.phone;
register(userName,password,phone,code,uuid).then(response => { const uuid = userInfo.uuid;
resolve(response); const code = userInfo.code;
}).catch(error => { return new Promise((resolve, reject) => {
reject(error) register(userName, password, phone, code, uuid)
}) .then((response) => {
}) resolve(response);
}, })
.catch((error) => {
}, reject(error);
}) });
});
},
},
});
export default useUserStore; export default useUserStore;

View File

@@ -0,0 +1,140 @@
/**
* 根据后缀判断文件类型
* @param {string} fileName 文件后缀名
* @returns
*/
export function matchType(fileName) {
// 后缀获取
let suffix = "";
// 获取类型结果
let result = "";
try {
let flieArr = fileName.split(".");
suffix = flieArr[flieArr.length - 1];
} catch (err) {
suffix = "";
}
// fileName无后缀返回 false
if (!suffix) {
result = false;
return result;
}
// 图片格式
let imglist = ["png", "jpg", "jpeg", "bmp", "gif"];
// 进行图片匹配
result = imglist.some(function (item) {
return item == suffix;
});
if (result) {
result = "image";
return result;
}
// 匹配txt
let txtlist = ["txt"];
result = txtlist.some(function (item) {
return item == suffix;
});
if (result) {
result = "txt";
return result;
}
// 匹配 excel
let excelist = ["xls", "xlsx"];
result = excelist.some(function (item) {
return item == suffix;
});
if (result) {
result = "excel";
return result;
}
// 匹配 word
let wordlist = ["doc", "docx"];
result = wordlist.some(function (item) {
return item == suffix;
});
if (result) {
result = "word";
return result;
}
// 匹配 pdf
let pdflist = ["pdf"];
result = pdflist.some(function (item) {
return item == suffix;
});
if (result) {
result = "pdf";
return result;
}
// 匹配 ppt
let pptlist = ["ppt"];
result = pptlist.some(function (item) {
return item == suffix;
});
if (result) {
result = "ppt";
return result;
}
// 匹配 视频
let videolist = ["mp4", "m2v", "mkv"];
result = videolist.some(function (item) {
return item == suffix;
});
if (result) {
result = "video";
return result;
}
// 匹配 音频
let radiolist = ["mp3", "wav", "wmv"];
result = radiolist.some(function (item) {
return item == suffix;
});
if (result) {
result = "radio";
return result;
}
// 其他 文件类型
result = "other";
return result;
}
/**
* url处理
* @param {string} path url路径
* @returns
*/
export function convertToUrl(path) {
// 替换反斜杠为正斜杠
const normalizedPathWithSlashes = path.replace(/\\/g, "/");
// 去掉开始的点号和反斜杠
const removedDotsAndSlashes = normalizedPathWithSlashes.replace(/^\.\//, "");
// 添加斜杠作为根路径
const url = `/${removedDotsAndSlashes}`;
return url;
}
/**
* 下载文件
*
* @param {*} path 下载地址/下载请求地址。
* @param {string} name 下载文件的名字(考虑到兼容性问题,最好加上后缀名
*/
export const downLoadFile = (path, name) => {
const link = document.createElement("a");
link.href = path;
link.download = name;
if (isMobileDevice()) {
link.target = "_blank";
link.rel = "noopener noreferrer";
}
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
// 判断是否移动设备
export function isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
}

View File

@@ -0,0 +1,53 @@
/**
* window.localStorage 浏览器永久缓存
* @method set 设置永久缓存
* @method get 获取永久缓存
* @method remove 移除永久缓存
* @method clear 移除全部永久缓存
*/
export const Local = {
// 设置永久缓存
set(key, val) {
window.localStorage.setItem(key, JSON.stringify(val));
},
// 获取永久缓存
get(key) {
let json = window.localStorage.getItem(key);
return JSON.parse(json);
},
// 移除永久缓存
remove(key) {
window.localStorage.removeItem(key);
},
// 移除全部永久缓存
clear() {
window.localStorage.clear();
},
};
/**
* window.sessionStorage 浏览器会话临时缓存
* @method set 设置临时缓存
* @method get 获取临时缓存
* @method remove 移除临时缓存
* @method clear 移除全部临时缓存
*/
export const Session = {
// 设置临时缓存
set(key, val) {
window.sessionStorage.setItem(key, JSON.stringify(val));
},
// 获取临时缓存
get(key) {
let json = window.sessionStorage.getItem(key);
return JSON.parse(json);
},
// 移除临时缓存
remove(key) {
window.sessionStorage.removeItem(key);
},
// 移除全部临时缓存
clear() {
window.sessionStorage.clear();
},
};

View File

@@ -1,47 +1,59 @@
<template> <template>
<div class="login-wrapper"> <div class="login-wrapper">
<h1>{{configStore.name}}-登录</h1> <h1>{{ configStore.name }}-登录</h1>
<div class="login-form"> <div class="login-form">
<el-form ref="loginFormRef" :model="loginForm" :rules="rules">
<el-form ref="loginFormRef" v-model="loginForm" :rules="rules" > <div class="username form-item">
<el-form-item prop="userName">
<div class="username form-item"> <span>使用账号</span>
<el-form-item prop="userName"> <el-input
<span>使用账号</span> v-model="loginForm.userName"
<input type="text" class="input-item" v-model="loginForm.userName"> class="input-item"
</el-form-item> ></el-input>
</div> <!-- <input
type="text"
<div class="password form-item"> class="input-item"
<el-form-item prop="password"> v-model="loginForm.userName"
<span>密码</span> /> -->
<input type="password" class="input-item" v-model="loginForm.password"> </el-form-item>
</el-form-item>
</div>
</el-form>
<RouterLink to="/register" > 没有账号前往注册</RouterLink>
<button class="login-btn" @click="login"> </button>
<button class="login-btn" @click="guestlogin">游客临时登录</button>
</div> </div>
<div class="password form-item">
<el-form-item prop="password">
<span>密码</span>
<div class="divider"> <el-input
<span class="line"></span> type="password"
<span class="divider-text">其他方式登录</span> v-model="loginForm.password"
<span class="line"></span> class="input-item"
</div> ></el-input>
<!-- <input
<div class="other-login-wrapper"> type="password"
<div class="other-login-item"> class="input-item"
<img src="@/assets/login_images/QQ.png" alt=""> v-model="loginForm.password"
</div> /> -->
<div class="other-login-item"> </el-form-item>
<img src="@/assets/login_images/WeChat.png" alt="">
</div>
</div> </div>
</el-form>
<RouterLink to="/register"> 没有账号前往注册</RouterLink>
<button class="login-btn" @click="login(loginFormRef)"> </button>
<button class="login-btn" @click="guestlogin">游客临时登录</button>
</div> </div>
<!-- <h2> 登录-欢迎</h2>
<div class="divider">
<span class="line"></span>
<span class="divider-text">其他方式登录</span>
<span class="line"></span>
</div>
<div class="other-login-wrapper">
<div class="other-login-item">
<img src="@/assets/login_images/QQ.png" alt="" />
</div>
<div class="other-login-item">
<img src="@/assets/login_images/WeChat.png" alt="" />
</div>
</div>
</div>
<!-- <h2> 登录-欢迎</h2>
<el-input v-model="loginForm.userName" placeholder="用户名" /> <el-input v-model="loginForm.userName" placeholder="用户名" />
<el-input v-model="loginForm.password" placeholder="密码" show-password /> <el-input v-model="loginForm.password" placeholder="密码" show-password />
<el-button class="login-btn" type="primary" @click="login">登录</el-button> <el-button class="login-btn" type="primary" @click="login">登录</el-button>
@@ -49,53 +61,63 @@
<el-button class="login-btn" type="primary" @click="guestlogin">游客临时登录</el-button> --> <el-button class="login-btn" type="primary" @click="guestlogin">游客临时登录</el-button> -->
</template> </template>
<script setup> <script setup>
import { reactive } from 'vue'; import { ref, reactive } from "vue";
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from "vue-router";
import useUserStore from '@/stores/user.js' import useUserStore from "@/stores/user.js";
import useConfigStore from "@/stores/config"; import useConfigStore from "@/stores/config";
const configStore= useConfigStore(); import useAuths from "@/hooks/useAuths";
const configStore = useConfigStore();
const userStore = useUserStore(); const userStore = useUserStore();
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const { loginFun } = useAuths();
const loginFormRef = ref();
const rules = reactive({ const rules = reactive({
userName: [ userName: [{ required: true, message: "请输入账号名", trigger: "blur" }],
{ required: true, message: '请输入账号名', trigger: 'blur' }, password: [{ required: true, message: "请输入密码", trigger: "blur" }],
{ min: 3, message: '至少大于等于3位', trigger: 'blur' }, });
],
password:[
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 3, message: '至少大于等于6位', trigger: 'blur' },
]})
const loginForm = reactive({ const loginForm = reactive({
userName: "cc", userName: "cc",
password: "123456", password: "123456",
uuid: "", uuid: "",
code: "" code: "",
}) });
const guestlogin = async () => { const guestlogin = async () => {
loginForm.userName = "guest"; loginForm.userName = "guest";
loginForm.password = "123456" loginForm.password = "123456";
await userStore.login(loginForm); await userStore.login(loginForm);
const redirect = route.query?.redirect ?? '/index' const redirect = route.query?.redirect ?? "/index";
router.push(redirect) router.push(redirect);
} };
const login = async () => { const login = async (formEl) => {
const response = await userStore.login(loginForm).catch((e) => { if (!formEl) return;
loginForm.password = ""; await formEl.validate((valid) => {
}); if (valid) {
if (response!=undefined) { try {
loginFun(loginForm);
} catch (error) {
ElMessage({ ElMessage({
message: `您好${loginForm.userName},登录成功!`, message: error.message,
type: 'success', type: "error",
}) duration: 2000,
});
const redirect = route.query?.redirect ?? '/index' }
router.push(redirect)
} }
});
// const response = await userStore.login(loginForm).catch((e) => {
// loginForm.password = "";
// });
// if (response != undefined) {
// ElMessage({
// message: `您好${loginForm.userName},登录成功!`,
// type: "success",
// });
} // const redirect = route.query?.redirect ?? "/index";
// router.push(redirect);
// }
};
</script> </script>
<style src="@/assets/styles/login.scss" scoped></style> <style src="@/assets/styles/login.scss" scoped></style>

View File

@@ -3,7 +3,7 @@
// 分页查询 // 分页查询
export function listData(query) { export function listData(query) {
return request({ return request({
url: '/article/pageList', url: '/article',
method: 'get', method: 'get',
params: query params: query
}) })
@@ -12,7 +12,7 @@ export function listData(query) {
// id查询 // id查询
export function getData(code) { export function getData(code) {
return request({ return request({
url: '/article/getById/' + code, url: '/article/' + code,
method: 'get' method: 'get'
}) })
} }
@@ -20,7 +20,7 @@ export function getData(code) {
// 新增 // 新增
export function addData(data) { export function addData(data) {
return request({ return request({
url: '/article/add', url: '/article',
method: 'post', method: 'post',
data: data data: data
}) })
@@ -29,17 +29,17 @@ export function addData(data) {
// 修改 // 修改
export function updateData(data) { export function updateData(data) {
return request({ return request({
url: '/article/update', url: `/article/${data.id}`,
method: 'put', method: 'put',
data: data data: data
}) })
} }
// 删除 // 删除
export function delData(code) { export function delData(ids) {
return request({ return request({
url: '/article/delList', url: '/article',
method: 'delete', method: 'delete',
data:"string"==typeof(code)?[code]:code params:{id:ids}
}) })
} }

View File

@@ -0,0 +1,47 @@
import request from '@/utils/request'
/* 以下为api的模板通用的crud将以下变量替换即可
plate : 实体模型
*/
// 分页查询
export function listData(query) {
return request({
url: '/plate',
method: 'get',
params: query
})
}
// id查询
export function getData(id) {
return request({
url: `/plate/${id}`,
method: 'get'
})
}
// 新增
export function addData(data) {
return request({
url: '/plate',
method: 'post',
data: data
})
}
// 修改
export function updateData(id,data) {
return request({
url: `/plate/${id}`,
method: 'put',
data: data
})
}
// 删除
export function delData(ids) {
return request({
url: `/plate`,
method: 'delete',
params:{id:ids}
})
}

View File

@@ -40,7 +40,8 @@ export function updateData(id,data) {
// 删除 // 删除
export function delData(ids) { export function delData(ids) {
return request({ return request({
url: `/@model@/${ids}`, url: `/@model@`,
method: 'delete', method: 'delete',
params:{id:ids}
}) })
} }

View File

@@ -0,0 +1,282 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="板块名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入板块名称" clearable style="width: 240px"
@keyup.enter="handleQuery" prop="name" />
</el-form-item>
<el-form-item label="板块编号" prop="code">
<el-input v-model="queryParams.code" placeholder="请输入板块编号" clearable style="width: 240px"
@keyup.enter="handleQuery" prop="code" />
</el-form-item>
<el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
placeholder="状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['bbs:plate:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
v-hasPermi="['bbs:plate:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
v-hasPermi="['bbs:plate:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['bbs:plate:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-----------------------这里开始就是数据表单的全部列------------------------>
<el-table-column label="板块编号" align="center" prop="code" />
<el-table-column label="板块名称" align="center" prop="name" :show-overflow-tooltip="true" />
<!-- <el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true" /> -->
<!-- <el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag
:options="sys_normal_disable"
:value="scope.row.isDeleted"
/>
</template>
</el-table-column> -->
<el-table-column
label="简介"
align="center"
prop="introduction"
:show-overflow-tooltip="true"
/>
<el-table-column
label="创建时间"
align="center"
prop="creationTime"
width="180"
>
<template #default="scope">
<span>{{ parseTime(scope.row.creationTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button type="text" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['bbs:plate:edit']">修改</el-button>
<el-button type="text" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['bbs:plate:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="Number(total)" v-model:page="queryParams.skipCount"
v-model:limit="queryParams.maxResultCount" @pagination="getList" />
<!-- ---------------------这里是新增和更新的对话框--------------------- -->
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
<el-form ref="dataRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="板块编码" prop="code">
<el-input v-model="form.code" placeholder="请输入板块编码" />
</el-form-item>
<el-form-item label="板块名称" prop="name">
<el-input v-model="form.name" placeholder="请输入板块名称" />
</el-form-item>
<el-form-item label="板块Logo" prop="logo">
<el-input v-model="form.logo" placeholder="请输入板块图片连接" />
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="JSON.parse(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item> -->
<el-form-item label="简介" prop="introduction">
<el-input v-model="form.introduction" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {
listData,
getData,
delData,
addData,
updateData,
} from "@/api/bbs/plateApi";
import { ref } from "@vue/reactivity";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const dataList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const dateRange = ref([]);
const data = reactive({
form: {},
queryParams: {
skipCount: 1,
maxResultCount: 10,
name: undefined,
code: undefined,
},
rules: {
code: [{ required: true, message: "板块编号不能为空", trigger: "blur" }],
name: [{ required: true, message: "板块名称不能为空", trigger: "blur" }],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询列表 */
function getList() {
loading.value = true;
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
dataList.value = response.data.items;
total.value = response.data.totalCount;
loading.value = false;
}
);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.skipCount = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加板块";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改板块";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate((valid) => {
if (valid) {
if (form.value.id != undefined) {
updateData(form.value.id, form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const delIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除编号为"' + delIds + '"的数据项?')
.then(function () {
return delData(delIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => { });
}
/** 导出按钮操作 */
function handleExport() { }
getList();
</script>

View File

@@ -92,11 +92,11 @@
<el-table-column <el-table-column
label="创建时间" label="创建时间"
align="center" align="center"
prop="createTime" prop="creationTime"
width="180" width="180"
> >
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.creationTime) }}</span>
</template> </template>
</el-table-column> --> </el-table-column> -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">