Browse Source

update

pull/1/head
wanggang 1 year ago
parent
commit
a20b6bdfcb
  1. 44
      docs/demo/src/WTA.Application/Identity/Data/IdentityDbSeed.cs
  2. 14
      docs/demo/src/WTA.Shared/Attributes/ManyToManyAttribute.cs
  3. 14
      docs/demo/src/WTA.Shared/Attributes/ManyToOneAttribute.cs
  4. 13
      docs/demo/src/WTA.Shared/Controllers/GenericController.cs
  5. 8
      docs/demo/src/WTA.Shared/Extensions/JsonSchemaExtensions.cs
  6. 7
      docs/demo/src/WTA/wwwroot/components/form/form-input.js
  7. 6
      docs/demo/src/WTA/wwwroot/components/form/form-item.js
  8. 5
      docs/demo/src/WTA/wwwroot/components/form/index.js
  9. 34
      docs/demo/src/WTA/wwwroot/components/icon/index.js
  10. 126
      docs/demo/src/WTA/wwwroot/components/list/index.js
  11. 36
      docs/demo/src/WTA/wwwroot/components/markdown/index.js
  12. 2
      docs/demo/src/WTA/wwwroot/index.html
  13. 13
      docs/demo/src/WTA/wwwroot/layouts/header.js
  14. 14
      docs/demo/src/WTA/wwwroot/layouts/index.js
  15. 7
      docs/demo/src/WTA/wwwroot/layouts/locale.js
  16. 9
      docs/demo/src/WTA/wwwroot/layouts/menu-item.js
  17. 19
      docs/demo/src/WTA/wwwroot/layouts/tabs.js
  18. 2
      docs/demo/src/WTA/wwwroot/main.js
  19. 2
      docs/demo/src/WTA/wwwroot/router/index.js
  20. 1
      docs/demo/src/WTA/wwwroot/store/app.js

44
docs/demo/src/WTA.Application/Identity/Data/IdentityDbSeed.cs

