feat(model):The model driver is optimized, and built-in interfaces for adding, deleting, modifying, and querying are added#1756
Conversation
…into fix/model-driven
…into feat/model-driven
WalkthroughReplaces direct axios calls with a centralized meta API ( Changes
Sequence Diagram(s)sequenceDiagram
participant UI as rgba(70,130,180,0.5) UI Component
participant Meta as rgba(34,139,34,0.5) Meta API (getMetaApi)
participant Service as rgba(178,34,34,0.5) Backend Service
participant Canvas as rgba(218,165,32,0.5) Canvas / Model Store
UI->>Meta: POST/GET to apiInfo.url (payload: { nameEn, nameCn, params, currentPage, pageSize, ... })
Meta->>Service: Forward HTTP request to target URL
Service-->>Meta: Response (status, data)
Meta-->>UI: Raw response returned
Note over UI,Canvas: Model-configurator flow
UI->>Canvas: getCurrentSchema().props.serviceModel (id)
Canvas-->>UI: serviceModel id/baseUrl
UI->>Meta: GET /material-center/api/model/detail/{id}
Meta-->>UI: model detail response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
packages/plugins/model-manager/src/components/ModelBasicForm.vue (1)
42-64:⚠️ Potential issue | 🟡 MinorPreserve the default modelUrl on model switches
Line 42 and Line 60‑64:
localValueinitially merges the defaultmodelUrl, but the watcher replaces it withnewModel, which drops the default whenmodelUrlis absent. That makes the field empty after switching models. Reapply the default in the watcher (and avoidundefined/...when the env var is missing).🛠️ Suggested adjustment
-const localValue = ref({ modelUrl: `${import.meta.env.VITE_ORIGIN}/platform-center/api/model-data`, ...props.model }) +const origin = import.meta.env.VITE_ORIGIN ?? '' +const defaultModelUrl = `${origin}/platform-center/api/model-data` +const localValue = ref({ modelUrl: defaultModelUrl, ...props.model }) ... - (newModel) => { - localValue.value = newModel - }, + (newModel) => { + localValue.value = { modelUrl: defaultModelUrl, ...newModel } + },packages/builtinComponent/src/components/BaseForm.vue (1)
128-140:⚠️ Potential issue | 🟠 MajorAvoid mutating form state by deleting
idLine 133‑139:
delete data.idmutates the reactive model (modelData.value) and can drop the id needed for later update/delete flows. Build a copy for the payload instead.🛠️ Suggested adjustment
- const id = data.id - delete data.id + const { id, ...payload } = data ? { ...data } : {} return getMetaApi(META_SERVICE.Http) .post(apiInfo.url, { nameEn: formModel.value.nameEn, - data: data, + data: payload, params: { id } })packages/builtinComponent/src/components/BaseTable.vue (1)
167-175:⚠️ Potential issue | 🔴 CriticalFix undefined
tableModelreferences in CRUD helpersLine 173/191/214/234:
tableModelis not declared (onlyTableModelexists). Any CRUD call will throw a ReferenceError. UseTableModelconsistently.🛠️ Suggested adjustment
- .post(apiInfo.url, { nameEn: tableModel.value.nameEn, params: data }) + .post(apiInfo.url, { nameEn: TableModel.value.nameEn, params: data }) ... - nameEn: tableModel.value.nameEn, + nameEn: TableModel.value.nameEn, ... - nameEn: tableModel.value.nameEn, - nameCn: tableModel.value.nameCn, + nameEn: TableModel.value.nameEn, + nameCn: TableModel.value.nameCn, ... - .post(apiInfo.url, { ...evidence, nameEn: tableModel.value.nameEn }) + .post(apiInfo.url, { ...evidence, nameEn: TableModel.value.nameEn })Also applies to: 182-194, 203-216, 228-235
packages/builtinComponent/src/components/BasePage.vue (1)
320-332:⚠️ Potential issue | 🟠 MajorDon’t delete
idfrom edit form dataLine 325‑332: updateApi removes
data.idin place, which mutatesaddFormDataand can cause the dialog to lose the record id. Use a payload copy without mutating form state.🛠️ Suggested adjustment
- const id = data.id - delete data.id + const { id, ...payload } = data ? { ...data } : {} return getMetaApi(META_SERVICE.Http) .post(apiInfo.url, { nameEn: pageModel.value.nameEn, - data: data, + data: payload, params: { id } })
🤖 Fix all issues with AI agents
In `@packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue`:
- Around line 175-178: getModel currently only sets selectedModel and
methodBasicData.method, which can leave stale values in selectedFunction and
methodBasicData.url; update getModel to also clear selectedFunction (e.g. reset
selectedFunction or selectedFunction.value) and reset methodBasicData.url to an
empty string when switching models, keeping the existing methodBasicData.method
= 'post' behavior and ensuring you clear the reactive references
(selectedFunction and methodBasicData.url) so the UI does not show stale data.
In `@packages/plugins/model-manager/src/components/FieldManager.vue`:
- Around line 89-95: The inline edit for the defaultValue column must be
disabled for ModelRef types and the read-only cell should show the referenced
model's label instead of the raw ID: update the tiny-grid-column template (the
block using row.isEditing and row.defaultValue) to conditionally render the
tiny-input only when row.type !== 'ModelRef', and for ModelRef rows render the
resolved label (e.g., use an existing property like row.defaultValueLabel or
call a resolver method such as resolveModelLabel(row.defaultValue)). Ensure any
v-model binding to row.defaultValue is not applied for ModelRef in-line edits so
the expanded-panel select remains the single source of truth and invalid IDs
cannot be persisted.
packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/builtinComponent/src/components/BasePage.vue (1)
457-462:⚠️ Potential issue | 🟠 MajorRefresh table data after successful deletion.
Unlike
confirmSubmitwhich callsqueryApi()after insert/update,deleteRowdoes not refresh the table after deletion. The deleted row remains visible until the user manually refreshes.🔧 Proposed fix
const deleteRow = (rowData) => { const evidence = { id: rowData.id } - Modal.confirm('您确定要删除吗?').then(() => { - deleteApi(evidence) + Modal.confirm('您确定要删除吗?').then(async () => { + await deleteApi(evidence) + await queryApi() }) }
🤖 Fix all issues with AI agents
In `@packages/builtinComponent/src/components/BasePage.vue`:
- Around line 334-341: Remove the debug console.log in the Promise .then handler
inside BasePage.vue (the anonymous arrow function that receives res and triggers
Notify), so the handler returns res and shows the success Notify without calling
console.log; simply delete the console.log(res) line from that .then callback to
satisfy the no-console ESLint rule.
- Around line 361-367: Remove the debug console.log from the Promise .then
handler that processes the API response: inside the .then((res) => { ... })
block where you set tableData.value = res.list, pagerState.total = res.total,
and emit('update:tableData', tableData.value), delete the console.log(res) call
so ESLint no-console no longer fails; keep the rest of the logic (return res)
unchanged.
- Around line 305-315: Remove the debug console.log from the promise chain:
inside the .then((res) => { ... }) callback of
getMetaApi(META_SERVICE.Http).post(...) (the block that calls Notify and returns
res), delete the console.log(res) statement so the ESLint no-console rule no
longer fails; keep the Notify call and return res unchanged.
- Around line 380-388: In the .then((res) => { ... }) callback inside
BasePage.vue remove the debug console.log(res) statement to satisfy ESLint
no-console; keep the Notify call and the final return res intact so the promise
chain behavior doesn't change.
- Around line 326-333: The code mutates the input object by doing `delete
data.id`; instead, create a shallow copy (e.g., via object rest or spread) so
the original reactive `data`/`addFormData.value` is not modified: extract `id`
from `data` (const { id, ...payload } = data or const payload = { ...data } and
delete payload.id) and pass `payload` to getMetaApi(META_SERVICE.Http).post(...)
while keeping `params: { id }` and using `pageModel.value.nameEn` as before.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In
`@packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue`:
- Around line 60-61: Remove all console.log statements in
NestedPropertyConfigurator.vue (e.g., the console.log(res) inside the Promise
.then callbacks and the other occurrences noted at the same block ranges) and
either drop them or replace them with the project logger (e.g., call the shared
logger method used across the app). Locate the Promise handlers where
console.log is used (the .then((res) => { ... }) callbacks and similar callbacks
at the other noted spots) and replace console.log(...) with a proper logger call
(or remove the call) so the static checks no longer fail.
- Around line 50-134: The CRUD handlers insertApi, updateApi, queryApi and
deleteApi currently send hard-coded payloads (nameEn/id/name) making them
unusable for dynamic models; change them to accept payload or options from
props/meta or caller (e.g., expose functions that take a data object or use
reactive props like modelName, idField, and payloadRefs) and build the request
body from those values before calling getMetaApi(META_SERVICE.Http). Ensure
queryApi maps response into tableData.value and pagerState.total as now and that
update:tableData emits use the passed/prop-driven values rather than fixed
literals.
- Around line 98-111: queryApi references tableData and pagerState and emits
'update:tableData' but tableData and pagerState are not defined in setup and the
emit is not declared; declare reactive refs (e.g., const tableData = ref([]) and
const pagerState = reactive({ total: 0, currentPage: 1, pageSize: 10 })), add
'update:tableData' to the component's emits array/object, ensure queryApi uses
those refs (tableData.value, pagerState.total) and finally return tableData and
pagerState from setup so the template/other code can access them.
packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue
Outdated
Show resolved
Hide resolved
packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue
Outdated
Show resolved
Hide resolved
packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue`:
- Around line 62-66: The call to Notify(...) in NestedPropertyConfigurator.vue
is missing an import and will throw; fix by either importing and using the
useNotify composable (import { useNotify } from
'@opentiny/tiny-engine-meta-register', call const notify = useNotify() inside
setup and replace Notify(...) with notify(...)) or import Notify directly
(import { Notify } from '@opentiny/vue') and keep the Notify(...) call; update
the code around the existing Notify invocation (lines with Notify) and the
component setup block where composables are initialized.
🧹 Nitpick comments (1)
packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue (1)
3-6: Settype="button"on CRUD buttons.Avoid accidental form submission if this component is rendered inside a
<form>.🔧 Suggested update
- <button `@click`="insertApi">新增</button> - <button `@click`="updateApi">修改</button> - <button `@click`="queryApi">查询</button> - <button `@click`="deleteApi">删除</button> + <button type="button" `@click`="insertApi">新增</button> + <button type="button" `@click`="updateApi">修改</button> + <button type="button" `@click`="queryApi">查询</button> + <button type="button" `@click`="deleteApi">删除</button>
packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue`:
- Around line 3-6: The click handlers call async methods (insertApi, updateApi,
queryApi, deleteApi) without handling rejections leading to unhandled promise
errors; fix by ensuring each button either calls a small wrapper that calls the
async method and handles errors (e.g. use an inline arrow function that calls
insertApi().catch(err => /* log/notify */) for each button) or update the async
methods themselves (insertApi, updateApi, queryApi, deleteApi) to catch and
handle errors before they propagate; make sure the error handler logs or shows a
user-friendly message rather than silently swallowing errors.
- Around line 69-71: Replace the existing catch handlers that do throw new
Error(err) with logic that preserves the original error stack: in each .catch
callback in NestedPropertyConfigurator.vue (the arrow functions currently
written as .catch((err) => { throw new Error(err) })) check if err is an
instance of Error and rethrow it (throw err); otherwise wrap with a new
Error(String(err)) to preserve information. Apply this change to all occurrences
where throw new Error(err) appears (the four catch handlers).
packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue
Outdated
Show resolved
Hide resolved
packages/configurator/src/nested-property-configurator/NestedPropertyConfigurator.vue
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@packages/builtinComponent/src/components/BaseForm.vue`:
- Around line 133-134: The current code mutates the input parameter by doing
"delete data.id", which removes id from the original modelData.value and breaks
later code (e.g., deleteApi). Fix by avoiding mutation: create a shallow copy
without id via destructuring (capture id and rest into a new payload) and use
that payload for subsequent operations instead of mutating data; keep references
to modelData.value and deleteApi intact so other logic that reads
modelData.value?.id still works.
- Around line 154-155: The code is referencing an undefined variable pageModel
which will throw a ReferenceError when queryApi runs; update the params
construction to use the existing formModel (i.e., replace pageModel with
formModel) so it reads from formModel.value.parameters, or alternatively ensure
a pageModel is properly declared before use — adjust the line that builds params
(currently using pageModel.value.parameters) in the queryApi-related block to
reference formModel.value.parameters and keep the same mapping of item.prop to
null.
- Around line 175-181: The exposed function deleteApi was changed to drop its
evidence parameter which breaks callers like BasePage.vue that pass a custom id;
restore the parameter (e.g., deleteApi(evidence = { id: modelData.value?.id,
nameEn: formModel.value?.nameEn })) and use the provided evidence when present
instead of always reading modelData.value, ensuring you still fall back to
modelData/formModel defaults; update the deleteApi implementation that finds
apiInfo via props.modelApis and calls
getMetaApi(META_SERVICE.Http).post(apiInfo.url, evidence) so external callers
continue to work without breaking the public API.
🧹 Nitpick comments (1)
packages/builtinComponent/src/components/BaseForm.vue (1)
118-125: Redundant promise handlers and lost error context.The
.then((res) => { return res })is a no-op and can be removed. The.catch((err) => { throw new Error(err) })wraps the original error, losing the stack trace. Same pattern appears in all API methods.♻️ Suggested simplification
return getMetaApi(META_SERVICE.Http) .post(apiInfo.url, { nameEn: formModel.value.nameEn, params: data }) - .then((res) => { - return res - }) - .catch((err) => { - throw new Error(err) - })
…o feat/model-driven
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/builtinComponent/src/components/BaseTable.vue (2)
184-194:⚠️ Potential issue | 🔴 CriticalMutation of input parameter corrupts caller's data.
delete data.idmutates the input object. WhenupdateApiis called externally with an object reference, this permanently removes theidproperty from the caller's object, which may break subsequent operations.🐛 Proposed fix using destructuring
const updateApi = (data) => { const apiInfo = props.modelApis.find((api) => api.nameEn === 'updateApi') if (!apiInfo) { return undefined } - const id = data.id - delete data.id + const { id, ...restData } = data return getMetaApi(META_SERVICE.Http) .post(apiInfo.url, { - nameEn: tableModel.value.nameEn, - data: data, + nameEn: TableModel.value.nameEn, + data: restData, params: { id } })
204-224:⚠️ Potential issue | 🔴 CriticalFix undefined
tableModelreferences inqueryApi.Lines 205, 210, and 211 reference undefined
tableModel. UseTableModel(the computed property) orprops.serviceModelinstead.🐛 Proposed fix
// 处理查询参数 - const params = Object.fromEntries(tableModel.value.parameters.map((item) => [item.prop, null])) + const params = Object.fromEntries(TableModel.value.parameters.map((item) => [item.prop, null])) return getMetaApi(META_SERVICE.Http) .post(apiInfo.url, { currentPage: currentPage || 1, pageSize: pageSize || 10, - nameEn: tableModel.value.nameEn, - nameCn: tableModel.value.nameCn, + nameEn: TableModel.value.nameEn, + nameCn: TableModel.value.nameCn, params: {
🤖 Fix all issues with AI agents
In `@packages/builtinComponent/src/components/BaseTable.vue`:
- Around line 172-176: The runtime ReferenceError is caused by using the
undefined lowercase symbol tableModel instead of the computed TableModel; update
all API functions (insertApi, updateApi, queryApi, deleteApi) to reference
TableModel.value (e.g. TableModel.value.nameEn, TableModel.value.parameters,
TableModel.value.nameCn) where they currently use tableModel.value, keeping the
surrounding calls to getMetaApi(META_SERVICE.Http).post(...) and the existing
.catch handling unchanged.
- Around line 232-236: The deleteApi call references an undefined
tableModel.value.nameEn; fix it by replacing that reference with the actual
state/prop used in this component (e.g. use model.value.nameEn if the reactive
ref is named model, or use props.tableModel.nameEn if it’s passed as a prop).
Update the argument in the getMetaApi(...).post(...) call inside deleteApi to
use the correct identifier used elsewhere in this file (search for existing
usages like model, tableModelRef, or props.tableModel) so the nameEn value is
read from the defined variable instead of tableModel.
In `@packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue`:
- Line 172: Remove the stray debug console.log calls (e.g., the console.log(res)
and the other console.log present later) from ModelApiConfigurator.vue so
production code has no console debugging and ESLint warnings are resolved;
locate the console.log statements inside the component's methods and delete them
(or replace with proper processLogger/this.$logger calls if persistent logging
is needed).
- Around line 159-162: The ESLint error is caused by calling getModel inside
openPopover before getModel is defined; move the getModel function definition so
it appears before the openPopover const (or convert getModel to a hoisted
function declaration) so that getModel is defined when openPopover calls it;
update the code so getModel is declared above openPopover (references: getModel
and openPopover).
🧹 Nitpick comments (2)
packages/configurator/src/model-common/ModelSelect.vue (1)
91-94: Consider adding error handling for the async operation.If
handleSelectedModelParametersthrows or rejects, the error will propagate unhandled, potentially leaving the UI in an inconsistent state with no feedback to the user.💡 Suggested improvement
const selectModel = async (data) => { - currentSelectedModel.value = await handleSelectedModelParameters(data.row) - emit('modelSelect', currentSelectedModel.value) + try { + currentSelectedModel.value = await handleSelectedModelParameters(data.row) + emit('modelSelect', currentSelectedModel.value) + } catch (err) { + console.error('Failed to process model parameters:', err) + // Optionally show user notification + } }packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue (1)
218-228: Remove or document commented-out code.The commented-out block suggests incomplete implementation. Either complete and enable the functionality, or remove the dead code and track the TODO in a separate issue.
packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue
Show resolved
Hide resolved
packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue`:
- Around line 204-207: In selectModelFunction, guard against missing or empty
selectedModel.value.baseUrl before building methodBasicData.url: check
selectedModel.value && selectedModel.value.baseUrl (or trim() length) and only
set methodBasicData.url to
`${selectedModel.value.baseUrl}/${selectedFunction.value.nameEn}` when valid;
otherwise use a safe fallback (e.g., an empty string, null, or a default base
URL) and/or log/flag the missing baseUrl so callers know the URL is not set.
Ensure you reference selectedFunction.value.nameEn when constructing the URL and
update any downstream logic that expects methodBasicData.url accordingly.
- Around line 209-225: The watch callback uses model.baseUrl but elsewhere
(selectModelFunction/getModel) the enriched data lives on selectedModel.value,
and it also assumes selectedModel.value.method is an array; change the URL
construction to use selectedModel.value.baseUrl (not model.baseUrl) for
consistency, and add a null/array guard before mapping (e.g., const methods =
Array.isArray(selectedModel.value?.method) ? selectedModel.value.method : []),
then map over methods to build modelValue.value and emit('update:modelValue',
modelValue.value); keep the existing getModel() call and ensure you handle the
case when selectedModel.value is undefined by skipping the map/emit.
🧹 Nitpick comments (1)
packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue (1)
74-74:definePropsanddefineEmitsdon't need to be imported in<script setup>.These are compiler macros automatically available in
<script setup>blocks. While Vue handles this gracefully (the imports are effectively no-ops), removing them keeps the code cleaner.-import { ref, reactive, defineProps, defineEmits, watch } from 'vue' +import { ref, reactive, watch } from 'vue'
packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue
Show resolved
Hide resolved
packages/configurator/src/model-api-configurator/ModelApiConfigurator.vue
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/configurator/src/model-configurator/ModelConfigurator.vue (1)
361-369:⚠️ Potential issue | 🟠 MajorRecalculate
unusedParameterswhen model changes via the watcher.When
props.meta.widget.props.modelValuechanges, the watcher updates bothmodelDetailandoriginModelData, but it does not recalculateunusedParameters. This leaves the unused parameters list stale compared to the newly selected model.In
onMounted,unusedParametersis calculated by filteringoriginModelData.parametersagainst the currentmodelDetail.parameters. The same logic should apply when the model is updated via the watcher to ensure the UI displays the correct list of unused parameters.Add the unused parameters calculation to the watcher:
Suggested change
watch( () => props.meta.widget.props.modelValue, (value) => { if (value) { modelDetail.value = value originModelData.value = value unusedParameters.value = originModelData.value.parameters.filter((item) => { if (modelDetail.value.parameters.find((usedParams) => usedParams.prop === item.prop)) { return false } return true }) } } )
English | 简体中文
PR
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Background and solution
What is the current behavior?
原有模型驱动没有内置的增删改查接口,需要用户自定义接口
Issue Number: N/A
What is the new behavior?
后端内置了增删改查接口,前端改动自动匹配对应接口,如果需要修改为自己的接口就改动baseUrl即可
Does this PR introduce a breaking change?
Other information
Summary by CodeRabbit
New Features
Improvements
Style