Atom
is the most basic element of CabloyJS, such as article
, announcement
, leave application
, etc.
Through the combination of Atom
, we can achieve any desired requirements, such as CMS
, OA
, CRM
, ERP
and so on.
It is precisely because a general concept of Atom
has been abstracted from various business models
, that CabloyJS realizes many common features and functions for Atom
, thus enabling various practical business conveniently
For more detailed concepts of Atom
, see: Cabloy: Basic Concepts of Atom
Here, the basic concepts and usage are introduced mainly through the atomClass party
Business Module & Atom Class
When we create a business module, we will automatically create an atom class. For example, the atom class of party
in the module test-party
. Since the module test-party
already exists, the command to create the module is listed here, and it does not need to be executed again
- 1$ cd /path/to/project
- 2$ npm run cli :create:module test-party -- [--template=module-business] [--suite=test-party]
Name | Description |
---|---|
moduleName | Module Name, such as test-party |
template | Template Name, such as module-business |
suite | Suite Name, such as test-party . The test-party suite contains many modules, and the test-party module is just one of them |
Declaration of Atom Class
Atom Class
is the metadata information corresponding to Atom
, which is also set in the meta.js
file of the module
src/suite-vendor/test-party/modules/test-party/backend/src/meta.js
- 1const meta = {
- 2 base: {
- 3 atoms: {
- 4 party: {
- 5 info: {
- 6 bean: 'party',
- 7 title: 'Party',
- 8 tableName: 'testParty',
- 9 tableNameModes: {
- 10 default: 'testPartyView',
- 11 },
- 12 language: false,
- 13 category: true,
- 14 tag: true,
- 15 },
- 16 actions: {
- 17 },
- 18 validator: 'party',
- 19 search: {
- 20 validator: 'partySearch',
- 21 },
- 22 },
- 23 },
- 24 },
- 25};
Name | Description |
---|---|
info.bean | The Bean Component of Atom Class |
info.title | Atom Class’s title |
info.tableName | The data table of Atom Class |
info.tableNameModes.default | Can specify data view as needed |
info.language | Whether to enable localization feature |
info.category | Whether to enable category feature |
info.tag | Whether to enable tag feature |
validator | Used to render form and validate form data |
search.validator | Used to render custom search form fields |
Data Table
Data schema
change management related to the module is in the bean component version.manager
src/suite-vendor/test-party/modules/test-party/backend/src/bean/version.manager.js
- 1async update(options) {
- 2 if (options.version === 1) {
- 3 // create table: testParty
- 4 let sql = `
- 5 CREATE TABLE testParty (
- 6 id int(11) NOT NULL AUTO_INCREMENT,
- 7 createdAt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- 8 updatedAt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- 9 deleted int(11) DEFAULT '0',
- 10 iid int(11) DEFAULT '0',
- 11 atomId int(11) DEFAULT '0',
- 12 personCount int(11) DEFAULT '0',
- 13 partyTypeId int(11) DEFAULT '0',
- 14 PRIMARY KEY (id)
- 15 )
- 16 `;
- 17 await this.ctx.model.query(sql);
- 18 }
- 19}
src/suite-vendor/test-party/modules/test-party/backend/src/beans.js
- 1const versionManager = require('./bean/version.manager.js');
- 2
- 3module.exports = app => {
- 4 const beans = {
- 5 // version
- 6 'version.manager': {
- 7 mode: 'app',
- 8 bean: versionManager,
- 9 },
- 10 };
- 11 return beans;
- 12};
Model
Defining model objects corresponding to data tables makes it easier to manipulate data
src/suite-vendor/test-party/modules/test-party/backend/src/model/party.js
- 1module.exports = app => {
- 2 class Party extends app.meta.Model {
- 3 constructor(ctx) {
- 4 super(ctx, { table: 'testParty', options: { disableDeleted: false } });
- 5 }
- 6 }
- 7 return Party;
- 8};
Name | Default | Description |
---|---|---|
table | The name of the data table or view corresponding to the model object | |
disableDeleted | false | Disable Soft Deletion feature |
Form Validation
CabloyJS’s Form Validation
mechanism uses ajv
. Suggest you have a preliminary understanding of ajv
With the Form Validation
, we can automatically render the form by defining the business-related JSON Schema
, and validate the form data automatically. If the form data does not meet expectations, the error messages will be displayed automatically
For more information about Form Validation
, see: Cabloy: Form Validation
src/suite-vendor/test-party/modules/test-party/backend/src/config/validation/schemas.js
- 1module.exports = app => {
- 2 const schemas = {};
- 3 // party
- 4 schemas.party = {
- 5 type: 'object',
- 6 properties: {
- 7 atomName: {
- 8 type: 'string',
- 9 ebType: 'text',
- 10 ebTitle: 'Party Name',
- 11 notEmpty: true,
- 12 },
- 13 personCount: {
- 14 type: 'number',
- 15 ebType: 'text',
- 16 ebTitle: 'Person Count',
- 17 minimum: 1,
- 18 notEmpty: true,
- 19 },
- 20 partyTypeId: {
- 21 type: 'number',
- 22 ebType: 'select',
- 23 ebTitle: 'Party Type',
- 24 ebOptionsUrl: '/test/party/party/types',
- 25 ebOptionTitleKey: 'name',
- 26 ebOptionValueKey: 'id',
- 27 ebOptionsBlankAuto: true,
- 28 notEmpty: true,
- 29 },
- 30 atomCategoryId: {
- 31 type: 'number',
- 32 ebType: 'category',
- 33 ebTitle: 'Category',
- 34 },
- 35 atomTags: {
- 36 type: [ 'string', 'null' ],
- 37 ebType: 'tags',
- 38 ebTitle: 'Tags',
- 39 },
- 40 },
- 41 };
- 42 // party search
- 43 schemas.partySearch = {
- 44 type: 'object',
- 45 properties: {
- 46 partyTypeId: {
- 47 type: 'number',
- 48 ebType: 'select',
- 49 ebTitle: 'Party Type',
- 50 ebOptionsUrl: '/test/party/party/types',
- 51 ebOptionTitleKey: 'name',
- 52 ebOptionValueKey: 'id',
- 53 ebOptionsBlankAuto: true,
- 54 },
- 55 },
- 56 };
- 57 return schemas;
- 58};
Atom Bean
& Atom Action
CabloyJS refers to all operations of business data as Atom Action
, which fall into two main categories:
Basic Action
: create、read、write、deleteCustom Action
:business-specific operations, such asreview
,publish
, etc.
Just provide a bean component for the atom class to encapsulate the business logic of all atom actions
src/suite-vendor/test-party/modules/test-party/backend/src/bean/atom.party.js
- 1module.exports = app => {
- 2
- 3 const gPartyTypeEmojis = {
- 4 Birthday: '🎂',
- 5 Dance: '💃',
- 6 Garden: '🏡',
- 7 };
- 8
- 9 class Atom extends app.meta.AtomBase {
- 10
- 11 async create({ atomClass, item, user }) {
- 12 // super
- 13 const key = await super.create({ atomClass, item, user });
- 14 // add party
- 15 const res = await this.ctx.model.party.insert({
- 16 atomId: key.atomId,
- 17 });
- 18 return { atomId: key.atomId, itemId: res.insertId };
- 19 }
- 20
- 21 async read({ atomClass, options, key, user }) {
- 22 // super
- 23 const item = await super.read({ atomClass, options, key, user });
- 24 if (!item) return null;
- 25 // read
- 26 await this._getMeta(item, options);
- 27 // ok
- 28 return item;
- 29 }
- 30
- 31 async select({ atomClass, options, items, user }) {
- 32 // super
- 33 await super.select({ atomClass, options, items, user });
- 34 // select
- 35 for (const item of items) {
- 36 await this._getMeta(item, options);
- 37 }
- 38 }
- 39
- 40 async write({ atomClass, target, key, item, options, user }) {
- 41 // super
- 42 await super.write({ atomClass, target, key, item, options, user });
- 43 // update party
- 44 const data = await this.ctx.model.party.prepareData(item);
- 45 data.id = key.itemId;
- 46 await this.ctx.model.party.update(data);
- 47 }
- 48
- 49 async delete({ atomClass, key, user }) {
- 50 // delete party
- 51 await this.ctx.model.party.delete({
- 52 id: key.itemId,
- 53 });
- 54 // super
- 55 await super.delete({ atomClass, key, user });
- 56 }
- 57
- 58 async _getMeta(item, options) {
- 59 // layout: list/table/mobile/pc
- 60 const layout = options && options.layout;
- 61 // meta
- 62 const meta = this._ensureItemMeta(item);
- 63 // meta.flags
- 64 if (item.partyOver) {
- 65 meta.flags.push(this.ctx.text('PartyOverFlag'));
- 66 }
- 67 if (layout !== 'table' && item.personCount) {
- 68 meta.flags.push(item.personCount + 'P');
- 69 }
- 70 // meta.summary
- 71 if (item.partyTypeCode) {
- 72 const dictItem = await this.ctx.bean.dict.findItem({
- 73 dictKey: 'test-party:dictPartyType',
- 74 code: item.partyTypeCode,
- 75 });
- 76 meta.summary = `${dictItem.options.emoji}${dictItem.titleLocaleFull}`;
- 77 }
- 78 }
- 79
- 80 }
- 81
- 82 return Atom;
- 83};
Name | Description |
---|---|
create | create a new record of party |
read | select one record of party |
select | select some records of party, supporting paged |
write | update one record of party |
delete | delete one record of party |
src/suite-vendor/test-party/modules/test-party/backend/src/beans.js
- 1const atomParty = require('./bean/atom.party.js');
- 2
- 3module.exports = app => {
- 4 const beans = {
- 5 // atom
- 6 'atom.party': {
- 7 mode: 'app',
- 8 bean: atomParty,
- 9 },
- 10 };
- 11 return beans;
- 12};
Comments: