mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-04-20 05:02:50 +08:00
parent
1743f4ff28
commit
2f300285aa
@ -15,7 +15,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.11.20">
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.12.19">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
@ -38,7 +38,9 @@ public sealed record DynamicFilterInfo : DataAbstraction
|
||||
public static implicit operator FreeSql.Internal.Model.DynamicFilterInfo(DynamicFilterInfo d)
|
||||
{
|
||||
var ret = d.Adapt<FreeSql.Internal.Model.DynamicFilterInfo>();
|
||||
ProcessDynamicFilter(ret);
|
||||
#pragma warning disable VSTHRD002
|
||||
ProcessDynamicFilterAsync(ret).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#pragma warning restore VSTHRD002
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -79,35 +81,27 @@ public sealed record DynamicFilterInfo : DataAbstraction
|
||||
return !condition ? this : Add(df);
|
||||
}
|
||||
|
||||
private static void ParseDateExp(FreeSql.Internal.Model.DynamicFilterInfo d)
|
||||
private static async Task ParseDateExpAsync(FreeSql.Internal.Model.DynamicFilterInfo d)
|
||||
{
|
||||
var values = ((JsonElement)d.Value).Deserialize<string[]>();
|
||||
if (!DateTime.TryParse(values[0], CultureInfo.InvariantCulture, out _)) {
|
||||
var result = values[0]
|
||||
.ExecuteCSharpCodeAsync<DateTime>([typeof(DateTime).Assembly], nameof(System))
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
var result = await values[0].ExecuteCSharpCodeAsync<DateTime>([typeof(DateTime).Assembly], nameof(System)).ConfigureAwait(false);
|
||||
values[0] = $"{result:yyyy-MM-dd HH:mm:ss}";
|
||||
}
|
||||
|
||||
if (!DateTime.TryParse(values[1], CultureInfo.InvariantCulture, out _)) {
|
||||
var result = values[1]
|
||||
.ExecuteCSharpCodeAsync<DateTime>([typeof(DateTime).Assembly], nameof(System))
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
var result = await values[1].ExecuteCSharpCodeAsync<DateTime>([typeof(DateTime).Assembly], nameof(System)).ConfigureAwait(false);
|
||||
values[1] = $"{result:yyyy-MM-dd HH:mm:ss}";
|
||||
}
|
||||
|
||||
d.Value = values;
|
||||
}
|
||||
|
||||
private static void ProcessDynamicFilter(FreeSql.Internal.Model.DynamicFilterInfo d)
|
||||
private static async Task ProcessDynamicFilterAsync(FreeSql.Internal.Model.DynamicFilterInfo d)
|
||||
{
|
||||
if (d?.Filters != null) {
|
||||
foreach (var filterInfo in d.Filters) {
|
||||
ProcessDynamicFilter(filterInfo);
|
||||
await ProcessDynamicFilterAsync(filterInfo).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +113,7 @@ public sealed record DynamicFilterInfo : DataAbstraction
|
||||
}
|
||||
}
|
||||
else if (d?.Operator == DynamicFilterOperator.DateRange) {
|
||||
ParseDateExp(d);
|
||||
await ParseDateExpAsync(d).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,9 +3,9 @@
|
||||
<Import Project="$(SolutionDir)/build/copy.pkg.xml.comment.files.targets"/>
|
||||
<Import Project="$(SolutionDir)/build/prebuild.targets"/>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.833-ns5" Label="refs"/>
|
||||
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.833-ns5" Label="refs"/>
|
||||
<PackageReference Include="Gurion" Version="1.2.1" Label="refs"/>
|
||||
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.833-ns6" Label="refs"/>
|
||||
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.833-ns6" Label="refs"/>
|
||||
<PackageReference Include="Gurion" Version="1.2.2" Label="refs"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.12.0-3.final"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0"/>
|
||||
<PackageReference Include="Minio" Version="6.0.3"/>
|
||||
|
@ -16,7 +16,9 @@ public sealed class ApiIdAttribute : ValidationAttribute
|
||||
var req = new QueryReq<QueryApiReq> { Filter = new QueryApiReq { Id = value as string } };
|
||||
|
||||
var method = service.GetType().GetMethod("ExistAsync");
|
||||
var exist = ((Task<bool>)method!.Invoke(service, [req]))!.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#pragma warning disable VSTHRD002
|
||||
var exist = ((Task<bool>)method!.Invoke(service, [req]))!.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#pragma warning restore VSTHRD002
|
||||
return !exist ? new ValidationResult(Ln.接口编码不存在) : ValidationResult.Success;
|
||||
}
|
||||
}
|
@ -16,7 +16,9 @@ public sealed class UserIdAttribute : ValidationAttribute
|
||||
var req = new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = (long)value! } };
|
||||
|
||||
var method = service.GetType().GetMethod("ExistAsync");
|
||||
var exist = ((Task<bool>)method!.Invoke(service, [req]))!.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#pragma warning disable VSTHRD002
|
||||
var exist = ((Task<bool>)method!.Invoke(service, [req]))!.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#pragma warning restore VSTHRD002
|
||||
return !exist ? new ValidationResult(Ln.用户编号不存在) : ValidationResult.Success;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-if="loading" v-loading="true" style="height: 100%"></div>
|
||||
<el-main v-else>
|
||||
<widgets v-if="dashboard"></widgets>
|
||||
<el-main v-else :style="{ height: mainHeight }">
|
||||
<widgets v-if="dashboard" @on-customizing="onCustomizing"></widgets>
|
||||
<work v-else></work>
|
||||
</el-main>
|
||||
</template>
|
||||
@ -20,6 +20,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
mainHeight: 'auto',
|
||||
dashboard: false,
|
||||
}
|
||||
},
|
||||
@ -30,7 +31,11 @@ export default {
|
||||
this.loading = false
|
||||
},
|
||||
mounted() {},
|
||||
methods: {},
|
||||
methods: {
|
||||
onCustomizing(isCustomizing) {
|
||||
this.mainHeight = isCustomizing ? '100%' : 'auto'
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div :class="[{ active: active }]" @click="$emit('onSetLayout', realLayout)" class="selectLayout-item">
|
||||
<el-row v-for="l in layout.split('-')" :gutter="2">
|
||||
<el-col v-for="span in l.split(',')" :span="Number(span) > 24 ? 24 : Number(span)"><span></span></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: ['active', 'layout'],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
realLayout() {
|
||||
return this.layout
|
||||
.replaceAll('-', ',')
|
||||
.split(',')
|
||||
.map((x) => Number(x))
|
||||
},
|
||||
},
|
||||
async created() {},
|
||||
mounted() {},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.selectLayout-item {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
border: 0.2rem solid var(--el-border-color-light);
|
||||
padding: 0.4rem;
|
||||
cursor: pointer;
|
||||
margin-right: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.selectLayout-item .el-row {
|
||||
height: 3.6rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.selectLayout-item span {
|
||||
display: block;
|
||||
background: var(--el-border-color-light);
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:only-child) span {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:nth-child(2)):not(:has(:nth-child(3))) > span {
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:nth-child(3)):not(:has(:nth-child(4))) > span {
|
||||
height: 33.3%;
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:nth-child(4)):not(:has(:nth-child(5))) > span {
|
||||
height: 25%;
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:nth-child(5)):not(:has(:nth-child(6))) > span {
|
||||
height: 20%;
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:nth-child(6)):not(:has(:nth-child(7))) > span {
|
||||
height: 16.7%;
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:nth-child(7)):not(:has(:nth-child(8))) > span {
|
||||
height: 14.3%;
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:nth-child(8)):not(:has(:nth-child(9))) > span {
|
||||
height: 12.5%;
|
||||
}
|
||||
|
||||
.selectLayout-item:has(:nth-child(9)):not(:has(:nth-child(10))) > span {
|
||||
height: 11.1%;
|
||||
}
|
||||
|
||||
.selectLayout-item:hover {
|
||||
border-color: var(--na-color-primary);
|
||||
}
|
||||
|
||||
.selectLayout-item.active {
|
||||
border-color: var(--na-color-primary);
|
||||
}
|
||||
|
||||
.selectLayout-item.active span {
|
||||
background: var(--na-color-primary);
|
||||
}
|
||||
</style>
|
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<sc-dialog v-model="visible" :title="`${title}`" @closed="$emit('closed')" destroy-on-close>
|
||||
<el-form :model="form" ref="form">
|
||||
<el-form-item
|
||||
v-for="(row, index) in form.rows"
|
||||
:label="`第${index + 1}行`"
|
||||
:prop="'rows.' + index + '.value'"
|
||||
:rules="{
|
||||
required: true,
|
||||
message: '请输入以空格分隔的24分栏布局:如【24】或【12 12】或【8 8 8】',
|
||||
trigger: 'blur',
|
||||
}">
|
||||
<el-input
|
||||
v-model="form.rows[index].value"
|
||||
:input="(form.rows[index].value = form.rows[index].value.replace(/[^0-9 ]/g, ''))"
|
||||
placeholder="请输入以空格分隔的24分栏布局:如【24】或【12 12】或【8 8 8】">
|
||||
<template #append>
|
||||
<el-button @click.prevent="form.rows.splice(index, 1)" icon="delete">删除</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="this.form.rows.push({ value: '' })">{{ $t('添加一行') }}</el-button>
|
||||
<el-button @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
title: '添加自定义布局',
|
||||
visible: false,
|
||||
form: {
|
||||
rows: [{ value: '' }],
|
||||
},
|
||||
}
|
||||
},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
async open({ title }) {
|
||||
this.visible = true
|
||||
this.title = title
|
||||
|
||||
return this
|
||||
},
|
||||
async submit() {
|
||||
const valid = await this.$refs.form.validate().catch(() => {})
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
this.form.rows.forEach((r) => {
|
||||
r.value = r.value
|
||||
.split(' ')
|
||||
.map((x) => x.trim())
|
||||
.filter((x) => x !== '')
|
||||
.join(',')
|
||||
})
|
||||
|
||||
let l = this.form.rows.map((x) => x.value).join('-')
|
||||
if (l !== '') {
|
||||
this.$emit('onCustomLayout', l)
|
||||
}
|
||||
this.visible = false
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -64,42 +64,21 @@
|
||||
</el-header>
|
||||
<el-header style="height: auto">
|
||||
<div class="selectLayout">
|
||||
<div :class="{ active: grid.layout.join(',') === '12,6,6' }" @click="setLayout([12, 6, 6])" class="selectLayout-item item01">
|
||||
<el-row :gutter="2">
|
||||
<el-col :span="12"><span></span></el-col>
|
||||
<el-col :span="6"><span></span></el-col>
|
||||
<el-col :span="6"><span></span></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div
|
||||
:class="{ active: grid.layout.join(',') === '24,12,12' }"
|
||||
@click="setLayout([24, 12, 12])"
|
||||
class="selectLayout-item item02">
|
||||
<el-row :gutter="2">
|
||||
<el-col :span="24"><span></span></el-col>
|
||||
<el-col :span="12"><span></span></el-col>
|
||||
<el-col :span="12"><span></span></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div
|
||||
:class="{ active: grid.layout.join(',') === '24,16,8' }"
|
||||
@click="setLayout([24, 16, 8])"
|
||||
class="selectLayout-item item02">
|
||||
<el-row :gutter="2">
|
||||
<el-col :span="24"><span></span></el-col>
|
||||
<el-col :span="16"><span></span></el-col>
|
||||
<el-col :span="8"><span></span></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div :class="{ active: grid.layout.join(',') === '24' }" @click="setLayout([24])" class="selectLayout-item item03">
|
||||
<el-row :gutter="2">
|
||||
<el-col :span="24"><span></span></el-col>
|
||||
<el-col :span="24"><span></span></el-col>
|
||||
<el-col :span="24"><span></span></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<layout
|
||||
v-for="l in layouts"
|
||||
:active="grid.layout.join(',') === l.replaceAll('-', ',')"
|
||||
:layout="l"
|
||||
@onSetLayout="setLayout"></layout>
|
||||
<layout
|
||||
v-for="l in customLayouts"
|
||||
:active="grid.layout.join(',') === l.replaceAll('-', ',')"
|
||||
:layout="l"
|
||||
@onSetLayout="setLayout"></layout>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-header style="height: auto">
|
||||
<el-button @click="this.dialog.customLayout = { title: '添加自定义布局' }" style="margin: 0 auto">添加自定义布局</el-button>
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<div class="widgets-list">
|
||||
<div v-if="myCompsList.length <= 0" class="widgets-list-nodata">
|
||||
@ -129,17 +108,30 @@
|
||||
</div>
|
||||
|
||||
<div @click="custom" class="layout-setting">
|
||||
<el-icon><el-icon-setting /></el-icon>
|
||||
<el-icon>
|
||||
<el-icon-setting />
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<custom-layout-dialog
|
||||
v-if="dialog.customLayout"
|
||||
@closed="dialog.customLayout = null"
|
||||
@mounted="$refs.customLayoutDialog.open(dialog.customLayout)"
|
||||
@onCustomLayout="(l) => (customLayouts = [l])"
|
||||
ref="customLayoutDialog"></custom-layout-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import allComps from './components'
|
||||
import customLayoutDialog from './dialog/custom-layout-dialog.vue'
|
||||
import layout from './components/components/layout.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
draggable,
|
||||
customLayoutDialog,
|
||||
layout,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -148,6 +140,9 @@ export default {
|
||||
selectLayout: [],
|
||||
defaultGrid: this.$CONFIG.APP_SET_HOME_GRID,
|
||||
grid: [],
|
||||
layouts: ['12,6,6', '24-12,12', '24-16,8', '24-24-24'],
|
||||
customLayouts: [],
|
||||
dialog: {},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -197,16 +192,23 @@ export default {
|
||||
methods: {
|
||||
//开启自定义
|
||||
custom() {
|
||||
this.customizing = true
|
||||
this.customizing = !this.customizing
|
||||
const oldWidth = this.$refs.widgets.offsetWidth
|
||||
this.$nextTick(() => {
|
||||
const scale = this.$refs.widgets.offsetWidth / oldWidth
|
||||
this.$refs.widgets.style.setProperty('transform', `scale(${scale})`)
|
||||
this.$refs.widgets.style.setProperty('transform', `scale(${this.customizing ? scale : 1})`)
|
||||
})
|
||||
this.$emit('on-customizing', this.customizing)
|
||||
},
|
||||
//设置布局
|
||||
setLayout(layout) {
|
||||
this.grid.layout = layout
|
||||
|
||||
// 初始化
|
||||
layout.forEach((_, i) => {
|
||||
if (!this.grid.compsList[i]) this.grid.compsList[i] = []
|
||||
})
|
||||
|
||||
if (layout.join(',') === '24') {
|
||||
this.grid.compsList[0] = [...this.grid.compsList[0], ...this.grid.compsList[1], ...this.grid.compsList[2]]
|
||||
this.grid.compsList[1] = []
|
||||
@ -230,6 +232,7 @@ export default {
|
||||
this.customizing = false
|
||||
this.$refs.widgets.style.removeProperty('transform')
|
||||
this.$TOOL.data.set('APP_SET_HOME_GRID', this.grid)
|
||||
this.$emit('on-customizing', this.customizing)
|
||||
},
|
||||
//恢复默认
|
||||
backDefault() {
|
||||
@ -237,12 +240,14 @@ export default {
|
||||
this.$refs.widgets.style.removeProperty('transform')
|
||||
this.grid = JSON.parse(JSON.stringify(this.defaultGrid))
|
||||
this.$TOOL.data.remove('APP_SET_HOME_GRID')
|
||||
this.$emit('on-customizing', this.customizing)
|
||||
},
|
||||
//关闭
|
||||
close() {
|
||||
this.customizing = false
|
||||
this.$refs.widgets.style.removeProperty('transform')
|
||||
this.loadGrid()
|
||||
this.$emit('on-customizing', this.customizing)
|
||||
},
|
||||
loadGrid() {
|
||||
this.grid = this.$TOOL.data.get('APP_SET_HOME_GRID') || JSON.parse(JSON.stringify(this.defaultGrid))
|
||||
@ -436,47 +441,6 @@ export default {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.selectLayout-item {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
border: 0.2rem solid var(--el-border-color-light);
|
||||
padding: 0.4rem;
|
||||
cursor: pointer;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.selectLayout-item span {
|
||||
display: block;
|
||||
background: var(--el-border-color-light);
|
||||
height: 3.6rem;
|
||||
}
|
||||
|
||||
.selectLayout-item.item02 span {
|
||||
height: 2.4rem;
|
||||
}
|
||||
|
||||
.selectLayout-item.item02 .el-col:nth-child(1) span {
|
||||
height: 1.1rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.selectLayout-item.item03 span {
|
||||
height: 1.1rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.selectLayout-item:hover {
|
||||
border-color: var(--na-color-primary);
|
||||
}
|
||||
|
||||
.selectLayout-item.active {
|
||||
border-color: var(--na-color-primary);
|
||||
}
|
||||
|
||||
.selectLayout-item.active span {
|
||||
background: var(--na-color-primary);
|
||||
}
|
||||
|
||||
.dark {
|
||||
.widgets-aside {
|
||||
background: #2b2b2b;
|
||||
|
Loading…
x
Reference in New Issue
Block a user