@ -119,18 +119,18 @@ public class IdentityDbSeed : IDbSeed<IdentityDbContext>
context.Set<User>().Add(superUser); context.Set<User>().Add(superUser);
} }
private void InitTestDate(IdentityDbContext context) private static void InitTestDate(IdentityDbContext context)
{ {
context.Set<HBPO_SA>().Add(new HBPO_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据", RecordCount = "测试数据" }); context.Set<HBPO_SA>().Add(new HBPO_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据", RecordCount = "测试数据" });
context.Set<HBPO_SA_DETAIL>().Add(new HBPO_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据" }); context.Set<HBPO_SA_DETAIL>().Add(new HBPO_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据" });
context.Set<BBAC_SA>().Add(new BBAC_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据", RecordCount = "测试数据" }); context.Set<BBAC_SA>().Add(new BBAC_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据", RecordCount = "测试数据" });
context.Set<BBAC_SA_DETAIL>().Add(new BBAC_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据", Category = "测试数据", IsReturn = "测试数据" }); context.Set<BBAC_SA_DETAIL>().Add(new BBAC_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据", Category = "测试数据", IsReturn = "测试数据" });
context.Set<JIT_SA>().Add(new JIT_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据", RecordCount = "测试数据" }); context.Set<JIT_SA>().Add(new JIT_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据", RecordCount = "测试数据" });
context.Set<JIT_SA_DETAIL>().Add(new JIT_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据" }); context.Set<JIT_SA_DETAIL>().Add(new JIT_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据" });
context.Set<BJ_SA>().Add(new BJ_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据", RecordCount = "测试数据" }); context.Set<BJ_SA>().Add(new BJ_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据", RecordCount = "测试数据" });
context.Set<BJ_SA_DETAIL>().Add(new BJ_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据" }); context.Set<BJ_SA_DETAIL>().Add(new BJ_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据" });
context.Set<IN_SA>().Add(new IN_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据" }); context.Set<IN_SA>().Add(new IN_SA { Version = "测试数据", BillNum = "123", DNBillNum = "测试数据", State = "测试数据" });
context.Set<IN_SA_DETAIL>().Add(new IN_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PU = "测试数据", Site = "测试数据",SettleDate = new DateTime(), GroupNum = "测试数据" }); context.Set<IN_SA_DETAIL>().Add(new IN_SA_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PU = "测试数据", Site = "测试数据", SettleDate = new DateTime(), GroupNum = "测试数据" });
context.Set<HBPO_DN>().Add(new HBPO_DN { Version = "测试数据", DNBillNum = "123", StockCount = "测试数据" }); context.Set<HBPO_DN>().Add(new HBPO_DN { Version = "测试数据", DNBillNum = "123", StockCount = "测试数据" });
context.Set<HBPO_DN_DETAIL>().Add(new HBPO_DN_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), State = "测试数据", INVGroupNum = "测试数据", GroupNum = "测试数据", DNBillNum = "测试数据" }); context.Set<HBPO_DN_DETAIL>().Add(new HBPO_DN_DETAIL { KeyCode = "测试数据", Version = "测试数据", BillNum = "123", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), State = "测试数据", INVGroupNum = "测试数据", GroupNum = "测试数据", DNBillNum = "测试数据" });
context.Set<BBAC_DN>().Add(new BBAC_DN { Version = "测试数据", DNBillNum = "123", StockCount = "测试数据" }); context.Set<BBAC_DN>().Add(new BBAC_DN { Version = "测试数据", DNBillNum = "123", StockCount = "测试数据" });
@ -140,13 +140,43 @@ public class IdentityDbSeed : IDbSeed<IdentityDbContext>
context.Set<BJ_DN>().Add(new BJ_DN { Version = "测试数据", DNBillNum = "123", StockCount = "测试数据" }); context.Set<BJ_DN>().Add(new BJ_DN { Version = "测试数据", DNBillNum = "123", StockCount = "测试数据" });
context.Set<BJ_DN_DETAIL>().Add(new BJ_DN_DETAIL { KeyCode = "测试数据", Version = "测试数据", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), State = "测试数据", INVGroupNum = "测试数据", GroupNum = "测试数据", DNBillNum = "测试数据" }); context.Set<BJ_DN_DETAIL>().Add(new BJ_DN_DETAIL { KeyCode = "测试数据", Version = "测试数据", LU = "测试数据", PN = "测试数据", Site = "测试数据", SettleDate = new DateTime(), State = "测试数据", INVGroupNum = "测试数据", GroupNum = "测试数据", DNBillNum = "测试数据" });
context.Set<IN_DN>().Add(new IN_DN { Version = "测试数据", DNBillNum = "123", StockCount = "测试数据" }); context.Set<IN_DN>().Add(new IN_DN { Version = "测试数据", DNBillNum = "123", StockCount = "测试数据" });
context.Set<IN_DN_DETAIL>().Add(new IN_DN_DETAIL { KeyCode = "测试数据", Version = "测试数据", LU = "测试数据", PU = "测试数据", Site = "测试数据", SettleDate = new DateTime(), State = "测试数据", INVGroupNum = "测试数据", GroupNum = "测试数据", DNBillNum = "测试数据" }); context.Set<IN_DN_DETAIL>().Add(new IN_DN_DETAIL { KeyCode = "测试数据", Version = "测试数据", LU = "测试数据", PU = "测试数据", Site = "测试数据", SettleDate = new DateTime(), State = "测试数据", INVGroupNum = "测试数据", GroupNum = "测试数据", DNBillNum = "测试数据" });
context.Set<INVOICE>().Add(new INVOICE { RealnvBillNum = "测试数据", InvbillNum = "123", INVGroupNum = "测试数据", FileName ="测试数据",BusinessType="测试数据"}); context.Set<INVOICE>().Add(new INVOICE { RealnvBillNum = "测试数据", InvbillNum = "123", INVGroupNum = "测试数据", FileName = "测试数据", BusinessType = "测试数据" });
context.Set<INVOICE_DETAIL>().Add(new INVOICE_DETAIL { LU = "测试数据", InvbillNum = "123"}); context.Set<INVOICE_DETAIL>().Add(new INVOICE_DETAIL { LU = "测试数据", InvbillNum = "123" });
} }
private void InitDictionaries(DbContext context) private static void InitDictionaries(DbContext context)
{ {
context.Set<DictionaryItem>().Add(new DictionaryItem
{
Name = "测试1",
Number = "test1",
Children = new List<DictionaryItem> {
new DictionaryItem{
Name="测试1.1",
Number="test1.1",
},
new DictionaryItem{
Name="测试1.2",
Number="test1.2",
}
}
}.UpdateId());
context.Set<DictionaryItem>().Add(new DictionaryItem
{
Name = "测试2",
Number = "test2",
Children = new List<DictionaryItem> {
new DictionaryItem{
Name="测试2.1",
Number="test2.1",
},
new DictionaryItem{
Name="测试2.2",
Number="test2.2",
}
}
}.UpdateId());
} }
private void InitPermissions(DbContext context) private void InitPermissions(DbContext context)

14
docs/demo/src/WTA.Shared/Attributes/ManyToManyAttribute.cs

@ -0,0 +1,14 @@
namespace WTA.Shared.Attributes;
[AttributeUsage(AttributeTargets.Property)]
public class ManyToManyAttribute<TEntity> : Attribute, ITypeAttribute
{
public Type Type { get; set; } = null!;
public string? Property { get; }
public ManyToManyAttribute(string? property = null)
{
this.Type = typeof(TEntity);
this.Property = property;
}
}

14
docs/demo/src/WTA.Shared/Attributes/ManyToOneAttribute.cs

@ -0,0 +1,14 @@
namespace WTA.Shared.Attributes;
[AttributeUsage(AttributeTargets.Property)]
public class ManyToOneAttribute<TEntity> : Attribute, ITypeAttribute
{
public Type Type { get; set; } = null!;
public string? Property { get; }
public ManyToOneAttribute(string? property = null)
{
this.Type = typeof(TEntity);
this.Property = property;
}
}

13
docs/demo/src/WTA.Shared/Controllers/GenericController.cs

