### Build and Install libgdiplus for .NET Core on CentOS/RHEL Source: https://github.com/dotnetcore/wtm/blob/dotnet8/QA.md Provides steps to build and install libgdiplus from source, along with necessary dependencies, to resolve graphics-related issues (like component not found or text rendering problems) when running .NET Core applications on CentOS/RHEL. ```bash yum -y install autoconf automake libtool yum -y install freetype-devel fontconfig libXft-devel yum -y install libjpeg-turbo-devel libpng-devel giflib-devel libtiff-devel libexif-devel yum -y install glib2-devel cairo-devel yum -y install git mkdir -p /softwares cd /softwares git clone https://github.com/mono/libgdiplus cd libgdiplus ./autogen.sh make make install ln -s /usr/local/lib/libgdiplus.so /usr/lib64/gdiplus.dll ########################type init 错误。提示找不到libgdiplus组件########## ## 方案1 ln -s /usr/local/lib/libgdiplus.so /usr/lib64/libgdiplus.so ln -s /usr/local/lib/libgdiplus.so /usr/libgdiplus.so ## 方案2 vi /etc/ld.so.conf ##将 /usr/local/lib 加入 # 使配置生效。 ldconfig ###################################################################### ######生成出来的图片没有任何文字 DrawString not dislpay in image########## # 复制 windowns fronts to /usr/share/fonts/chinese/TrueType/ ###################################################################### ``` -------------------------------- ### Git Commit Body Example Source: https://github.com/dotnetcore/wtm/blob/dotnet8/CONTRIBUTING.md Provides an example of the optional Body section of a commit message. The body should contain a more detailed explanation of the changes, wrapped to about 72 characters per line, and can include multiple paragraphs or bullet points. ```text More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. Further paragraphs come after blank lines. - Bullet points are okay, too - Use a hanging indent ``` -------------------------------- ### Displaying Create Form with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the GET request for displaying the create form. It creates a VM instance for the entity and returns a partial view containing the form. ```C# [ActionDescription("Sys.Create")] public ActionResult Create() { var vm = Wtm.CreateVM<$modelname$VM>(); return PartialView(vm); } ``` -------------------------------- ### Git Revert Commit Message Example Source: https://github.com/dotnetcore/wtm/blob/dotnet8/CONTRIBUTING.md Shows the specific format for a commit that reverts a previous commit. It must start with 'revert:' followed by the header of the reverted commit, and the body must state 'This reverts commit .' where is the SHA of the reverted commit. ```text revert: feat(pencil): add 'graphiteWidth' option This reverts commit 667ecc1654a317a13331b17617d973392f415f02. ``` -------------------------------- ### Install libunwind for .NET Core on CentOS/RHEL Source: https://github.com/dotnetcore/wtm/blob/dotnet8/QA.md Resolves the 'libunwind.so.8: cannot open shared object file' error when running .NET Core applications by installing the libunwind package using yum. ```bash # Failed to load ▒▒, error: libunwind.so.8: cannot open shared object file: No such file or directory # Failed to bind to CoreCLR at '/websites/walkingtec.mvvm.mvc.admin/libcoreclr.so' yum -y install libunwind ``` -------------------------------- ### Displaying Search View with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the GET request for the index page, typically displaying a search form or initial list view. It creates a ListVM instance and returns a partial view. ```C# [ActionDescription("Sys.Search")] public ActionResult Index() { var vm = Wtm.CreateVM<$modelname$ListVM>(); return PartialView(vm); } ``` -------------------------------- ### Displaying Details View with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the GET request for displaying the details view of a specific entity. It creates a VM instance populated with the entity data based on the provided ID and returns a partial view. ```C# [ActionDescription("Sys.Details")] public ActionResult Details(string id) { var vm = Wtm.CreateVM<$modelname$VM>(id); return PartialView(vm); } ``` -------------------------------- ### Default Vuex Store Configuration based on API (TypeScript) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/demo/WalkingTec.Mvvm.VueDemo/ClientApp/README.md Demonstrates the default setup for a Vuex store module. It imports the service definition from `api.ts`, uses a `createStore` helper function from `@/store/base/index` to generate the initial store structure (state, actions, mutations), and then exports a new Vuex Store instance incorporating this structure. ```TypeScript // frameworkuser/store/api.ts const search = { url: "/api/_FrameworkUser/search", // 请求api的地址;支持{}写法,如果url有 {ID}会根据请求参数中的ID替换内容; method: "post", // 请求类型 dataType: "array", // 返回的数据类型 array | object contentType: "" // 请求herder.Content-Type值,默认json接口 }; const add = { url: reqPath + "Add", method: "post" }; ... export default { search, add, ... }; // frameworkuser/store/index.ts // 默认写法如下,生成的stroe在对象newStore中; import Vuex from "vuex"; import service from "./api"; import createStore from "@/store/base/index"; const newStore = createStore(service); // 可以打印查看store结构 console.log('newStore:', newStore); export default new Vuex.Store({ strict: true, getters: {}, ...newStore }); ``` -------------------------------- ### Vue Script Setup - Mounted Hook Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue3/Edit.txt The `onMounted` lifecycle hook is used to initialize the component. It includes a placeholder `$init$` for custom initialization. It checks for an entity ID from component attributes or router query and fetches the existing entity data using the API's `get` method, populating the form model. ```TypeScript // 页面加载时 onMounted(() => { $init$ if (ci.attrs["wtmdata"]) { state$modelname$.vmModel.Entity.ID = ci.attrs["wtmdata"].ID; } else if (useRouter().currentRoute.value.query.id) { state$modelname$.vmModel.Entity.ID = useRouter().currentRoute.value.query.id as any; } $modelname$Api().get(state$modelname$.vmModel.Entity.ID ?? "").then((data: any) => other.setValue(state$modelname$.vmModel, data)); }); ``` -------------------------------- ### Install ICU for .NET Core Globalization on CentOS/RHEL Source: https://github.com/dotnetcore/wtm/blob/dotnet8/QA.md Addresses the 'Couldn't find a valid ICU package' error related to globalization support in .NET Core by installing the icu package using yum. ```bash # FailFast: Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support. # # at System.Environment.FailFast(System.String) # at System.Globalization.GlobalizationMode.GetGlobalizationInvariantMode() # at System.Globalization.GlobalizationMode..cctor() # at System.Globalization.CultureData.CreateCultureWithInvariantData() # at System.Globalization.CultureData.get_Invariant() # at System.Globalization.CultureData.GetCultureData(System.String, Boolean) # at System.Globalization.CultureInfo.InitializeFromName(System.String, Boolean) # at System.Globalization.CultureInfo.Init() # at System.Globalization.CultureInfo..cctor() # at System.StringComparer..cctor() # at System.AppDomainSetup.SetCompatibilitySwitches(System.Collections.Generic.IEnumerable`1) # at System.AppDomain.PrepareDataForSetup(System.String, System.AppDomainSetup, System.Security.Policy.Evidence, System.Security.Polic y.Evidence, IntPtr, System.String, System.String[], System.String[]) # Aborted yum -y install icu ``` -------------------------------- ### Displaying Delete Confirmation with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the GET request for displaying the delete confirmation dialog for a specific entity. It creates a VM instance populated with the entity data based on the provided ID and returns a partial view. ```C# [ActionDescription("Sys.Delete")] public ActionResult Delete(string id) { var vm = Wtm.CreateVM<$modelname$VM>(id); return PartialView(vm); } ``` -------------------------------- ### Download Import Template (Blazor C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Blazor/Import.txt Asynchronously downloads the required Excel template file for data import. It makes a GET request to the specified API endpoint to retrieve the template file. ```C# private async Task DownloadTemplate() { await Download("/api/$modelname$/GetExcelTemplate", new { }, HttpMethodEnum.GET); } ``` -------------------------------- ### Testing API Get Endpoint Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ApiTest.txt Tests the Get method of the API controller. It saves an entity to the database and then attempts to retrieve it using the controller's Get method, asserting that a result is returned. ```C# [TestMethod] public void GetTest() { $model$ v = new $model$(); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { $pros$ context.Set<$model$>().Add(v); context.SaveChanges(); } var rv = _controller.Get(v.ID.ToString()); Assert.IsNotNull(rv); } ``` -------------------------------- ### Vue Script Setup - Expose Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue3/Edit.txt Uses `defineExpose` to explicitly expose properties or methods from the component's setup function, making them accessible to the parent component via template refs. This component currently exposes nothing. ```TypeScript // 暴露变量 defineExpose({ }); ``` -------------------------------- ### Displaying Edit Form with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the GET request for displaying the edit form for a specific entity. It creates a VM instance populated with the entity data based on the provided ID and returns a partial view. ```C# [ActionDescription("Sys.Edit")] public ActionResult Edit(string id) { var vm = Wtm.CreateVM<$modelname$VM>(id); return PartialView(vm); } ``` -------------------------------- ### Git Commit Footer - Closing Issue Example Source: https://github.com/dotnetcore/wtm/blob/dotnet8/CONTRIBUTING.md Illustrates how to use the optional Footer section to link a commit to and close one or more issues by listing their numbers prefixed with 'Closes #'. ```text Closes #123, #234, #235 ``` -------------------------------- ### Regenerate SVG Components using Yarn Source: https://github.com/dotnetcore/wtm/blob/dotnet8/demo/WalkingTec.Mvvm.VueDemo/ClientApp/src/assets/icon/README.md This command regenerates all SVG components based on the SVG files located in the icons/svg folder. Ensure vue-svgicon is installed globally or use npx before running. ```Shell yarn svg ``` -------------------------------- ### Testing WTM API Get Method C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ApiTestTopPoco.txt Tests the Get method for retrieving an entity by ID. It creates and saves an entity, calls the Get method with the entity's ID, and asserts that a non-null result is returned. ```C# [TestMethod] public void GetTest() { $model$ v = new $model$(); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { $pros$ context.Set<$model$>().Add(v); context.SaveChanges(); } var rv = _controller.Get(v.ID.ToString()); Assert.IsNotNull(rv); } ``` -------------------------------- ### Testing Controller Create Functionality - C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ControllerTest.txt Tests the Create method by first getting the view model for creation, populating an entity with placeholder properties, submitting the view model, and then verifying that the entity was added to the database with correct audit information. ```C# [TestMethod] public void CreateTest() { PartialViewResult rv = (PartialViewResult)_controller.Create(); Assert.IsInstanceOfType(rv.Model, typeof($model$VM)); $model$VM vm = rv.Model as $model$VM; $model$ v = new $model$(); $cpros$ vm.Entity = v; _controller.Create(vm); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data = context.Set<$model$>().Find(v.ID); $assert$ Assert.AreEqual(data.CreateBy, "user"); Assert.IsTrue(DateTime.Now.Subtract(data.CreateTime.Value).Seconds < 10); } } ``` -------------------------------- ### Getting Excel Import Template in WTM API Controller (C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Controller.txt Generates and returns an Excel template file for data import. Creates an ImportVM, sets parameters from the request query, generates the template, and returns it as a file download. ```C# [ActionDescription("Sys.DownloadTemplate")] [HttpGet("GetExcelTemplate")] public IActionResult GetExcelTemplate() { var vm = Wtm.CreateVM<$controllername$ImportVM>(); var qs = new Dictionary(); foreach (var item in Request.Query.Keys) { qs.Add(item, Request.Query[item]); } vm.SetParms(qs); var data = vm.GenerateTemplate(out string fileName); return File(data, "application/vnd.ms-excel", fileName); } ``` -------------------------------- ### Test Controller Create Action Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ControllerTestTopPoco.txt This test validates the controller's Create action. It checks the view model type returned by the initial Create GET request, populates a new entity via the view model, calls the Create POST action, and verifies the entity was successfully added to the in-memory database. ```C# [TestMethod] public void CreateTest() { PartialViewResult rv = (PartialViewResult)_controller.Create(); Assert.IsInstanceOfType(rv.Model, typeof($model$VM)); $model$VM vm = rv.Model as $model$VM; $model$ v = new $model$(); $cpros$ vm.Entity = v; _controller.Create(vm); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data = context.Set<$model$>().Find(v.ID); $assert$ } } ``` -------------------------------- ### Test Controller Batch Edit Action Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ControllerTestTopPoco.txt This test verifies the controller's BatchDelete (used here to get the batch edit VM) and DoBatchEdit actions. It adds multiple entities, retrieves them for batch editing, updates properties via the batch view model, calls the DoBatchEdit action, and is intended to verify the changes (verification block is a placeholder). ```C# [TestMethod] public void BatchEditTest() { $model$ v1 = new $model$(); $model$ v2 = new $model$(); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { $mpros$ context.Set<$model$>().Add(v1); context.Set<$model$>().Add(v2); context.SaveChanges(); } PartialViewResult rv = (PartialViewResult)_controller.BatchDelete(new string[] { v1.ID.ToString(), v2.ID.ToString() }); Assert.IsInstanceOfType(rv.Model, typeof($model$BatchVM)); $model$BatchVM vm = rv.Model as $model$BatchVM; vm.Ids = new string[] { v1.ID.ToString(), v2.ID.ToString() }; $linkedpros$ vm.FC = new Dictionary(); $linkedfc$ _controller.DoBatchEdit(vm, null); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { ``` -------------------------------- ### Download Error File (Blazor C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Blazor/Import.txt Asynchronously downloads the error file generated during the import process. It constructs the download URL using the stored ErrorFileId and makes a GET request to the file download API endpoint. ```C# private async Task DownloadErrorFile() { await Download($"/api/_file/DownloadFile/{ErrorFileId}", new { }, HttpMethodEnum.GET); } ``` -------------------------------- ### Test Controller Edit Action Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ControllerTestTopPoco.txt This test verifies the controller's Edit action. It first adds an entity to the database, then retrieves it using the Edit GET action, updates its properties via the view model, calls the Edit POST action, and finally asserts that the changes were persisted in the database. ```C# [TestMethod] public void EditTest() { $model$ v = new $model$(); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { $pros$ context.Set<$model$>().Add(v); context.SaveChanges(); } PartialViewResult rv = (PartialViewResult)_controller.Edit(v.ID.ToString()); Assert.IsInstanceOfType(rv.Model, typeof($model$VM)); $model$VM vm = rv.Model as $model$VM; vm.Wtm.DC = new DataContext(_seed, DBTypeEnum.Memory); v = new $model$(); v.ID = vm.Entity.ID; $epros$ vm.Entity = v; vm.FC = new Dictionary(); $fc$ _controller.Edit(vm); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data = context.Set<$model$>().Find(v.ID); $eassert$ } } ``` -------------------------------- ### Initializing Controller Test Environment - C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ControllerTest.txt Sets up the test class by creating a unique seed for the in-memory database and initializing the controller instance using a mock controller factory. ```C# public $model$ControllerTest() { _seed = Guid.NewGuid().ToString(); _controller = MockController.CreateController<$model$Controller>(new DataContext(_seed, DBTypeEnum.Memory), "user"); } ``` -------------------------------- ### Get $modelname$ by ID - TypeScript Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue3/indexapi.txt Sends a GET request to `/api/$modelname$/{id}` to retrieve a specific `$modelname$` resource by its ID. The ID can be a number or a string. ```TypeScript get: (data: number|string) => { return request({ url: '/api/$modelname$/'+data, method: 'get' }); } ``` -------------------------------- ### Initialize Controller Test Class Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ControllerTestTopPoco.txt This constructor sets up the test environment for the controller tests. It creates a unique seed for the in-memory database and initializes the controller instance using a mock context. ```C# public $model$ControllerTest() { _seed = Guid.NewGuid().ToString(); _controller = MockController.CreateController<$model$Controller>(new DataContext(_seed, DBTypeEnum.Memory), "user"); } ``` -------------------------------- ### WalkingTec.Mvvm Template and Import VM Structure - C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ImportVM.txt Provides the foundational C# code structure for creating template and import view models within the WalkingTec.Mvvm framework. It includes standard using statements, namespace declaration, and placeholder definitions for the template and import VM classes, designed for automated code generation. ```C# using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using WalkingTec.Mvvm.Core; using WalkingTec.Mvvm.Core.Extensions; using $modelnamespace$; $othernamespace$ namespace $vmnamespace$ { public partial class $classname$TemplateVM : BaseTemplateVM {$pros$ protected override void InitVM() {$init$ } } public class $classname$ImportVM : BaseImportVM<$classname$TemplateVM, $modelname$> { } } ``` -------------------------------- ### Configuring Vuex Store with API Module - JavaScript Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue/store/index.txt This snippet imports Vuex, an API module, and a base store creator. It then creates a new store using the base creator with the API module and exports a new Vuex store instance that includes strict mode, empty getters, and spreads the properties of the created base store. ```JavaScript import Vuex from "vuex"; import api from "./api"; import createStore from "@/store/base/index"; const newStore = createStore(api); export default new Vuex.Store({ strict: true, getters: {}, ...newStore }); ``` -------------------------------- ### Initialize Import View Model (C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Initializes a view model for the import process using a framework helper and returns a partial view containing the import form. ```C# var vm = Wtm.CreateVM<$modelname$ImportVM>(); return PartialView(vm); ``` -------------------------------- ### Getting Form Field Value (React/JS) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/React/views/models.txt This utility function retrieves the value of a specific form field (fieId). It first attempts to get the value from the Ant Design form instance (props.form.getFieldValue) and falls back to props.defaultValues. It converts the result to a string and returns a provided defaultvalue if the result is an empty string. ```Javascript getValue(props: WTM.FormProps, fieId, defaultvalue = undefined) { var rv = lodash.toString(props.form.getFieldValue(fieId) || lodash.get(props.defaultValues, fieId)); if (rv == "") { rv = lodash.toString(defaultvalue); } return rv; } ``` -------------------------------- ### Generating Column Format Info (C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/HeaderFormat.txt This C# method, `$field$Format`, takes a view entity and an object value, returning a list of `ColumnFormatInfo`. It specifically creates two format entries: one for a download button and one for a view button, both linked to the specified field within the entity. ```C# private List $field$Format($classname$_View entity, object val) { return new List { ColumnFormatInfo.MakeDownloadButton(ButtonTypesEnum.Button,entity.$field$), ColumnFormatInfo.MakeViewButton(ButtonTypesEnum.Button,entity.$field$,640,480), }; } ``` -------------------------------- ### Initializing API Controller Test Class Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ApiTest.txt Initializes the test class by creating a unique seed for the in-memory database and instantiating a mocked API controller for testing. ```C# public $model$ApiTest() { _seed = Guid.NewGuid().ToString(); _controller = MockController.CreateApi<$classnamel$Controller>(new DataContext(_seed, DBTypeEnum.Memory), "user"); } ``` -------------------------------- ### Creating Data with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the POST request for creating a new entity. It receives the VM with form data, validates the model state, performs the add operation, and returns a result to close the dialog and refresh the grid on success. ```C# [HttpPost] [ActionDescription("Sys.Create")] public ActionResult Create($modelname$VM vm) { if (!ModelState.IsValid) { return PartialView(vm); } else { vm.DoAdd(); if (!ModelState.IsValid) { vm.DoReInit(); return PartialView(vm); } else { return FFResult().CloseDialog().RefreshGrid(); } } } ``` -------------------------------- ### C# Code Block for Add Page Logic Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Blazor/Create.txt Contains the C# code-behind logic for the add page. It initializes the view model and form reference, handles component initialization (including a placeholder for custom init logic), defines the form submission logic calling an API endpoint, and provides a method to close the dialog. ```C# private $modelname$VM Model = new $modelname$VM(); private ValidateForm vform { get; set; } $fieldinit$ protected override async Task OnInitializedAsync() { $init$ await base.OnInitializedAsync(); } private async Task Submit(EditContext context) { await PostsForm(vform, "/api/$modelname$/add", (s) => "Sys.OprationSuccess"); } public void OnClose() { CloseDialog(); } ``` -------------------------------- ### Vue Script Setup - Cancel Action Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue3/Edit.txt Defines the `onClose$modelname$` function, which is triggered when the cancel button is clicked. It calls the `closeDialog` helper function to signal the parent component to close the dialog. ```TypeScript // 取消 const onClose$modelname$ = () => { closeDialog(); }; ``` -------------------------------- ### Defining Store Class with API Endpoints Configuration (TypeScript) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/React/store/index.txt This snippet defines a Store class inheriting from DataSource. It configures a set of standard API endpoints (search, details, insert, update, delete, import, export, exportIds, template) using a configuration object passed to the parent constructor. It uses placeholders like $modelname$ for the resource name and {ID} for dynamic parameters in URLs. ```TypeScript import { BindAll } from 'lodash-decorators'; import DataSource from 'store/dataSource'; @BindAll() export class Store extends DataSource { constructor() { super({ // IdKey: "ID", 默认 ID // Target: "/api", 默认 /api Apis: { search: { url: "/$modelname$/search", method: "post" }, details: { // 支持 嵌套 参数 /user/{ID}/{AAA}/{BBB} url: "/$modelname$/{ID}", method: "get" }, insert: { url: "/$modelname$/add", method: "post" }, update: { url: "/$modelname$/edit", method: "put" }, delete: { url: "/$modelname$/BatchDelete", method: "post" }, import: { url: "/$modelname$/import", method: "post" }, export: { url: "/$modelname$/ExportExcel", method: "post" }, exportIds: { url: "/$modelname$/ExportExcelByIds", method: "post" }, template: { url: "/$modelname$/GetExcelTemplate", method: "get" } } }); } } export default new Store(); ``` -------------------------------- ### Defining WalkingTec.Mvvm ListVM and View Class (C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ListVM.txt This snippet defines a standard List ViewModel (`ListVM`) and a nested View class (`_View`) for use in a WalkingTec.Mvvm project. The `ListVM` inherits from `BasePagedListVM` and includes methods for initializing grid headers (`InitGridHeader`) and defining the data search query (`GetSearchQuery`). The `_View` class is used to project data from the model for display. ```C# using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using WalkingTec.Mvvm.Core; using WalkingTec.Mvvm.Core.Extensions; using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; using $modelnamespace$; $othernamespace$ namespace $vmnamespace$ { public partial class $classname$ListVM : BasePagedListVM<$classname$_View, $classname$Searcher> {$actions$ protected override IEnumerable> InitGridHeader() { return new List>{$headers$ this.MakeGridHeaderAction(width: 200) }; }$format$ public override IOrderedQueryable<$classname$_View> GetSearchQuery() { var query = DC.Set<$modelname$>()$where$ .Select(x => new $classname$_View { ID = x.ID,$select$ }) .OrderBy(x => x.ID); return query; } } public class $classname$_View : $modelname${$subpros$ } } ``` -------------------------------- ### Render DataView Search Form (React/JSX) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/React/views/search.txt Renders the DataViewSearch component, passing necessary props like the MobX store, form instance, and calculated models. It includes commented-out examples of overriding default props. ```jsx render() { // item 的 props const props = { ...this.props, models: this.models, defaultValues: toJS(Store.DataSource.searchParams) } return { }} 覆盖默认方法 // onSubmit={() => { }} 覆盖默认方法 Store={Store} form={this.props.form} > {Models.renderModels(props)} } ``` -------------------------------- ### Displaying Batch Delete Confirmation with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the POST request for displaying the batch delete confirmation dialog for multiple entities. It creates a BatchVM instance populated with the provided IDs and returns a partial view. ```C# [HttpPost] [ActionDescription("Sys.BatchDelete")] public ActionResult BatchDelete(string[] IDs) { var vm = Wtm.CreateVM<$modelname$BatchVM>(Ids: IDs); return PartialView(vm); } ``` -------------------------------- ### Testing WTM API Create Method C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ApiTestTopPoco.txt Tests the Add method for creating a new entity. It creates a ViewModel, populates an entity, calls the Add method, asserts a successful response, and then verifies the entity was saved in the database. ```C# [TestMethod] public void CreateTest() { $classnamel$VM vm = _controller.Wtm.CreateVM<$classnamel$VM>(); $model$ v = new $model$(); $cpros$ vm.Entity = v; var rv = _controller.Add(vm); Assert.IsInstanceOfType(rv, typeof(OkObjectResult)); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data = context.Set<$model$>().Find(v.ID); $assert$ } } ``` -------------------------------- ### Test Controller Delete Action Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ControllerTestTopPoco.txt This test checks the controller's Delete action. It adds an entity, retrieves it using the Delete GET action, calls the Delete POST action, and verifies that the entity is removed from the database. ```C# [TestMethod] public void DeleteTest() { $model$ v = new $model$(); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { $pros$ context.Set<$model$>().Add(v); context.SaveChanges(); } PartialViewResult rv = (PartialViewResult)_controller.Delete(v.ID.ToString()); Assert.IsInstanceOfType(rv.Model, typeof($model$VM)); $model$VM vm = rv.Model as $model$VM; v = new $model$(); v.ID = vm.Entity.ID; vm.Entity = v; _controller.Delete(v.ID.ToString(),null); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data = context.Set<$model$>().Find(v.ID); $del$ } } ``` -------------------------------- ### Testing Export Operation - C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ControllerTest.txt Tests the export functionality by calling the controller's Index method to get a list view model and then calling ExportExcel with that model, asserting that the result is a FileContentResult with non-empty content. ```C# PartialViewResult rv = (PartialViewResult)_controller.Index(); Assert.IsInstanceOfType(rv.Model, typeof(IBasePagedListVM)); IActionResult rv2 = _controller.ExportExcel(rv.Model as $model$ListVM); Assert.IsTrue((rv2 as FileContentResult).FileContents.Length > 0); ``` -------------------------------- ### Initializing WTM API Test Class C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ApiTestTopPoco.txt Defines the unit test class for a WTM API controller. The constructor initializes an in-memory DataContext and creates a mock controller instance for testing. ```C# using Microsoft.AspNetCore.Mvc; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Linq; using System.Text; using WalkingTec.Mvvm.Core; using $cns$; using $vns$; using $mns$; using $dns$; $othernamespace$ namespace $tns$ { [TestClass] public class $model$ApiTest { private $classnamel$Controller _controller; private string _seed; public $model$ApiTest() { _seed = Guid.NewGuid().ToString(); _controller = MockController.CreateApi<$classnamel$Controller>(new DataContext(_seed, DBTypeEnum.Memory), "user"); } [TestMethod] public void SearchTest() { ContentResult rv = _controller.Search(new $classnamel$Searcher()) as ContentResult; Assert.IsTrue(string.IsNullOrEmpty(rv.Content)==false); } [TestMethod] public void CreateTest() { $classnamel$VM vm = _controller.Wtm.CreateVM<$classnamel$VM>(); $model$ v = new $model$(); $cpros$ vm.Entity = v; var rv = _controller.Add(vm); Assert.IsInstanceOfType(rv, typeof(OkObjectResult)); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data = context.Set<$model$>().Find(v.ID); $assert$ } } [TestMethod] public void EditTest() { $model$ v = new $model$(); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { $pros$ context.Set<$model$>().Add(v); context.SaveChanges(); } $classnamel$VM vm = _controller.Wtm.CreateVM<$classnamel$VM>(); var oldID = v.ID; v = new $model$(); v.ID = oldID; $epros$ vm.Entity = v; vm.FC = new Dictionary(); $fc$ var rv = _controller.Edit(vm); Assert.IsInstanceOfType(rv, typeof(OkObjectResult)); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data = context.Set<$model$>().Find(v.ID); $eassert$ } } [TestMethod] public void GetTest() { $model$ v = new $model$(); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { $pros$ context.Set<$model$>().Add(v); context.SaveChanges(); } var rv = _controller.Get(v.ID.ToString()); Assert.IsNotNull(rv); } [TestMethod] public void BatchDeleteTest() { $model$ v1 = new $model$(); $model$ v2 = new $model$(); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { $mpros$ context.Set<$model$>().Add(v1); context.Set<$model$>().Add(v2); context.SaveChanges(); } var rv = _controller.BatchDelete(new string[] { v1.ID.ToString(), v2.ID.ToString() }); Assert.IsInstanceOfType(rv, typeof(OkObjectResult)); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data1 = context.Set<$model$>().Find(v1.ID); var data2 = context.Set<$model$>().Find(v2.ID); $mdel$ } rv = _controller.BatchDelete(new string[] {}); Assert.IsInstanceOfType(rv, typeof(OkResult)); } $add$ } } ``` -------------------------------- ### Razor Form Structure with Tag Helpers Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/CreateView.txt This snippet shows the basic structure of a Razor view defining a form. It uses `@model` to specify the view model, `@inject` for dependency injection (localization), and custom `` Tag Helpers to render the form, fields (via a placeholder), and action buttons. ```Razor @model $vmnamespace$.$modelname$VM @inject IStringLocalizer Localizer; $fields$ ``` -------------------------------- ### Vue Script Setup - Emit and Close Dialog Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue3/Edit.txt Defines the events ('refresh', 'closeDialog') that the component can emit using `defineEmits`. The `closeDialog` helper function is defined to emit the 'closeDialog' event, typically used to close a parent dialog or modal. ```TypeScript // 定义子组件向父组件传值/事件 const emit = defineEmits(['refresh','closeDialog']); // 关闭弹窗 const closeDialog = () => { emit('closeDialog'); }; ``` -------------------------------- ### Creating $modelname$ Entity (WTM API C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Blazor/Controller.txt Handles the creation of a new $modelname$ entity. It validates the input VM and performs the add operation. ```C# [ActionDescription("Sys.Create")] [HttpPost("Add")] public IActionResult Add($controllername$VM vm) { if (!ModelState.IsValid) { return BadRequest(ModelState.GetErrorJson()); } else { vm.DoAdd(); if (!ModelState.IsValid) { return BadRequest(ModelState.GetErrorJson()); } else { return Ok(vm.Entity); } } } ``` -------------------------------- ### Vue Script Setup - State and Refs Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue3/Edit.txt Initializes reactive state (`state$modelname$`) to hold the form's view model (`vmModel`) and other potential data. It also defines a ref (`formRef$modelname$`) to access the Element Plus form instance for validation. ```TypeScript // 定义变量内容 const formRef$modelname$ = ref(); const state$modelname$ = reactive({ vmModel: { Entity:{ $fieldentityinit$ }, $selectfieldinit$ }, $fieldinit$ }); ``` -------------------------------- ### Testing API Create Endpoint Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/ApiTest.txt Tests the Add method (Create) of the API controller. It creates a new model instance, populates it, adds it via the controller, and then verifies the creation and audit fields in the database. ```C# [TestMethod] public void CreateTest() { $classnamel$VM vm = _controller.Wtm.CreateVM<$classnamel$VM>(); $model$ v = new $model$(); $cpros$ vm.Entity = v; var rv = _controller.Add(vm); Assert.IsInstanceOfType(rv, typeof(OkObjectResult)); using (var context = new DataContext(_seed, DBTypeEnum.Memory)) { var data = context.Set<$model$>().Find(v.ID); $assert$ Assert.AreEqual(data.CreateBy, "user"); Assert.IsTrue(DateTime.Now.Subtract(data.CreateTime.Value).Seconds < 10); } } ``` -------------------------------- ### Adding DataContext Constructor for Connection String Support (C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/CHANGELOG.md This C# code snippet provides a required constructor for the `DataContext` class when upgrading older WTM projects. The constructor takes a `CS` object (presumably representing connection string information) and passes it to the base class constructor. This allows the framework to initialize the data context using connection string details specified in configuration, enabling features like specifying database type or context via configuration keys. ```C# public DataContext(CS cs) : base(cs) { } ``` -------------------------------- ### Displaying Batch Edit Form with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the POST request for displaying the batch edit form for multiple entities. It creates a BatchVM instance populated with the provided IDs and returns a partial view. ```C# [HttpPost] [ActionDescription("Sys.BatchEdit")] public ActionResult BatchEdit(string[] IDs) { var vm = Wtm.CreateVM<$modelname$BatchVM>(Ids: IDs); return PartialView(vm); } ``` -------------------------------- ### Vue Script Setup - Submit Action Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue3/Edit.txt Defines the `onSubmit$modelname$` function, triggered by the submit button. It validates the form using the form ref. If valid, it calls the API's `edit` method with the form data. On success, it shows a message, emits 'refresh', and closes the dialog. On error, it uses a helper to set form errors. ```TypeScript // 提交 const onSubmit$modelname$ = () => { formRef$modelname$.value?.validate((valid: boolean, fields: any) => { if (valid) { $modelname$Api().edit(state$modelname$.vmModel).then(() => { ElMessage.success(ci.proxy.$t('message._system.common.vm.submittip')); emit('refresh'); closeDialog(); }).catch((error) => { other.setFormError(ci, error); }) } }) }; ``` -------------------------------- ### Downloading $modelname$ Excel Import Template (WTM API C#) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Blazor/Controller.txt Generates and provides an Excel template file for importing $modelname$ data. It uses an ImportVM to generate the template. ```C# [ActionDescription("Sys.DownloadTemplate")] [HttpGet("GetExcelTemplate")] public IActionResult GetExcelTemplate() { var vm = Wtm.CreateVM<$controllername$ImportVM>(); var qs = new Dictionary(); foreach (var item in Request.Query.Keys) { qs.Add(item, Request.Query[item]); } vm.SetParms(qs); var data = vm.GenerateTemplate(out string fileName); return File(data, "application/vnd.ms-excel", fileName); } ``` -------------------------------- ### Vue Script for Data Import Logic (TypeScript) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/Vue3/Import.txt This script uses the Vue 3 Composition API with ``` -------------------------------- ### Use Search Panel Tag Helper Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/ListView.txt Renders a search panel UI component using a custom tag helper, bound to the view model and including a reset button. The $fields$ placeholder indicates where search input fields would be placed. ```Razor $fields$\n ``` -------------------------------- ### Defining Root React Component with Authorization Decorator (TypeScript) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/React/index.txt Defines the main application component for a page, using a decorator for authorization and rendering several child components (Search, Action, Table, Other). It receives props and passes them down to its children. ```TypeScript import * as React from 'react'; import { AuthorizeDecorator } from 'store/system/authorize'; import Store from './store'; import Action from './views/action'; import Other from './views/other'; import Search from './views/search'; import Table from './views/table'; @AuthorizeDecorator({ PageStore: Store }) export default class App extends React.Component { render() { return (
); } } ``` -------------------------------- ### Use Grid Tag Helper Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/ListView.txt Renders a data grid UI component using a custom tag helper, bound to the view model and configured with a URL for fetching data. ```Razor ``` -------------------------------- ### Defining Store Actions and Component Props in WTM form-mixin (TypeScript) Source: https://github.com/dotnetcore/wtm/blob/dotnet8/demo/WalkingTec.Mvvm.VueDemo/ClientApp/README.md Illustrates the use of `@Action` decorator to map store actions (like add, edit, detail) to component methods, allowing direct API calls. Also shows the `@Prop` decorator for defining component properties like `status` to track the current operation state. ```TypeScript @Action("add") add; // 添加 》store @Action("edit") edit; // 修改 》store @Action("detail") detail; // 详情 》store // 表单状态 @Prop({ type: String, default: "" }) status; ``` -------------------------------- ### Importing Dependencies in React/TypeScript Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Spa/React/views/other.txt Imports necessary components (`ImportModal`) and a data store (`Store`) for the React component. ```TypeScript import { ImportModal } from 'components/dataView'; import * as React from 'react'; import Store from '../store'; ``` -------------------------------- ### Searching Data with WalkingTec.Mvvm C# Source: https://github.com/dotnetcore/wtm/blob/dotnet8/src/WalkingTec.Mvvm.Mvc/GeneratorFiles/Mvc/Controller.txt Handles the POST request for searching data. It receives search parameters, validates the model state, and returns the search results as a JSON string using the ListVM. ```C# [ActionDescription("Sys.Search")] [HttpPost] public string Search($modelname$Searcher searcher) { var vm = Wtm.CreateVM<$modelname$ListVM>(passInit: true); if (ModelState.IsValid) { vm.Searcher = searcher; return vm.GetJson(false); } else { return vm.GetError(); } } ```