签入版本

This commit is contained in:
2026-10-10 12:24:24 +08:00
parent 49b04a1ec4
commit 3423dea03f
11 changed files with 2372 additions and 43 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,4 @@
allowBuilds:
'@parcel/watcher': set this to true or false
esbuild: set this to true or false
vue-demi: set this to true or false
@@ -53,6 +53,8 @@
```typescript
// Axios 响应拦截器
import { message } from 'ant-design-vue';
axios.interceptors.response.use(response => {
const { code, msg, data } = response.data;
@@ -67,12 +69,12 @@ axios.interceptors.response.use(response => {
}
if (code === 403) {
ElMessage.error(msg || '无权限');
message.error(msg || '无权限');
return;
}
// 其他错误
ElMessage.error(msg || '操作失败');
message.error(msg || '操作失败');
return Promise.reject(new Error(msg));
});
```
@@ -253,6 +253,7 @@ $this->fail('缺少id参数', 1);
```typescript
// src/utils/http/axios/index.ts
import { message } from 'ant-design-vue';
axios.interceptors.response.use(
response => {
@@ -272,16 +273,16 @@ axios.interceptors.response.use(
// 权限不足
if (code === 403) {
ElMessage.error(msg || '无访问权限');
message.error(msg || '无访问权限');
return Promise.reject(new Error(msg));
}
// 其他业务错误
ElMessage.error(msg || '操作失败');
message.error(msg || '操作失败');
return Promise.reject(new Error(msg));
},
error => {
ElMessage.error('网络错误');
message.error('网络错误');
return Promise.reject(error);
}
);
@@ -305,9 +306,9 @@ const handleImport = async (file) => {
const res = await importUsers(file);
// res = { count: 8, errors: [{ row: 3, reason: "..." }] }
if (res.errors.length === 0) {
ElMessage.success(`成功导入 ${res.count} 条`);
message.success(`成功导入 ${res.count} 条`);
} else {
ElMessage.warning(`成功 ${res.count} 条,失败 ${res.errors.length} 条`);
message.warning(`成功 ${res.count} 条,失败 ${res.errors.length} 条`);
}
};
```
@@ -104,7 +104,7 @@ export function exampleBatchDelete(data: any) {
```vue
<script setup lang="ts">
import { getExamplePage, exampleDelete } from '@/api/tool/example';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Modal, message } from 'ant-design-vue';
const tableData = ref([]);
@@ -116,10 +116,15 @@ const fetchData = async () => {
// 删除
const handleDelete = async (id) => {
await ElMessageBox.confirm('确认删除?', '提示', { type: 'warning' });
await exampleDelete(id);
ElMessage.success('删除成功');
fetchData();
Modal.confirm({
title: '提示',
content: '确认删除?',
onOk: async () => {
await exampleDelete(id);
message.success('删除成功');
fetchData();
},
});
};
</script>
```
@@ -30,6 +30,8 @@ config.headers['Authorization'] = `Bearer ${token}`;
### 响应拦截器(统一错误处理)
```typescript
import { message } from 'ant-design-vue';
// 响应处理逻辑
const { code, data, msg } = res.data;
@@ -43,7 +45,7 @@ if (code === 401) {
}
// 其他错误,显示提示
ElMessage.error(msg || '操作失败');
message.error(msg || '操作失败');
```
:::tip 响应处理规则
@@ -80,8 +80,8 @@ export default {
<template>
<div>
<!-- 基础翻译 -->
<el-button>{{ $t('common.search') }}</el-button>
<el-button>{{ $t('common.reset') }}</el-button>
<a-button>{{ $t('common.search') }}</a-button>
<a-button>{{ $t('common.reset') }}</a-button>
<!-- 带参数翻译 -->
<p>{{ $t('message.welcome', { name: 'Admin' }) }}</p>
@@ -134,15 +134,17 @@ const columns = computed(() => [
```vue
<!-- ui/src/components/LangSwitch/index.vue -->
<template>
<el-dropdown @command="switchLang">
<el-button :icon="Icon" circle />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="zh-CN">中文</el-dropdown-item>
<el-dropdown-item command="en-US">English</el-dropdown-item>
</el-dropdown-menu>
<a-dropdown>
<a-button>
<GlobeOutlined />
</a-button>
<template #overlay>
<a-menu @click="({ key }) => switchLang(key)">
<a-menu-item key="zh-CN">中文</a-menu-item>
<a-menu-item key="en-US">English</a-menu-item>
</a-menu>
</template>
</el-dropdown>
</a-dropdown>
</template>
<script setup lang="ts">
@@ -23,7 +23,7 @@
| `ui/src/views/{app}/{name}/index.vue` | index.vue.tpl | 列表页(含搜索、表格、新增/编辑/详情弹窗、导入导出按钮) |
| `ui/src/views/{app}/{name}/edit.vue` | edit.vue.tpl | 编辑弹窗(新增/复用) |
| `ui/src/views/{app}/{name}/detail.vue` | detail.vue.tpl | 详情弹窗 |
| `ui/src/views/{app}/{name}/columns.ts` | columns.ts.tpl | 表格列配置(含图片 ElAvatar、选项 ElTag、链接等渲染) |
| `ui/src/views/{app}/{name}/columns.ts` | columns.ts.tpl | 表格列配置(含图片 Avatar、选项 Tag、链接等渲染) |
| `ui/src/views/{app}/{name}/querySchemas.ts` | querySchemas.ts.tpl | 查询表单配置(按字段类型自动选 Input/Select/InputNumber/DatePicker) |
### 前端文件(ui2/ 树形模板 — 4 个文件)
@@ -64,7 +64,7 @@ public function getTableList(): array
| 类型 | VARCHAR |
| 匹配 | 注释或字段名匹配 `/图片\|封面\|头像\|logo\|icon\|image\|avatar\|photo/i` |
识别后:`is_image = true`,归入 `file_fields`,前端用 ElAvatar 渲染。
识别后:`is_image = true`,归入 `file_fields`,前端用 Avatar 渲染。
### 富文本字段
@@ -102,12 +102,12 @@ public function getTableList(): array
标签颜色映射:
| 选项值 | 标签颜色 | Element Plus type |
| 选项值 | 标签颜色 | Ant Design color |
|--------|---------|-------------------|
| 1 | 绿色 | `success` |
| 2 | 红色 | `danger` |
| 2 | 红色 | `error` |
| 3 | 橙色 | `warning` |
| 其他 | 灰色 | `info` |
| 其他 | 灰色 | `default` |
识别后:`choices` 数组非空,自动归入 `eq_fields`(精确匹配)和 `serialize_maps`(字典映射)。
@@ -107,7 +107,7 @@ $field = [
'default' => 0, // 默认值
'is_image' => false, // 是否为图片字段
'is_rich_text' => false, // 是否为富文本字段
'choices' => [ // 选项列表(有值时可生成 ElTag 渲染)
'choices' => [ // 选项列表(有值时可生成 Tag 渲染)
['value' => 0, 'label' => '正常', 'type' => 'success'],
['value' => 1, 'label' => '禁用', 'type' => 'danger'],
],
@@ -159,28 +159,37 @@ class <?php echo $model_class_name ?>Logic extends BaseLogic
```typescript
import { h } from 'vue';
import { ElAvatar, ElTag } from 'element-plus';
import { Tag, Avatar } from 'ant-design-vue';
export const columns = [
{ type: 'selection' },
{ label: 'ID', prop: 'id', fixed: 'left', width: 50 },
{
title: 'ID',
dataIndex: '<?php echo $primary_key ?>',
fixed: 'left',
width: 50,
},
<?php foreach ($list_fields as $field): ?>
{
label: '<?php echo $field['label'] ?>',
prop: '<?php echo $field['camel_name'] ?>',
title: '<?php echo $field['label'] ?>',
dataIndex: '<?php echo $field['camel_name'] ?>',
key: '<?php echo $field['camel_name'] ?>',
<?php if ($field['is_image']): ?>
render(record) {
return h(ElAvatar, { size: 48, src: record.row.<?php echo $field['camel_name'] ?> });
customRender({ record }) {
return h(Avatar, {
size: 48,
src: record.<?php echo $field['camel_name'] ?>,
shape: 'square',
});
},
<?php elseif ($field['choices']): ?>
render(record) {
const map = {
customRender({ record }) {
const statusMap = {
<?php foreach ($field['choices'] as $choice): ?>
<?php echo $choice['value'] ?>: { text: '<?php echo $choice['label'] ?>', type: '<?php echo $choice['type'] ?>' },
<?php echo $choice['value'] ?>: { text: '<?php echo $choice['label'] ?>', color: '<?php echo ($choice['type'] === 'danger') ? 'error' : (($choice['type'] === 'info') ? 'default' : $choice['type']) ?>' },
<?php endforeach; ?>
};
const s = map[record.row.<?php echo $field['camel_name'] ?>];
return h(ElTag, { type: s?.type || 'info' }, { default: () => s?.text });
const status = statusMap[record.<?php echo $field['camel_name'] ?>];
return h(Tag, { color: status?.color || 'default' }, { default: () => status?.text });
},
<?php endif; ?>
},
@@ -221,7 +230,7 @@ export const columns = [
| `index.vue` | 列表页 | 导入 columns.ts、querySchemas.ts |
| `edit.vue` | 编辑弹窗 | 被 index.vue 动态加载 |
| `detail.vue` | 详情弹窗 | 被 index.vue 动态加载 |
| `columns.ts` | 表格列配置 | 被 index.vue 导入,含 ElTag/ElAvatar 渲染 |
| `columns.ts` | 表格列配置 | 被 index.vue 导入,含 Tag/Avatar 渲染 |
| `querySchemas.ts` | 查询表单配置 | 被 index.vue 导入,含 Select/Input/DatePicker 组件 |
## 相关文档
@@ -57,7 +57,7 @@ feat(generator): 支持树形表格模板生成
- 新增 ui2/ 树形模板目录
- 自动识别 parent_id/pid 字段
- 支持 el-tree-select 组件
- 支持 a-tree-select 组件
Closes #123
```