@ -38,13 +38,14 @@ public class GenericController<TEntity, TModel, TListModel, TSearchModel, TImpor
[HttpPost, Multiple, Order(-4), HtmlClass("el-button--primary")] [HttpPost, Multiple, Order(-4), HtmlClass("el-button--primary")]
public virtual IActionResult Index([FromBody] PaginationModel<TSearchModel, TListModel> model) public virtual IActionResult Index([FromBody] PaginationModel<TSearchModel, TListModel> model)
{ {
var query = BuildQuery(model); var isTree = typeof(TEntity).IsAssignableTo(typeof(BaseTreeEntity<TEntity>));
var query = BuildQuery(model, isTree);
model.TotalCount = query.Count(); model.TotalCount = query.Count();
if (!string.IsNullOrEmpty(model.OrderBy)) if (!string.IsNullOrEmpty(model.OrderBy))
{ {
query = query.OrderBy(model.OrderBy); query = query.OrderBy(model.OrderBy);
} }
if (model.QueryAll) if (model.QueryAll || isTree)
{ {
model.PageSize = model.TotalCount; model.PageSize = model.TotalCount;
} }
@ -59,9 +60,8 @@ public class GenericController<TEntity, TModel, TListModel, TSearchModel, TImpor
return Json(model); return Json(model);
} }
protected virtual IQueryable<TEntity> BuildQuery(PaginationModel<TSearchModel, TListModel> model) protected virtual IQueryable<TEntity> BuildQuery(PaginationModel<TSearchModel, TListModel> model, bool isTree)
{ {
var isTree = typeof(TEntity).IsAssignableTo(typeof(BaseTreeEntity<TEntity>));
var query = this.Repository.AsNoTracking(); var query = this.Repository.AsNoTracking();
query = query.Include(); query = query.Include();
if (model.Query != null) if (model.Query != null)
@ -181,8 +181,9 @@ public class GenericController<TEntity, TModel, TListModel, TSearchModel, TImpor
{ {
try try
{ {
var query = this.BuildQuery(model); var isTree = typeof(TEntity).IsAssignableTo(typeof(BaseTreeEntity<TEntity>));
if (!includeAll) var query = this.BuildQuery(model, isTree);
if (!includeAll && !isTree)
{ {
query = query.Skip(model.PageSize * (model.PageIndex - 1)).Take(model.PageSize); query = query.Skip(model.PageSize * (model.PageIndex - 1)).Take(model.PageSize);
} }

8
docs/demo/src/WTA.Shared/Extensions/JsonSchemaExtensions.cs

@ -75,6 +75,10 @@ public static class JsonSchemaExtensions
if (!modelType.IsValueType && modelType != typeof(string)) if (!modelType.IsValueType && modelType != typeof(string))
{ {
schema.Add("type", "object"); schema.Add("type", "object");
if (modelType.GetBaseClasses().Any(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(BaseTreeEntity<>)))
{
schema.Add("isTree", true);
}
var properties = new Dictionary<string, object>(); var properties = new Dictionary<string, object>();
foreach (var propertyMetadata in meta.Properties) foreach (var propertyMetadata in meta.Properties)
{ {
@ -151,11 +155,11 @@ public static class JsonSchemaExtensions
path = string.Join('.', path.Split('.').Select(o => o.ToLowerCamelCase())); path = string.Join('.', path.Split('.').Select(o => o.ToLowerCamelCase()));
schema.Add("navigation", path); schema.Add("navigation", path);
schema.Add("input", "select"); schema.Add("input", "select");
schema.Add("url", propertyName[..^2].ToSlugify()); schema.Add("url", defaultModelMetadata.ContainerType?.GetProperty(propertyName[..^2])?.PropertyType.Name.ToSlugify()!);
} }
if (defaultModelMetadata.Attributes.Attributes.FirstOrDefault(o => o.GetType().IsGenericType && o.GetType().GetGenericTypeDefinition() == typeof(OneToManyAttribute<>)) is ITypeAttribute oneToManyAttribute) if (defaultModelMetadata.Attributes.Attributes.FirstOrDefault(o => o.GetType().IsGenericType && o.GetType().GetGenericTypeDefinition() == typeof(OneToManyAttribute<>)) is ITypeAttribute oneToManyAttribute)
{ {
schema.Add("oneToMany",$"{oneToManyAttribute.Type.Name}.{oneToManyAttribute.GetType().GetProperty("Property")?.GetValue(oneToManyAttribute)??defaultModelMetadata.PropertyName}"); schema.Add("oneToMany", $"{oneToManyAttribute.Type.Name}.{oneToManyAttribute.GetType().GetProperty("Property")?.GetValue(oneToManyAttribute) ?? defaultModelMetadata.PropertyName}");
} }
if (defaultModelMetadata.Attributes.Attributes.FirstOrDefault(o => o.GetType() == typeof(ScaffoldColumnAttribute)) is ScaffoldColumnAttribute scaffoldColumnAttribute if (defaultModelMetadata.Attributes.Attributes.FirstOrDefault(o => o.GetType() == typeof(ScaffoldColumnAttribute)) is ScaffoldColumnAttribute scaffoldColumnAttribute
&& !scaffoldColumnAttribute.Scaffold) && !scaffoldColumnAttribute.Scaffold)

7
docs/demo/src/WTA/wwwroot/components/form/form-input.js

@ -42,7 +42,7 @@ export default {
/> />
<template v-else-if="schema.type==='boolean'"> <template v-else-if="schema.type==='boolean'">
<el-select :disabled="getDisabled()" v-model="model[prop]" :placeholder="schema.title" v-if="schema.nullable"> <el-select :disabled="getDisabled()" v-model="model[prop]" :placeholder="schema.title" v-if="schema.nullable">
<el-option prop="select" :value="null" :label="$t('select')" /> <el-option prop="select" value="" :label="$t('select')" />
<el-option prop="true" :value="true" :label="$t('true')" /> <el-option prop="true" :value="true" :label="$t('true')" />
<el-option prop="false" :value="false" :label="$t('false')" /> <el-option prop="false" :value="false" :label="$t('false')" />
</el-select> </el-select>
@ -85,6 +85,9 @@ export default {
return schema.input ?? schema.type; return schema.input ?? schema.type;
}; };
/*end*/ /*end*/
//options
const selectProps = ref({});
const selectValues = ref([]);
const options = ref([]); const options = ref([]);
if (props.schema.options) { if (props.schema.options) {
options.value = props.schema.options; options.value = props.schema.options;
@ -102,6 +105,8 @@ export default {
getDisabled, getDisabled,
getInput, getInput,
dayjs, dayjs,
selectProps,
selectValues,
options, options,
}; };
}, },

6
docs/demo/src/WTA/wwwroot/components/form/form-item.js

@ -1,10 +1,9 @@
import html from "html"; import html from "html";
import { ref, reactive, watch } from "vue"; import { defineAsyncComponent, ref, reactive, watch } from "vue";
import AppFormInput from "./form-input.js";
export default { export default {
name: "formItem", name: "formItem",
components: { AppFormInput }, components: { AppFormInput: defineAsyncComponent(() => import("./form-input.js")) },
template: html` template: html`
<template v-if="showItem()"> <template v-if="showItem()">
<template v-if="schema.type==='object'"></template> <template v-if="schema.type==='object'"></template>
@ -19,7 +18,6 @@ export default {
<app-form-input :schema="schema" :prop="prop" v-model="model" :isReadOnly="mode==='details'" /> <app-form-input :schema="schema" :prop="prop" v-model="model" :isReadOnly="mode==='details'" />
</el-form-item> </el-form-item>
</template> </template>
</template>
</template> </template>
`, `,
props: ["modelValue", "mode", "parentSchema", "schema", "prop", "errors"], props: ["modelValue", "mode", "parentSchema", "schema", "prop", "errors"],

5
docs/demo/src/WTA/wwwroot/components/form/index.js

@ -1,9 +1,8 @@
import html from "html"; import html from "html";
import { ref, reactive, watch } from "vue"; import { defineAsyncComponent, ref, reactive, watch } from "vue";
import AppFormItem from "./form-item.js";
export default { export default {
components: { AppFormItem }, components: { AppFormItem: defineAsyncComponent(() => import("./form-item.js")) },
name: "AppForm", name: "AppForm",
template: html`<el-form ref="formRef" :model="model" label-width="auto"> template: html`<el-form ref="formRef" :model="model" label-width="auto">
<template v-for="(value, prop) in schema.properties"> <template v-for="(value, prop) in schema.properties">

34
docs/demo/src/WTA/wwwroot/components/icon/index.js

@ -1,29 +1,35 @@
import html from "html";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
const template = `<component v-if="name.indexOf('ep-')===0" :is="name" /> <v-else g v-html="svg" /> `;
export default { export default {
template: html`<template v-if="name.indexOf('ep-')===0">
<component :is="name" />
</template>
<template v-else>
<g v-html="svg" />
</template> `,
props: { props: {
name: { name: {
default: "file", default: "file",
}, },
}, },
template, async setup(props) {
setup(props) { const svg = ref(null);
const svg = ref("");
onMounted(async () => { onMounted(async () => {
if (props.name.indexOf("ep-") !== 0) { if (!props.name.startsWith("ep-")) {
try { try {
const response = await fetch(`./assets/icons/${props.name}.svg`); const url = `./assets/icons/${props.name}.svg`;
if (response.ok && response.status === 200) { navigator.locks.request(url, async () => {
svg.value = await response.text(); const response = await fetch(url);
} if (response.ok && response.status === 200) {
svg.value = await response.text();
}
});
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} if (!svg.value) {
if (!svg.value) { svg.value = `<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M764.288 214.592 512 466.88 259.712 214.592a31.936 31.936 0 0 0-45.12 45.12L466.752 512 214.528 764.224a31.936 31.936 0 1 0 45.12 45.184L512 557.184l252.288 252.288a31.936 31.936 0 0 0 45.12-45.12L557.12 512.064l252.288-252.352a31.936 31.936 0 1 0-45.12-45.184z"></path></svg>`;
const response = await fetch("./assets/icons/file.svg"); }
svg.value = await response.text();
} }
} }
}); });

126
docs/demo/src/WTA/wwwroot/components/list/index.js

@ -1,19 +1,21 @@
import html, { getProp } from "html"; import html, { getProp } from "html";
import AppForm from "../form/index.js";
import { get, post } from "../../request/index.js"; import { get, post } from "../../request/index.js";
import { ref, reactive } from "vue"; import { defineAsyncComponent, ref, reactive, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import SvgIcon from "../../components/icon/index.js"; import { listToTree, schemaToModel } from "../../utils/index.js";
import { schemaToModel } from "../../utils/index.js";
import qs from "../../lib/qs/shim.js"; import qs from "../../lib/qs/shim.js";
import AppFormInput from "../form/form-input.js";
import VueOfficeExcel from "@vue-office/excel"; import VueOfficeExcel from "@vue-office/excel";
import { camelCase, capitalize } from "lodash"; import { camelCase, capitalize } from "lodash";
export default { export default {
name: "AppList", name: "AppList",
components: { AppForm, SvgIcon, AppFormInput, VueOfficeExcel }, components: {
AppForm: defineAsyncComponent(() => import("../form/index.js")),
SvgIcon: defineAsyncComponent(() => import("../../components/icon/index.js")),
AppFormInput: defineAsyncComponent(() => import("../form/form-input.js")),
VueOfficeExcel,
},
template: html` template: html`
<el-row> <el-row>
<el-col> <el-col>
@ -49,22 +51,22 @@ export default {
<el-scrollbar> <el-scrollbar>
<el-table <el-table
ref="tableRef" ref="tableRef"
v-loading="tableLoading" :v-loading="tableLoading"
:tree-props="treeProps"
:data="tableData"
@selection-change="handleSelectionChange"
@sort-change="sortChange"
:header-cell-class-name="getClass"
row-key="id" row-key="id"
table-layout="auto" table-layout="auto"
border border
fit fit
:data="data.items"
@selection-change="handleSelectionChange"
@sort-change="sortChange"
:header-cell-class-name="getClass"
v-if="data.items"
> >
<el-table-column fixed="left" type="selection" /> <el-table-column fixed="left" type="selection" />
<el-table-column type="index" :label="$t('rowIndex')"> <el-table-column type="index" :label="$t('rowIndex')">
<template #default="scope"> {{ (data.pageIndex - 1) * data.pageSize + scope.$index + 1 }} </template> <template #default="scope"> {{ (data.pageIndex - 1) * data.pageSize + scope.$index + 1 }} </template>
</el-table-column> </el-table-column>
<template v-for="(item,key) in tableSchema.items.properties"> <template v-for="(item,key) in tableSchema.properties">
<template v-if="key==='properties'"> <template v-if="key==='properties'">
<el-table-column :label="subKey" v-for="(subItem,subKey) in item.properties"> <el-table-column :label="subKey" v-for="(subItem,subKey) in item.properties">
<template #default="scope">{{ scope.row[key][subKey] }} </template> <template #default="scope">{{ scope.row[key][subKey] }} </template>
@ -126,7 +128,7 @@ export default {
<el-row> <el-row>
<el-col> <el-col>
<el-pagination <el-pagination
v-if="data.items&&data.pageSize<data.totalCount" v-if="tableData.length&&data.pageSize<data.totalCount"
v-model:currentPage="data.pageIndex" v-model:currentPage="data.pageIndex"
v-model:page-size="data.pageSize" v-model:page-size="data.pageSize"
:total="data.totalCount" :total="data.totalCount"
@ -216,6 +218,9 @@ export default {
props: ["modelValue", "controller", "buttons"], props: ["modelValue", "controller", "buttons"],
emits: ["command"], emits: ["command"],
async setup(props, context) { async setup(props, context) {
const treeProps = reactive({
children: "children",
});
const tableRef = ref(null); const tableRef = ref(null);
const columns = ref([]); const columns = ref([]);
const filterDrawer = ref(false); const filterDrawer = ref(false);
@ -230,13 +235,23 @@ export default {
const buttons = ref(props.buttons ?? route.meta.buttons); const buttons = ref(props.buttons ?? route.meta.buttons);
const baseUrl = props.controller ?? `${route.meta.controller}`; const baseUrl = props.controller ?? `${route.meta.controller}`;
const indexUrl = `${baseUrl}/index`; const indexUrl = `${baseUrl}/index`;
const vm = (await get(indexUrl)).data; const data = ref({});
const schema = vm.schema;
const data = reactive(vm.model ?? schemaToModel(schema));
//Object.assign(data,prop.)
const sortColumns = ref(new Map()); const sortColumns = ref(new Map());
const queryFromSchema = ref({});
const tableSchema = ref({});
const tableData = ref([]);
const editFormRef = ref(null);
const editFormloading = ref(false);
const editFormMode = ref(null);
const editFormTitle = ref("");
const editFormSchema = reactive({});
const editFormModel = reactive({});
const exportModel = reactive({
includeAll: false,
includeDeleted: false,
});
const getSortModel = (model) => { const getSortModel = (model) => {
const orderBy = model.orderBy model.orderBy
.split(",") .split(",")
.map((o) => o.trim()) .map((o) => o.trim())
.filter((o) => o) .filter((o) => o)
@ -245,32 +260,30 @@ export default {
order: (o.split(" ").filter((o) => o)[1] ?? "asc") + "ending", order: (o.split(" ").filter((o) => o)[1] ?? "asc") + "ending",
})) }))
.forEach((o) => sortColumns.value.set(o.prop, o.order)); .forEach((o) => sortColumns.value.set(o.prop, o.order));
return orderBy;
}; };
const sortModel = reactive(getSortModel(data)); const getColumns = (schema) => {
Object.keys(schema.properties).forEach((propertyName) => {
const property = schema.properties[propertyName];
if (property.type !== "object" && property.type !== "array" && !property.hidden) {
columns.value.push({ name: propertyName, title: property.title, checked: true });
}
});
};
const getClass = ({ row, column }) => { const getClass = ({ row, column }) => {
if (column.property) { if (column.property) {
column.order = sortColumns.value.get(column.property); column.order = sortColumns.value.get(column.property);
} }
}; };
const sortChange = ({ column, prop, order }) => { const sortChange = async ({ column, prop, order }) => {
if (order === null) { if (order === null) {
sortColumns.value.delete(prop); sortColumns.value.delete(prop);
} else { } else {
sortColumns.value.set(prop, order); sortColumns.value.set(prop, order);
} }
data.orderBy = Array.from(sortColumns.value) data.value.orderBy = Array.from(sortColumns.value)
.map((o) => capitalize(o[0]) + (o[1] === "ascending" ? "" : ` DESC`)) .map((o) => capitalize(o[0]) + (o[1] === "ascending" ? "" : ` DESC`))
.join(","); .join(",");
load(indexUrl); await load(indexUrl);
};
const getColumns = (schema) => {
Object.keys(schema.properties).forEach((propertyName) => {
const property = schema.properties[propertyName];
if (property.type !== "object" && property.type !== "array" && !property.hidden) {
columns.value.push({ name: propertyName, title: property.title, checked: true });
}
});
}; };
const showColumn = (item, prop) => { const showColumn = (item, prop) => {
return ( return (
@ -280,35 +293,29 @@ export default {
columns.value.findIndex((o) => o.name === prop && o.checked) >= 0 columns.value.findIndex((o) => o.name === prop && o.checked) >= 0
); );
}; };
getColumns(schema.properties.query);
const queryFromSchema = schema.properties.query;
const tableSchema = schema.properties.items;
const editFormRef = ref(null);
const editFormloading = ref(false);
const editFormMode = ref(null);
const editFormTitle = ref("");
const editFormSchema = reactive({});
const editFormModel = reactive({});
const exportModel = reactive({
includeAll: false,
includeDeleted: false,
});
const handleSelectionChange = (rows) => (selectedRows.value = rows); const handleSelectionChange = (rows) => (selectedRows.value = rows);
const load = async (url) => { const load = async (url) => {
tableLoading.value = true; tableLoading.value = true;
try { try {
const postData = JSON.parse(JSON.stringify(data)); const postData = JSON.parse(JSON.stringify(data.value));
delete postData["Id"]; // delete postData["Id"];
delete postData["items"]; // delete postData["items"];
Object.assign(data, (await post(url, postData)).data); const listData = (await post(url, postData)).data;
if (tableSchema.value.isTree) {
listData.items = listToTree(listData.items);
}
tableData.value = listData.items;
delete listData["items"];
data.value = listData;
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} finally { } finally {
tableLoading.value = false; tableLoading.value = false;
} }
}; };
const onPageIndexChange = () => load(indexUrl); const onPageIndexChange = async () => await load(indexUrl);
const onPageSizeChange = () => load(indexUrl); const onPageSizeChange = async () => await load(indexUrl);
const click = async (item, rows) => { const click = async (item, rows) => {
editFormMode.value = item.path; editFormMode.value = item.path;
context.emit("command", item, rows); context.emit("command", item, rows);
@ -383,7 +390,7 @@ export default {
editFormloading.value = false; editFormloading.value = false;
} }
} else if (editFormMode.value === "details") { } else if (editFormMode.value === "details") {
load(indexUrl); await load(indexUrl);
editFormMode.value = null; editFormMode.value = null;
dialogVisible.value = false; dialogVisible.value = false;
} }
@ -410,8 +417,18 @@ export default {
subDrawer.value = true; subDrawer.value = true;
} }
}; };
await load(indexUrl); onMounted(async () => {
const vm = (await get(indexUrl)).data;
const schema = vm.schema;
queryFromSchema.value = schema.properties.query;
tableSchema.value = schema.properties.items.items;
data.value = vm.model ?? schemaToModel(schema);
getSortModel(data.value);
getColumns(schema.properties.query);
await load(indexUrl);
});
return { return {
treeProps,
tableRef, tableRef,
tableLoading, tableLoading,
columns, columns,
@ -420,12 +437,11 @@ export default {
subDrawer, subDrawer,
dialogVisible, dialogVisible,
selectedRows, selectedRows,
schema,
queryFromSchema, queryFromSchema,
tableSchema, tableSchema,
buttons, buttons,
data, data,
sortModel, tableData,
getClass, getClass,
sortChange, sortChange,
getProp, getProp,

36
docs/demo/src/WTA/wwwroot/components/markdown/index.js

@ -1,14 +1,18 @@
import { ref, onMounted } from 'vue'; import html from "html";
import { marked, setOptions } from '../../lib/marked/marked.esm.js'; import { ref, onMounted } from "vue";
import mermaid from '../../lib/mermaid/mermaid.esm.min.mjs'; import { marked, setOptions } from "../../lib/marked/marked.esm.js";
import hljs from '../../lib/highlightjs/highlight.min.js'; import mermaid from "../../lib/mermaid/mermaid.esm.min.mjs";
import hljs from "../../lib/highlightjs/highlight.min.js";
export default { export default {
template: `<div ref="tplRef"><div class="source" style="display:none;"><slot /></div><div class="markdown-body"></div></template>`, template: html`<div ref="tplRef">
<div class="source" style="display:none;"><slot /></div>
<div class="markdown-body"></div>
</div>`,
props: { props: {
name: { name: {
default: null default: null,
} },
}, },
setup(props) { setup(props) {
const tplRef = ref(null); const tplRef = ref(null);
@ -17,25 +21,25 @@ export default {
onMounted(async () => { onMounted(async () => {
setOptions({ setOptions({
highlight: function (code, lang) { highlight: function (code, lang) {
if (lang === 'mermaid') { if (lang === "mermaid") {
return mermaid.mermaidAPI.render(`mermaid${id++}`, code, undefined); return mermaid.mermaidAPI.render(`mermaid${id++}`, code, undefined);
} else { } else {
const language = hljs.getLanguage(lang) ? lang : 'plaintext'; const language = hljs.getLanguage(lang) ? lang : "plaintext";
return hljs.highlight(code, { language }).value; return hljs.highlight(code, { language }).value;
} }
}, },
langPrefix: 'hljs language-', langPrefix: "hljs language-",
}); });
let mdText = tplRef.value.querySelector('.source').innerText; let mdText = tplRef.value.querySelector(".source").innerText;
if (props.name !== null) { if (props.name !== null) {
const response = await fetch(`./assets/docs/${props.name}.md`); const response = await fetch(`./assets/docs/${props.name}.md`);
mdText = await response.text(); mdText = await response.text();
} }
tplRef.value.querySelector('.markdown-body').innerHTML = marked(mdText); tplRef.value.querySelector(".markdown-body").innerHTML = marked(mdText);
tplRef.value.querySelector('.source').remove(); tplRef.value.querySelector(".source").remove();
}); });
return { return {
tplRef tplRef,
}; };
} },
} };

2
docs/demo/src/WTA/wwwroot/index.html

@ -69,4 +69,4 @@
<script type="module" src="./main.js"></script> <script type="module" src="./main.js"></script>
</body> </body>
</html> </html>

13
docs/demo/src/WTA/wwwroot/layouts/header.js

@ -1,18 +1,21 @@
import html from "html"; import html from "html";
import { ref, onMounted, onUnmounted } from "vue"; import { defineAsyncComponent, ref, onMounted, onUnmounted } from "vue";
import { useAppStore } from "../store/index.js"; import { useAppStore } from "../store/index.js";
import SvgIcon from "../components/icon/index.js";
import LayoutLogo from "./logo.js";
import { useDark, useFullscreen, useToggle } from "@vueuse/core"; import { useDark, useFullscreen, useToggle } from "@vueuse/core";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { logout } from "../api/user.js"; import { logout } from "../api/user.js";
import LayoutLocale from "./locale.js";
import router from "../router/index.js"; import router from "../router/index.js";
import { treeToList } from "../utils/index.js"; import { treeToList } from "../utils/index.js";
export default { export default {
components: { SvgIcon, LayoutLogo, LayoutLocale, ElMessage, ElMessageBox }, components: {
SvgIcon: defineAsyncComponent(() => import("../components/icon/index.js")),
LayoutLogo: defineAsyncComponent(() => import("./logo.js")),
LayoutLocale: defineAsyncComponent(() => import("./locale.js")),
ElMessage,
ElMessageBox,
},
template: html` template: html`
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">

14
docs/demo/src/WTA/wwwroot/layouts/index.js

@ -1,14 +1,14 @@
import html from "html"; import html from "html";
import LayoutHeader from "./header.js";
import LayoutMenu from "./menu.js";
import LayoutTabs from "./tabs.js";
import LayoutFooter from "./footer.js";
import Icon from "../components/icon/index.js";
import { useAppStore } from "../store/index.js"; import { useAppStore } from "../store/index.js";
import { computed } from "vue"; import { defineAsyncComponent, computed } from "vue";
export default { export default {
components: { Icon, LayoutHeader, LayoutMenu, LayoutTabs, LayoutFooter }, components: {
LayoutHeader: defineAsyncComponent(() => import("./header.js")),
LayoutMenu: defineAsyncComponent(() => import("./menu.js")),
LayoutTabs: defineAsyncComponent(() => import("./tabs.js")),
LayoutFooter: defineAsyncComponent(() => import("./footer.js")),
},
template: html`<el-container> template: html`<el-container>
<el-header><layout-header /></el-header> <el-header><layout-header /></el-header>
<el-container> <el-container>

7
docs/demo/src/WTA/wwwroot/layouts/locale.js

@ -1,13 +1,14 @@
import html from "html"; import html from "html";
import { defineAsyncComponent } from "vue";
import { useAppStore } from "../store/index.js"; import { useAppStore } from "../store/index.js";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import Icon from "../components/icon/index.js";
export default { export default {
components: { Icon }, components: { SvgIcon: defineAsyncComponent(() => import("../components/icon/index.js")) },
template: html`<el-dropdown class="cursor-pointer" v-if="appStore.settings.enableLocale"> template: html`<el-dropdown class="cursor-pointer" v-if="appStore.settings.enableLocale">
<span class="el-dropdown-link flex"> <span class="el-dropdown-link flex">
<el-icon :size="18"> <el-icon :size="18">
<icon name="lang" /> <svg-icon name="lang" />
</el-icon> </el-icon>
</span> </span>
<template #dropdown> <template #dropdown>

9
docs/demo/src/WTA/wwwroot/layouts/menu-item.js

@ -1,18 +1,17 @@
import html from "html"; import html from "html";
import { reactive, watch } from "vue"; import { defineAsyncComponent, reactive, watch } from "vue";
import Icon from "../components/icon/index.js";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
export default { export default {
name: "menuItem", name: "menuItem",
components: { Icon }, components: { SvgIcon: defineAsyncComponent(() => import("../components/icon/index.js")) },
template: html`<template v-if="!modelValue.meta.isHidden"> template: html`<template v-if="!modelValue.meta.isHidden">
<el-sub-menu <el-sub-menu
:index="modelValue.meta.path" :index="modelValue.meta.path"
v-if="modelValue.children&&modelValue.children.some(o=>!o.meta.isHidden)" v-if="modelValue.children&&modelValue.children.some(o=>!o.meta.isHidden)"
> >
<template #title> <template #title>
<el-icon><icon :name="modelValue.meta.icon??'folder'" /></el-icon> <el-icon><svg-icon :name="modelValue.meta.icon??'folder'" /></el-icon>
<span>{{modelValue.meta.title}}</span> <span>{{modelValue.meta.title}}</span>
</template> </template>
<menu-item v-for="item in modelValue.children" v-model="item" /> <menu-item v-for="item in modelValue.children" v-model="item" />
@ -22,7 +21,7 @@ export default {
:index="modelValue.meta.isExternal?null:modelValue.meta.path" :index="modelValue.meta.isExternal?null:modelValue.meta.path"
@click.native="click(modelValue)" @click.native="click(modelValue)"
> >
<el-icon><icon :name="modelValue.meta.icon??file" /></el-icon> <el-icon><svg-icon :name="modelValue.meta.icon??file" /></el-icon>
<template #title> <template #title>
<span>{{modelValue.meta.title}}</span> <span>{{modelValue.meta.title}}</span>
</template> </template>

19
docs/demo/src/WTA/wwwroot/layouts/tabs.js

@ -1,12 +1,10 @@
import html from "html"; import html from "html";
import { ref, nextTick } from "vue"; import { defineAsyncComponent, ref, nextTick } from "vue";
import { useRoute, onBeforeRouteUpdate, useRouter } from "vue-router"; import { useRoute, onBeforeRouteUpdate, useRouter } from "vue-router";
import Icon from "../components/icon/index.js";
import { useAppStore } from "../store/index.js"; import { useAppStore } from "../store/index.js";
import MenuItem from "./menu-item.js";
export default { export default {
components: { Icon, MenuItem }, components: { SvgIcon: defineAsyncComponent(() => import("../components/icon/index.js")) },
template: html`<el-tabs template: html`<el-tabs
v-model="model" v-model="model"
type="border-card" type="border-card"
@ -24,23 +22,24 @@ export default {
@visible-change="showContextMenu(index, $event)" @visible-change="showContextMenu(index, $event)"
> >
<span class="inline-flex items-center"> <span class="inline-flex items-center">
<el-icon><icon v-if="item.meta.icon" :name="item.meta.icon" /></el-icon> <el-icon><svg-icon v-if="item.meta.icon" :name="item.meta.icon" /></el-icon>
{{ item.meta?.title ?? item.fullPath }} {{ item.meta?.title ?? item.fullPath }}
</span> </span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item @click="refresh(index)"><i-ep-refresh />刷新</el-dropdown-item> <el-dropdown-item @click="refresh(index)">
<el-icon><ep-refresh /></el-icon><span></span>
</el-dropdown-item>
<el-dropdown-item :disabled="index === 0" @click="removeLeft(index)"> <el-dropdown-item :disabled="index === 0" @click="removeLeft(index)">
<i-ep-back />关闭左侧 <el-icon><ep-back /></el-icon><span></span>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item :disabled="index === appStore.routes.length - 1" @click="removeRight(index)"> <el-dropdown-item :disabled="index === appStore.routes.length - 1" @click="removeRight(index)">
<i-ep-right />关闭右侧 <el-icon><ep-right /></el-icon><span></span>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item <el-dropdown-item
:disabled="index === 0 && index === appStore.routes.length - 1" :disabled="index === 0 && index === appStore.routes.length - 1"
@click="removeOthers(index)" @click="removeOthers(index)"
> ><el-icon><ep-switch /></el-icon><span></span>
<i-ep-switch />
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>

2
docs/demo/src/WTA/wwwroot/main.js

@ -1,5 +1,5 @@
import { createApp } from "vue"; import { createApp } from "vue";
import style from './mixins/style.js'; import style from "./mixins/style.js";
import store, { useAppStore } from "./store/index.js"; import store, { useAppStore } from "./store/index.js";
import router from "./router/index.js"; import router from "./router/index.js";
import ElementPlus from "element-plus"; import ElementPlus from "element-plus";

2
docs/demo/src/WTA/wwwroot/router/index.js

@ -93,7 +93,7 @@ const reset = (list, parent = null) => {
meta: o.meta, meta: o.meta,
}; };
if (o.type === "Resource") { if (o.type === "Resource") {
item.component = import(`../views/${o.component ? o.component : "list"}.js`); item.component = () => import(`../views/${o.component ? o.component : "list"}.js`);
} }
item.meta.controller = item.path; item.meta.controller = item.path;
item.meta.path = `${parent === null ? "/" : parent.meta.path + "/"}${item.path}`; item.meta.path = `${parent === null ? "/" : parent.meta.path + "/"}${item.path}`;

1
docs/demo/src/WTA/wwwroot/store/app.js

@ -11,6 +11,7 @@ const useAppStore = defineStore("app", {
isMenuCollapse: false, isMenuCollapse: false,
isRefreshing: false, isRefreshing: false,
routes: [], routes: [],
cache: new Map(),
}; };
const localSettings = JSON.parse(localStorage.getItem("settings") ?? "{}"); const localSettings = JSON.parse(localStorage.getItem("settings") ?? "{}");
Object.assign(state.settings, localSettings); Object.assign(state.settings, localSettings);

Loading…
Cancel
Save