Merge branch 'furion' of https://gitee.com/ccnetcore/Yi into furion
This commit is contained in:
49
README.md
49
README.md
@@ -30,20 +30,43 @@ Yi框架最新版本标签:`v3.0.0`,具体版本可以查看标签迭代
|
||||
|
||||
**分支:**
|
||||
|
||||
(本项目由EFCore版本历经3年不断迭代至Sqlsugar版本,现EFcore版本已弃用,目前sqlsugar已带业务功能)
|
||||
(本项目由EFCore版本历经4年不断迭代至Sqlsugar版本,现EFcore版本已弃用,目前sqlsugar已带业务功能)
|
||||
|
||||
- **Framework**: 框架分支,所有东西都在这里
|
||||
- (推荐) **Furion**: 基于Furion分支,回归开发本质,极度简单,用起来贼爽
|
||||
|
||||
- **Furion**: 基于Furion分支,回归开发本质,极度简单,用起来贼爽
|
||||
- ~~**Framework**~~: 框架分支,所有东西都在这里
|
||||
|
||||
- ~~**SqlSugar**:.Net6 DDD领域驱动设计 简单分层微服务架构~~
|
||||
|
||||
- ~~**SqlSugar-Dev**:为sqlsugar分支的实时开发版本~~
|
||||
|
||||
- ~~**ec**: EFcore完整电商项目~~
|
||||
- ~~**abp**:基于abp.vnext项目~~
|
||||
|
||||
****
|
||||
|
||||
**目录:**
|
||||
|
||||
Yi后端框架分为3个部分:
|
||||
|
||||
- Infrastructure(基础设施,框架底层+sqlsugar+furion)
|
||||
- Module(应用模块,可选项,例如缓存模块、微信模块、文件模块、日志模块等)
|
||||
- Application(业务模块,用于开发)
|
||||
|
||||
另外,光说不练假把式,我们不仅仅提供一个空白的框架,还同时提供3个基于yi框架的业务模块,没有听错,目前为1个后端,支持3个前端。各个模块关系解耦,可单独使用其中的任意业务模块
|
||||
|
||||
- Yi.RuoYi.Vue3:Ruoyi后台管理系统Rbac Vue3前端(推荐)
|
||||
|
||||
- Yi.Furion.Net6:.NET6后端(推荐)
|
||||
|
||||
- Yi.App.Vue3:移动端App Vue3前端
|
||||
|
||||
- Yi.BBS.Vue3:Web网页端BBS论坛 Vue3+Ts前端
|
||||
|
||||
后续我们持续更新各大应用模块及业务模块:shop商场、erp进销存、mes工厂系统等
|
||||
|
||||
业务支持并扩展至各个领域,用于具体项目的二次开发极大复用后端代码及前端代码,以通用的部分+不通的部分快速二开
|
||||
|
||||
|
||||
### 演示地址:
|
||||
|
||||
废话少说直接上地址,**请不要**更改里面的数据
|
||||
@@ -54,14 +77,15 @@ Bbs社区系统:[ccnetcore.com](https://ccnetcore.com) (已上线,欢迎加
|
||||
|
||||
Rbac后台管理系统:[yi.ccnetcore.com](http://yi.ccnetcore.com) (已上线)~~管理员账号:cc 、 123456~~
|
||||
|
||||
网关地址:~~[gate.ccnetcore.com/swagger](http://gate.ccnetcore.com/swagger)~~(目前使用单体架构)
|
||||
App移动端系统:[xxx](xxx)正在部署
|
||||
|
||||
网关地址:~~[gate.ccnetcore.com/swagger](http://gate.ccnetcore.com/swagger)~~(目前使用单体架构部署,无需网关)
|
||||
|
||||
### 支持:
|
||||
|
||||
- [x] 完全支持单体应用架构
|
||||
- [x] 完全支持分布式应用架构
|
||||
- [x] 完全支持微服务架构
|
||||
- [ ] 即将支持网格服务架构(我们将在后续版本加入dapr)
|
||||
|
||||
****
|
||||
### 详细到爆炸的Yi框架教程导航:
|
||||
@@ -125,11 +149,12 @@ Rbac后台管理系统:[yi.ccnetcore.com](http://yi.ccnetcore.com) (已上
|
||||
- 操作日志管理
|
||||
- Sms短信
|
||||
- 微信支付
|
||||
- 模板代码生成
|
||||
- WebFirst代码生成
|
||||
|
||||
### 业务项目
|
||||
- RABC后台管理系统
|
||||
- BBS社区系统
|
||||
- APP移动端系统
|
||||
|
||||
> 重复的东西,无需再写一遍,这也是优雅的体现之一
|
||||
|
||||
@@ -184,7 +209,7 @@ RABC权限管理系统(正在更新)
|
||||
- 定时任务
|
||||
- 缓存列表
|
||||
- 服务监控
|
||||
- 等等
|
||||
- WebFirst代码生成工具
|
||||
|
||||
**演示截图:**
|
||||

|
||||
@@ -197,6 +222,8 @@ RABC权限管理系统(正在更新)
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
BBS论坛系统(持续迭代)
|
||||
- 文章管理
|
||||
@@ -206,7 +233,11 @@ BBS论坛系统(持续迭代)
|
||||
- 点赞管理
|
||||
- 等等
|
||||
|
||||
ERP进销存系统(正在更新)
|
||||
APP移动端系统(持续迭代)
|
||||
- 动态查询
|
||||
- 我的资料
|
||||
|
||||
ERP进销存系统(持续迭代)
|
||||
- 供货商管理
|
||||
- 等等
|
||||
|
||||
|
||||
19
Yi.App.Vue3/components.d.ts
vendored
19
Yi.App.Vue3/components.d.ts
vendored
@@ -14,14 +14,33 @@ declare module '@vue/runtime-core' {
|
||||
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
VanActionBar: typeof import('vant/es')['ActionBar']
|
||||
VanActionBarButton: typeof import('vant/es')['ActionBarButton']
|
||||
VanActionBarIcon: typeof import('vant/es')['ActionBarIcon']
|
||||
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
||||
VanButton: typeof import('vant/es')['Button']
|
||||
VanCell: typeof import('vant/es')['Cell']
|
||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||
VanCol: typeof import('vant/es')['Col']
|
||||
VanDivider: typeof import('vant/es')['Divider']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
VanGrid: typeof import('vant/es')['Grid']
|
||||
VanGridItem: typeof import('vant/es')['GridItem']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanImage: typeof import('vant/es')['Image']
|
||||
VanList: typeof import('vant/es')['List']
|
||||
VanLoading: typeof import('vant/es')['Loading']
|
||||
VanNavBar: typeof import('vant/es')['NavBar']
|
||||
VanPopup: typeof import('vant/es')['Popup']
|
||||
VanPullRefresh: typeof import('vant/es')['PullRefresh']
|
||||
VanRow: typeof import('vant/es')['Row']
|
||||
VanSticky: typeof import('vant/es')['Sticky']
|
||||
VanSwipe: typeof import('vant/es')['Swipe']
|
||||
VanSwipeItem: typeof import('vant/es')['SwipeItem']
|
||||
VanTab: typeof import('vant/es')['Tab']
|
||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||
VanTabs: typeof import('vant/es')['Tabs']
|
||||
VanUploader: typeof import('vant/es')['Uploader']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import myaxios from '@/utils/myaxios'
|
||||
import { ArticleEntity } from '@/type/interface/ArticleEntity'
|
||||
|
||||
export default {
|
||||
add(data:any) {
|
||||
return myaxios({
|
||||
url: `/article/add`,
|
||||
url: `/Trends`,
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
},
|
||||
pageList(data:any) {
|
||||
return myaxios({
|
||||
url: '/article/pageList',
|
||||
url: '/Trends',
|
||||
method: 'get',
|
||||
params: data
|
||||
})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import myaxios from '@/utils/myaxios'
|
||||
|
||||
export default{
|
||||
upload(type:string,data:any){
|
||||
upload(data:any){
|
||||
return myaxios({
|
||||
url: `/file/upload/${type}`,
|
||||
url: `/file`,
|
||||
headers:{"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"},
|
||||
method: 'POST',
|
||||
method: 'post',
|
||||
data:data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export function register(data:any) {
|
||||
// 获取用户详细信息
|
||||
export function getInfo() {
|
||||
return myaxios({
|
||||
url: '/account/getUserAllInfo',
|
||||
url: '/account',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import router from './router'
|
||||
// import 'nprogress/nprogress.css'
|
||||
import { getToken } from '@/utils/auth'
|
||||
// import { isHttp } from '@/utils/validate'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import useUserStore from '@/store/modules/user.js'
|
||||
import { isRelogin } from '@/utils/myaxios'
|
||||
// import useSettingsStore from '@/store/modules/settings'
|
||||
// import usePermissionStore from '@/store/modules/permission'
|
||||
|
||||
@@ -21,21 +21,23 @@ const useUserStore = defineStore(
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
login(username, password, code, uuid).then(res => {
|
||||
if(!res.status)
|
||||
if(!(res as any).succeeded)
|
||||
{
|
||||
reject(res)
|
||||
}
|
||||
setToken(res.data.token);
|
||||
this.token = res.data.token;
|
||||
resolve(res);
|
||||
|
||||
return resolve(res);
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
return reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 获取用户信息
|
||||
getInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
getInfo().then(response => {
|
||||
const res=response.data;
|
||||
const user = res.user
|
||||
|
||||
@@ -5,7 +5,7 @@ import axios from 'axios'
|
||||
import JsonBig from 'json-bigint'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { useRouter } from "vue-router";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import useUserStore from '@/store/modules/user.js'
|
||||
import { Notify } from 'vant';
|
||||
// import VuetifyDialogPlugin from 'vuetify-dialog/nuxt/index';
|
||||
export let isRelogin = { show: false };
|
||||
@@ -20,8 +20,14 @@ const myaxios = axios.create({
|
||||
transformResponse: [data => {
|
||||
const json = JsonBig({
|
||||
storeAsString: true
|
||||
})
|
||||
return json.parse(data)
|
||||
});
|
||||
try {
|
||||
return json.parse(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return data;
|
||||
}
|
||||
}],
|
||||
})
|
||||
// 请求拦截器
|
||||
@@ -53,18 +59,25 @@ myaxios.interceptors.response.use(async function(response) {
|
||||
}
|
||||
// store.dispatch("closeLoad");
|
||||
return resp;
|
||||
}, async function(error) {
|
||||
},
|
||||
async function(error) {
|
||||
const code=error.response.status;
|
||||
const message=error.message;
|
||||
//未授权、失败
|
||||
if(error.response==undefined)
|
||||
{
|
||||
Notify({ type: 'danger', message: `服务器异常:${error.message}` });
|
||||
|
||||
// useUserStore().logOut().then(() => {
|
||||
// location.href = '/';
|
||||
// })
|
||||
|
||||
return Promise.reject(error);;
|
||||
}
|
||||
|
||||
const resp = error.response.data
|
||||
if (resp.code == undefined && resp.message == undefined) {
|
||||
if (code == undefined &&message == undefined) {
|
||||
Notify({ type: 'danger', message: '未知错误' });
|
||||
} else if (resp.code == 401) {
|
||||
} else if (code == 401) {
|
||||
// if (!isRelogin.show) {
|
||||
Notify({ type: 'warning', message: '登录过期' });
|
||||
//登出
|
||||
@@ -73,9 +86,10 @@ if (resp.code == undefined && resp.message == undefined) {
|
||||
})
|
||||
isRelogin.show = false;
|
||||
// }
|
||||
} else if (resp.code !== 200) {
|
||||
Notify({ type: 'danger', message: `错误代码:${resp.code},原因:${resp.message}` });
|
||||
} else if (code !== 200) {
|
||||
Notify({ type: 'danger', message: `错误代码:${code},原因:${message}` });
|
||||
}
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
export default myaxios
|
||||
@@ -36,8 +36,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import useUserStore from "@/store/modules/user";
|
||||
import useUserStore from "@/store/modules/user.js";
|
||||
import { Toast } from "vant";
|
||||
import { debug } from "console";
|
||||
|
||||
const router = useRouter();
|
||||
const redirect = ref(undefined);
|
||||
@@ -55,15 +56,16 @@ const login = () => {
|
||||
.login(loginForm.value)
|
||||
.then((response: any) => {
|
||||
Toast({
|
||||
message: response.message,
|
||||
message: "登录成功",
|
||||
position: "bottom",
|
||||
});
|
||||
|
||||
router.push({ path: redirect.value || "/" });
|
||||
})
|
||||
.catch((response:any) => {
|
||||
loginForm.value.password="";
|
||||
Toast({
|
||||
message: response.message,
|
||||
message: response.errors,
|
||||
position: "bottom",
|
||||
});
|
||||
// loading.value = false;
|
||||
|
||||
@@ -58,10 +58,15 @@
|
||||
text="评论"
|
||||
@click="openComment(item.id)"
|
||||
/>
|
||||
<van-grid-item
|
||||
<!-- <van-grid-item
|
||||
icon="good-job-o"
|
||||
:text="`点赞:${item.agreeNum}`"
|
||||
@click="aggreeHand(item.id)"
|
||||
/> -->
|
||||
<van-grid-item
|
||||
icon="good-job-o"
|
||||
:text="`点赞:10`"
|
||||
@click="aggreeHand(item.id)"
|
||||
/>
|
||||
</van-grid>
|
||||
</van-col>
|
||||
@@ -113,7 +118,6 @@ import AppUserIcon from "@/components/AppUserIcon.vue";
|
||||
import articleApi from "@/api/articleApi";
|
||||
import agreeApi from "@/api/agreeApi";
|
||||
import commentApi from "@/api/commentApi";
|
||||
import { ArticleEntity } from "@/type/interface/ArticleEntity";
|
||||
const VanImagePreview = ImagePreview.Component;
|
||||
const url = `${import.meta.env.VITE_APP_BASE_API}/file/`;
|
||||
const data = reactive({
|
||||
@@ -174,19 +178,17 @@ const onLoad = async () => {
|
||||
// 异步更新数据
|
||||
// setTimeout 仅做示例,真实场景中一般为 ajax 请求
|
||||
articleApi.pageList(queryParams.value).then((response: any) => {
|
||||
if (response.data.data.length == 0) {
|
||||
if (response.data.items.length == 0) {
|
||||
console.log("结束");
|
||||
finished.value = true;
|
||||
} else {
|
||||
console.log("执行");
|
||||
articleList.value.push(...response.data.data);
|
||||
articleList.value.push(...response.data.items);
|
||||
totol.value = response.data.totol;
|
||||
queryParams.value.pageNum += 1;
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
|
||||
console.log(loading.value);
|
||||
});
|
||||
};
|
||||
const onRefresh = () => {
|
||||
|
||||
@@ -93,7 +93,7 @@ import AppGrid from "@/components/AppGrid.vue";
|
||||
import { AppGridData } from "@/type/class/AppGridData";
|
||||
import { ref } from "vue";
|
||||
import { Dialog } from "vant";
|
||||
import useUserStore from "@/store/modules/user";
|
||||
import useUserStore from "@/store/modules/user.js";
|
||||
import { storeToRefs } from 'pinia';
|
||||
import AppUserIcon from "@/components/AppUserIcon.vue";
|
||||
const show = ref<boolean>(false);
|
||||
|
||||
@@ -97,8 +97,8 @@ const afterRead = (file: any) => {
|
||||
});
|
||||
}
|
||||
|
||||
fileApi.upload("image", formData).then((response: any) => {
|
||||
images.value.push(...response.data);
|
||||
fileApi.upload(formData).then((response: any) => {
|
||||
images.value.push(...response.data.map((x:any)=>x.id));
|
||||
|
||||
if (file.length == undefined) {
|
||||
file.status = "done";
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/store/modules/user.ts", "src/utils/myaxios.ts"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
||||
@@ -43,18 +43,19 @@ myaxios.interceptors.response.use(function (response) {
|
||||
}
|
||||
return response.data;
|
||||
}, function (error) {
|
||||
const response=error.response.data;
|
||||
const code = error.response.status;
|
||||
const msg = error.message;
|
||||
//业务异常+应用异常,统一处理
|
||||
switch(response.code)
|
||||
switch(code)
|
||||
{
|
||||
case 401:
|
||||
ElMessage.error('登录已过期')
|
||||
break;
|
||||
case 403:
|
||||
ElMessage.error(response.message)
|
||||
ElMessage.error(msg)
|
||||
break;
|
||||
case 500:
|
||||
ElMessage.error(response.message)
|
||||
ElMessage.error(msg)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Yi.Furion.Application.App.Services.Impl
|
||||
/// <summary>
|
||||
/// Trends服务实现
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings("App")]
|
||||
[ApiDescriptionSettings("APP")]
|
||||
public class TrendsService : CrudAppService<TrendsEntity, TrendsGetOutputDto, TrendsGetListOutputDto, long, TrendsGetListInput, TrendsCreateInput, TrendsUpdateInputVo>,
|
||||
ITrendsService, IDynamicApiController, ITransient
|
||||
{
|
||||
@@ -27,8 +27,23 @@ namespace Yi.Furion.Application.App.Services.Impl
|
||||
|
||||
var entities = await _DbQueryable
|
||||
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
|
||||
.OrderByDescending(x=>x.CreationTime)
|
||||
.ToPageListAsync(input.PageNum, input.PageSize, total);
|
||||
return new PagedResultDto<TrendsGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布文章
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public override Task<TrendsGetOutputDto> CreateAsync(TrendsCreateInput input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input.Title))
|
||||
{
|
||||
input.Title = input.Content.Substring(0, Math.Min(5, input.Content.Length));
|
||||
}
|
||||
return base.CreateAsync(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Yi.Furion.Application.App.Services.Impl.TrendsService.CreateAsync(Yi.Furion.Core.App.Dtos.Trends.TrendsCreateInput)">
|
||||
<summary>
|
||||
发布文章
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:Yi.Furion.Application.App.Services.ITrendsService">
|
||||
<summary>
|
||||
Trends服务抽象
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Furion;
|
||||
using Furion.Schedule;
|
||||
using Furion.TimeCrontab;
|
||||
@@ -73,19 +72,7 @@ public class Startup : AppStartup
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseInject(string.Empty);
|
||||
}
|
||||
|
||||
private string ConverStr(string utf8mb3String)
|
||||
{
|
||||
// 将 utf8mb3String 转换为 UTF-8mb3 编码的字节数组
|
||||
byte[] utf8mb3Bytes = Encoding.UTF8.GetBytes(utf8mb3String);
|
||||
|
||||
// 将 UTF-8mb3 编码的字节数组转换为 UTF-8mb4 编码的字节数组
|
||||
byte[] utf8mb4Bytes = Encoding.Convert(Encoding.UTF8, new UTF8Encoding(true), utf8mb3Bytes);
|
||||
|
||||
// 将 UTF-8mb4 编码的字节数组转换为字符串
|
||||
string utf8mb4String = Encoding.UTF8.GetString(utf8mb4Bytes);
|
||||
return utf8mb4String;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
<Content Update="appsettings.Production.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\Image\1633441011139219456.jpg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
|
||||
@@ -24,7 +24,13 @@ const service = axios.create({
|
||||
const json = JsonBig({
|
||||
storeAsString: true
|
||||
})
|
||||
try {
|
||||
return json.parse(data)
|
||||
}
|
||||
catch
|
||||
{
|
||||
return data;
|
||||
}
|
||||
}],
|
||||
})
|
||||
|
||||
@@ -94,7 +100,7 @@ service.interceptors.response.use(res => {
|
||||
},
|
||||
error => {
|
||||
const code = error.response.status;
|
||||
const msg = error.response.data.message;
|
||||
const msg = error.message;
|
||||
handler(code, msg);
|
||||
}
|
||||
)
|
||||
|
||||
BIN
readme/1696760969217.jpg
Normal file
BIN
readme/1696760969217.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
BIN
readme/1696761014270.jpg
Normal file
BIN
readme/1696761014270.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
Reference in New Issue
Block a user