init commit
This commit is contained in:
@@ -6,4 +6,5 @@ VITE_APP_VERSION_NAME=开发版
|
||||
VITE_APP_CACHE_PROFIX=logistics_dev_admin
|
||||
|
||||
# API配置
|
||||
VITE_API_BASE_URL=http://127.0.0.1:9081/api
|
||||
# VITE_API_BASE_URL=http://127.0.0.1:9081/api
|
||||
VITE_API_BASE_URL=https://vet.iqudoo.com/api
|
||||
75
src/views/business/DemoDoc.vue
Normal file
75
src/views/business/DemoDoc.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div class="demo-doc">
|
||||
<h3 v-if="title" class="demo-doc__title">{{ title }}</h3>
|
||||
<a-collapse v-model:activeKey="activeKeys" :bordered="false" ghost>
|
||||
<a-collapse-panel
|
||||
v-for="(doc, index) in docs"
|
||||
:key="String(index)"
|
||||
:header="doc.title"
|
||||
>
|
||||
<pre class="demo-code">{{ doc.content }}</pre>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
docs: { type: Array, default: () => [] },
|
||||
});
|
||||
|
||||
const activeKeys = ref([]);
|
||||
|
||||
watch(
|
||||
() => props.docs,
|
||||
(docs) => {
|
||||
activeKeys.value = docs.map((_, i) => String(i));
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-doc {
|
||||
margin-bottom: 20px;
|
||||
padding: 12px 16px;
|
||||
background: #fafafa;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.demo-doc__title {
|
||||
margin: 0 0 8px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
|
||||
.demo-doc :deep(.ant-collapse-header) {
|
||||
padding: 8px 0 !important;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.demo-doc :deep(.ant-collapse-content-box) {
|
||||
padding: 0 0 8px !important;
|
||||
}
|
||||
|
||||
.demo-code {
|
||||
margin: 0;
|
||||
padding: 12px 16px;
|
||||
background: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1.65;
|
||||
overflow-x: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
color: #333;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +1,44 @@
|
||||
<template>
|
||||
<div class="demo-page">
|
||||
<div class="demo-intro">
|
||||
<p>本页演示项目中 <code>@/iview</code> 封装组件的常见用法,数据均为本地 Mock,无需后端接口。</p>
|
||||
<div class="demo-hero">
|
||||
<h2 class="demo-hero__title">IView 组件库使用文档</h2>
|
||||
<p class="demo-hero__desc">
|
||||
<code>@/iview</code> 是基于 Ant Design Vue 封装的业务组件库,提供配置驱动的表单、筛选、表格、详情与整页布局能力。
|
||||
本页包含<strong>说明文档</strong>与<strong>可交互示例</strong>,数据均为本地 Mock,无需后端接口。
|
||||
</p>
|
||||
<div class="demo-hero__tags">
|
||||
<a-tag color="blue">Vue 3</a-tag>
|
||||
<a-tag color="green">Ant Design Vue 4</a-tag>
|
||||
<a-tag>配置驱动</a-tag>
|
||||
<a-tag>响应式</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IViewTabs v-model:activeKey="activeSection" :animated="false" embedded>
|
||||
<!-- ── 概览 ── -->
|
||||
<IViewTabPane key="overview" tab="概览">
|
||||
<div v-if="activeSection === 'overview'" class="demo-section">
|
||||
<a-collapse v-model:activeKey="overviewCollapse" :bordered="false" ghost>
|
||||
<a-collapse-panel key="arch" header="目录结构">
|
||||
<pre class="demo-code">{{ docOverview.structure }}</pre>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel key="components" header="组件一览">
|
||||
<a-table :columns="componentTableColumns" :data-source="componentTableData" :pagination="false"
|
||||
size="small" row-key="name" />
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel key="quickstart" header="快速上手">
|
||||
<pre class="demo-code">{{ docOverview.quickstart }}</pre>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</div>
|
||||
</IViewTabPane>
|
||||
|
||||
<!-- ── 表单 ── -->
|
||||
<IViewTabPane key="form" tab="表单 IViewForm">
|
||||
<div v-if="activeSection === 'form'" class="demo-section">
|
||||
<IViewForm
|
||||
ref="formRef"
|
||||
v-model="formData"
|
||||
:config="formConfig"
|
||||
:read-only="formReadOnly"
|
||||
/>
|
||||
<DemoDoc title="IViewForm" :docs="docForm" />
|
||||
<div class="demo-live">
|
||||
<IViewForm ref="formRef" v-model="formData" :config="formConfig" :read-only="formReadOnly" />
|
||||
<div class="demo-actions">
|
||||
<a-button type="primary" @click="handleFormSubmit">提交校验</a-button>
|
||||
<a-button @click="handleFormReset">重置</a-button>
|
||||
@@ -20,24 +46,18 @@
|
||||
{{ formReadOnly ? "切换为编辑" : "切换为只读" }}
|
||||
</a-button>
|
||||
</div>
|
||||
<a-alert
|
||||
v-if="formResult"
|
||||
type="info"
|
||||
show-icon
|
||||
:message="'表单数据:' + formResult"
|
||||
style="margin-top: 16px"
|
||||
/>
|
||||
<a-alert v-if="formResult" type="info" show-icon :message="'表单数据:' + formResult" style="margin-top: 16px" />
|
||||
</div>
|
||||
</div>
|
||||
</IViewTabPane>
|
||||
|
||||
<!-- ── 列表 ── -->
|
||||
<IViewTabPane key="list" tab="列表 IViewTable">
|
||||
<div v-if="activeSection === 'list'" class="demo-section">
|
||||
<IViewFilter
|
||||
v-model="filterParams"
|
||||
:config="filterConfig"
|
||||
@search="handleFilterSearch"
|
||||
@reset="handleFilterReset"
|
||||
/>
|
||||
<DemoDoc title="IViewFilter + IViewTable" :docs="docList" />
|
||||
<div class="demo-live">
|
||||
<IViewFilter v-model="filterParams" :config="filterConfig" @search="handleFilterSearch"
|
||||
@reset="handleFilterReset" />
|
||||
<div class="demo-list-header">
|
||||
<span class="demo-list-title">订单列表示例(共 {{ filteredList.length }} 条)</span>
|
||||
<a-button type="primary" @click="handleAddRecord">
|
||||
@@ -45,41 +65,31 @@
|
||||
新增
|
||||
</a-button>
|
||||
</div>
|
||||
<IViewTable
|
||||
:loading="listLoading"
|
||||
:columns="listColumns"
|
||||
:data-source="filteredList"
|
||||
row-key="id"
|
||||
:pagination="tablePagination"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<IViewTable :loading="listLoading" :columns="listColumns" :data-source="filteredList" row-key="id"
|
||||
:pagination="tablePagination" @change="handleTableChange">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<a-tag :color="statusColor(record.status)">{{ statusLabel(record.status) }}</a-tag>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-button size="small" type="link" @click="handleViewRecord(record)">查看</a-button>
|
||||
<IViewConfirm
|
||||
importance="normal"
|
||||
title="确认删除该记录吗?"
|
||||
@confirm="() => handleDeleteRecord(record)"
|
||||
>
|
||||
<IViewConfirm importance="normal" title="确认删除该记录吗?" @confirm="() => handleDeleteRecord(record)">
|
||||
<a-button size="small" type="link" danger>删除</a-button>
|
||||
</IViewConfirm>
|
||||
</template>
|
||||
</template>
|
||||
</IViewTable>
|
||||
</div>
|
||||
</div>
|
||||
</IViewTabPane>
|
||||
|
||||
<!-- ── 详情 ── -->
|
||||
<IViewTabPane key="detail" tab="详情 IViewDescriptions">
|
||||
<div v-if="activeSection === 'detail'" class="demo-section">
|
||||
<IViewDescriptions
|
||||
:record-data="detailRecord"
|
||||
:columns-list="detailColumns"
|
||||
:column-size="2"
|
||||
:hidden-label="false"
|
||||
>
|
||||
<DemoDoc title="IViewDescriptions" :docs="docDetail" />
|
||||
<div class="demo-live">
|
||||
<IViewDescriptions :record-data="detailRecord" :columns-list="detailColumns" :column-size="2"
|
||||
:hidden-label="false">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<a-tag :color="statusColor(record.status)">{{ statusLabel(record.status) }}</a-tag>
|
||||
@@ -87,29 +97,52 @@
|
||||
</template>
|
||||
</IViewDescriptions>
|
||||
</div>
|
||||
</div>
|
||||
</IViewTabPane>
|
||||
|
||||
<!-- ── 整页布局 ── -->
|
||||
<IViewTabPane key="layout" tab="页面 ILayoutPage">
|
||||
<div v-if="activeSection === 'layout'" class="demo-section">
|
||||
<a-alert
|
||||
type="warning"
|
||||
show-icon
|
||||
message="ILayoutPage 需配置真实 API,完整示例请参考「系统设置 → 管理员账号」页面。"
|
||||
style="margin-bottom: 16px"
|
||||
/>
|
||||
<DemoDoc title="ILayoutPage" :docs="docLayout" />
|
||||
<div class="demo-live">
|
||||
<a-alert type="warning" show-icon message="ILayoutPage 需配置真实 API,完整可运行示例请参考「系统设置 → 管理员账号」页面。"
|
||||
style="margin-bottom: 16px" />
|
||||
<pre class="demo-code">{{ layoutPageExample }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</IViewTabPane>
|
||||
|
||||
<!-- ── 通用组件 ── -->
|
||||
<IViewTabPane key="common" tab="通用组件">
|
||||
<div v-if="activeSection === 'common'" class="demo-section">
|
||||
<DemoDoc title="IViewConfirm / IViewDrawer / IViewTabs" :docs="docCommon" />
|
||||
<div class="demo-live">
|
||||
<h4 class="demo-subtitle">IViewConfirm — 确认操作</h4>
|
||||
<div class="demo-actions">
|
||||
<IViewConfirm importance="normal" title="确认执行此操作吗?" @confirm="handleNormalConfirm">
|
||||
<a-button>普通确认(PC 气泡 / 移动端 Modal)</a-button>
|
||||
</IViewConfirm>
|
||||
<IViewConfirm importance="important" title="危险操作确认" entity-name="确认删除" @confirm="handleImportantConfirm">
|
||||
<a-button danger>重要确认(需输入文字)</a-button>
|
||||
</IViewConfirm>
|
||||
</div>
|
||||
|
||||
<h4 class="demo-subtitle">IViewDrawer — 抽屉</h4>
|
||||
<a-button type="primary" @click="drawerOpen = true">打开详情抽屉</a-button>
|
||||
|
||||
<h4 class="demo-subtitle">消息提示 — messageTips</h4>
|
||||
<div class="demo-actions">
|
||||
<a-button @click="showSuccessTips('操作成功')">showSuccessTips</a-button>
|
||||
<a-button @click="showErrorTips({ msg: '操作失败,请重试' })">showErrorTips</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</IViewTabPane>
|
||||
</IViewTabs>
|
||||
|
||||
<IViewDrawer :open="drawerOpen" title="订单详情" @close="drawerOpen = false">
|
||||
<IViewDescriptions
|
||||
v-if="currentRecord"
|
||||
:record-data="currentRecord"
|
||||
:columns-list="detailColumns"
|
||||
:column-size="1"
|
||||
:hidden-label="false"
|
||||
>
|
||||
<IViewDescriptions v-if="currentRecord" :record-data="currentRecord" :columns-list="detailColumns"
|
||||
:column-size="1" :hidden-label="false">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<a-tag :color="statusColor(record.status)">{{ statusLabel(record.status) }}</a-tag>
|
||||
@@ -131,9 +164,307 @@ import IViewTable from "@/iview/IViewTable.vue";
|
||||
import IViewDescriptions from "@/iview/IViewDescriptions.vue";
|
||||
import IViewConfirm from "@/iview/IViewConfirm.vue";
|
||||
import IViewDrawer from "@/iview/IViewDrawer.vue";
|
||||
import DemoDoc from "./DemoDoc.vue";
|
||||
import { showSuccessTips, showErrorTips } from "@/iview/utils/messageTips";
|
||||
|
||||
const activeSection = ref("form");
|
||||
const activeSection = ref("overview");
|
||||
const overviewCollapse = ref(["arch", "components", "quickstart"]);
|
||||
|
||||
// ── 文档内容 ──────────────────────────────────────────
|
||||
const docOverview = {
|
||||
structure: `src/iview/
|
||||
├── IViewForm.vue # 配置驱动表单
|
||||
├── IViewFilter.vue # 筛选栏(基于 IViewForm inline 布局)
|
||||
├── IViewTable.vue # 表格(PC 表格 / 移动端卡片)
|
||||
├── IViewDescriptions.vue # 详情描述列表
|
||||
├── IViewConfirm.vue # 确认弹层
|
||||
├── IViewDrawer.vue # 响应式抽屉
|
||||
├── IViewTabs.vue # 标签页
|
||||
├── ILayoutPage.vue # 整页 CRUD 布局
|
||||
├── form/ # 各类型表单控件
|
||||
├── display/ # 展示类子组件
|
||||
├── utils/ # request、messageTips 等工具
|
||||
└── urlEmbed/ # iframe 嵌入页通信`,
|
||||
quickstart: `// 1. 按需引入组件
|
||||
import IViewForm from "@/iview/IViewForm.vue";
|
||||
import { showSuccessTips, showErrorTips } from "@/iview/utils/messageTips";
|
||||
import { apiRequest } from "@/iview/utils/request";
|
||||
|
||||
// 2. 配置驱动表单
|
||||
const formData = ref({});
|
||||
const formConfig = ref({
|
||||
fields: [
|
||||
{ name: "username", label: "账号", type: "text", required: true },
|
||||
{ name: "status", label: "状态", type: "boolean", trueValue: 1, falseValue: 0 },
|
||||
],
|
||||
});
|
||||
|
||||
// 3. 模板
|
||||
<IViewForm ref="formRef" v-model="formData" :config="formConfig" />
|
||||
|
||||
// 4. 提交
|
||||
await formRef.value.validate();
|
||||
await apiRequest("api.xxx.create", formData.value);
|
||||
showSuccessTips("保存成功");`,
|
||||
};
|
||||
|
||||
const componentTableColumns = [
|
||||
{ title: "组件", dataIndex: "name", width: 180 },
|
||||
{ title: "用途", dataIndex: "desc" },
|
||||
{ title: "典型场景", dataIndex: "scene", ellipsis: true },
|
||||
];
|
||||
|
||||
const componentTableData = [
|
||||
{ name: "IViewForm", desc: "配置驱动表单,支持 17+ 字段类型", scene: "新增/编辑、设置页" },
|
||||
{ name: "IViewFilter", desc: "列表筛选栏,支持高级筛选折叠", scene: "列表页顶部搜索" },
|
||||
{ name: "IViewTable", desc: "表格,PC 端可拖拽横向滚动,移动端卡片", scene: "数据列表展示" },
|
||||
{ name: "IViewDescriptions", desc: "详情描述列表", scene: "详情页、抽屉内容" },
|
||||
{ name: "IViewConfirm", desc: "确认操作(普通 / 重要)", scene: "删除、危险操作" },
|
||||
{ name: "IViewDrawer", desc: "响应式抽屉,自动适配侧边栏宽度", scene: "详情、表单弹层" },
|
||||
{ name: "IViewTabs", desc: "标签页,移动端 Strip 样式", scene: "模块切换、嵌套 Tab" },
|
||||
{ name: "ILayoutPage", desc: "整页 CRUD 布局引擎", scene: "标准增删改查页面" },
|
||||
{ name: "apiRequest", desc: "统一 API 请求(自动带 token)", scene: "所有后端接口调用" },
|
||||
{ name: "messageTips", desc: "成功/错误消息提示", scene: "操作反馈" },
|
||||
];
|
||||
|
||||
const docForm = [
|
||||
{
|
||||
title: "Props",
|
||||
content: `IViewForm
|
||||
v-model / modelValue Object | String 表单数据(modelFormat='json' 时为 JSON 字符串)
|
||||
config Object | String 表单配置 { fields, extrasFields, formatValue, unformatValue }
|
||||
readOnly Boolean 全局只读
|
||||
layout 'vertical' | 'horizontal' | 'inline'
|
||||
labelCol / wrapperCol Object 标签布局(inline 时无效)
|
||||
disableResponsive Boolean 禁用移动端强制 vertical 布局`,
|
||||
},
|
||||
{
|
||||
title: "暴露方法(ref)",
|
||||
content: `formRef.value.validate() // 校验全部可见字段,失败 throw
|
||||
formRef.value.validateField(field) // 校验单个字段
|
||||
formRef.value.resetFormData() // 重置为 defaultValue`,
|
||||
},
|
||||
{
|
||||
title: "字段配置 fields[]",
|
||||
content: `通用属性:
|
||||
name 字段名(必填)
|
||||
label 标签
|
||||
type 字段类型(见下方类型表)
|
||||
required 是否必填
|
||||
defaultValue 默认值
|
||||
placeholder 占位符
|
||||
tips 输入提示
|
||||
show 显示条件,支持函数或表达式字符串,如 "!!record.guid"
|
||||
disabled 禁用,支持函数
|
||||
onChanged 值变化回调
|
||||
|
||||
字段类型:
|
||||
title 分组标题(仅展示 label)
|
||||
text 单行文本(minLength / maxlength / textLenMax)
|
||||
textarea 多行文本(textRows / maxlength)
|
||||
number 数字(min / max / numMin / numMax)
|
||||
radio 单选(options: [{ value, label }])
|
||||
checkbox 多选(options)
|
||||
select 下拉(options,支持远程 optionsApi)
|
||||
date 日期
|
||||
datetime 日期时间
|
||||
time 时间
|
||||
boolean 开关(trueValue / falseValue)
|
||||
image 图片上传
|
||||
video 视频上传
|
||||
file 文件上传
|
||||
fileBase64 Base64 文件
|
||||
imageBase64 Base64 图片
|
||||
signatureImage 手写签名
|
||||
|
||||
扩展:registerIViewFormFieldComponent(type, component) 注册自定义字段类型`,
|
||||
},
|
||||
{
|
||||
title: "代码示例",
|
||||
content: `<IViewForm ref="formRef" v-model="formData" :config="formConfig" />
|
||||
|
||||
const formConfig = ref({
|
||||
extrasFields: ["guid"], // 额外保留但不渲染的字段
|
||||
fields: [
|
||||
{ type: "title", label: "基础信息" },
|
||||
{ name: "name", label: "姓名", type: "text", required: true, maxlength: 20 },
|
||||
{ name: "city", label: "城市", type: "select", options: [
|
||||
{ value: "gz", label: "广州" },
|
||||
]},
|
||||
{ name: "enabled", label: "启用", type: "boolean", trueValue: 1, falseValue: 0 },
|
||||
],
|
||||
});`,
|
||||
},
|
||||
];
|
||||
|
||||
const docList = [
|
||||
{
|
||||
title: "IViewFilter Props",
|
||||
content: `config Object 筛选项配置 { fields: [...] },字段同 IViewForm
|
||||
v-model Object 筛选参数
|
||||
searchButtonText String 搜索按钮文字,默认「搜索」
|
||||
resetButtonText String 重置按钮文字,默认「重置」
|
||||
|
||||
字段 advanced: true → PC 端归入「高级选项」折叠区
|
||||
移动端首个筛选项始终可见,其余可收入「高级筛选」
|
||||
|
||||
事件:@search @reset @init`,
|
||||
},
|
||||
{
|
||||
title: "IViewTable Props",
|
||||
content: `columns Array 列配置
|
||||
data-source Array 数据源
|
||||
row-key String 行唯一键
|
||||
loading Boolean 加载态
|
||||
pagination Object | false 分页配置,false 关闭分页
|
||||
show-filter Boolean 是否显示列显示设置
|
||||
|
||||
列配置:
|
||||
title / dataIndex 标题 / 字段名
|
||||
width 列宽
|
||||
bodySlot: true 使用 #bodyCell 插槽自定义渲染
|
||||
fixed: 'right' 固定列
|
||||
ellipsis 超长省略
|
||||
customRender 函数 ({ record, column, mobile }) => HTML 字符串
|
||||
|
||||
事件:@change(pagination, filters, sorter)
|
||||
|
||||
特性:PC 端支持列宽拖拽、横向拖拽滚动条;移动端自动切换为卡片布局`,
|
||||
},
|
||||
{
|
||||
title: "代码示例",
|
||||
content: `<IViewFilter v-model="filterParams" :config="filterConfig" @search="onSearch" />
|
||||
|
||||
<IViewTable :columns="columns" :data-source="list" row-key="id"
|
||||
:pagination="{ current: 1, pageSize: 10, total: 100 }"
|
||||
@change="handleTableChange">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-button @click="edit(record)">编辑</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</IViewTable>`,
|
||||
},
|
||||
];
|
||||
|
||||
const docDetail = [
|
||||
{
|
||||
title: "Props",
|
||||
content: `record-data Object 详情数据对象
|
||||
columns-list Array 列配置(同表格列,支持 bodySlot / customRender / span)
|
||||
column-size Number 每行列数,默认 2
|
||||
hidden-label Boolean 是否隐藏标签,默认 true`,
|
||||
},
|
||||
{
|
||||
title: "列配置扩展",
|
||||
content: `span Number 占列数(如 span: 2 占满一行)
|
||||
bodySlot: true 使用 #bodyCell 插槽
|
||||
show Function | String 条件显示
|
||||
customRender Function ({ record, column, mobile }) => HTML
|
||||
|
||||
<IViewDescriptions :record-data="record" :columns-list="columns" :hidden-label="false">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<a-tag v-if="column.dataIndex === 'status'">{{ record.status }}</a-tag>
|
||||
</template>
|
||||
</IViewDescriptions>`,
|
||||
},
|
||||
];
|
||||
|
||||
const docCommon = [
|
||||
{
|
||||
title: "IViewConfirm",
|
||||
content: `importance 'normal' | 'important'
|
||||
normal PC 端 Popconfirm 气泡;移动端 Modal
|
||||
important Modal + 需输入 entityName 文字才能确认
|
||||
|
||||
title 确认标题
|
||||
entityName important 模式下需输入的确认文字
|
||||
@confirm 确认回调,可返回 Promise 自动 loading
|
||||
|
||||
<IViewConfirm importance="normal" title="确认删除?" @confirm="handleDelete">
|
||||
<a-button danger>删除</a-button>
|
||||
</IViewConfirm>`,
|
||||
},
|
||||
{
|
||||
title: "IViewDrawer",
|
||||
content: `open / v-model:open 是否打开
|
||||
title 标题
|
||||
width 固定宽度(可选,默认自适应)
|
||||
flushContent 去掉内边距,适合 iframe 全屏
|
||||
@close 关闭回调
|
||||
|
||||
<IViewDrawer :open="open" title="详情" @close="open = false">
|
||||
<!-- 内容 -->
|
||||
</IViewDrawer>`,
|
||||
},
|
||||
{
|
||||
title: "IViewTabs",
|
||||
content: `v-model:activeKey 当前 Tab key
|
||||
embedded 嵌入模式(去掉外层 padding)
|
||||
level 'primary' | 'secondary' 层级样式
|
||||
animated 是否开启动画
|
||||
|
||||
<IViewTabs v-model:activeKey="key" :animated="false" embedded>
|
||||
<IViewTabPane key="a" tab="Tab A">...</IViewTabPane>
|
||||
<IViewTabPane key="b" tab="Tab B">...</IViewTabPane>
|
||||
</IViewTabs>`,
|
||||
},
|
||||
{
|
||||
title: "messageTips / apiRequest",
|
||||
content: `import { showSuccessTips, showErrorTips } from "@/iview/utils/messageTips";
|
||||
import { apiRequest } from "@/iview/utils/request";
|
||||
|
||||
showSuccessTips("保存成功");
|
||||
showErrorTips(error); // 支持表单 errorFields 自动滚动定位
|
||||
|
||||
const data = await apiRequest("api.system.admin.info.list", { page: 1 });
|
||||
// api 字符串对应后端接口标识,请求体自动附带 token`,
|
||||
},
|
||||
];
|
||||
|
||||
const docLayout = [
|
||||
{
|
||||
title: "config 结构",
|
||||
content: `const config = ref({
|
||||
listPages: [{ // 列表页(可多个 Tab)
|
||||
title, name, api, rowKey, isDefault,
|
||||
showFilter, pagination, columns, filters,
|
||||
defaultParams,
|
||||
}],
|
||||
formPages: [{ // 表单页(抽屉内)
|
||||
name, title,
|
||||
submitApi, // 新增提交接口
|
||||
recordApi, // 编辑时拉取详情(update 场景)
|
||||
paramsKey: ["guid"], // 从 record 取参的字段
|
||||
formConfig: { fields: [...] },
|
||||
}],
|
||||
detailPages: [{ // 详情页(抽屉内)
|
||||
name, title, recordApi, paramsKey, columns,
|
||||
}],
|
||||
infoPages: [{ // 顶部信息区(可选)
|
||||
name, recordApi, columns,
|
||||
}],
|
||||
});`,
|
||||
},
|
||||
{
|
||||
title: "暴露方法(pageRef)",
|
||||
content: `pageRef.value.showFormPage('create') // 打开新增表单
|
||||
pageRef.value.showFormPage('update', record) // 打开编辑表单
|
||||
pageRef.value.showDetailPage('detail', record)// 打开详情
|
||||
pageRef.value.refreshList() // 刷新列表
|
||||
pageRef.value.refreshPage() // 刷新整页
|
||||
pageRef.value.closeFormPage() // 关闭表单抽屉
|
||||
pageRef.value.patchListRow(id, patch) // 局部更新列表行`,
|
||||
},
|
||||
{
|
||||
title: "插槽",
|
||||
content: `#listActions="{ type, refresh }" 列表操作区(标题、新增按钮等)
|
||||
#bodyCell="{ column, record, type, refresh }" 自定义列/详情渲染
|
||||
#listHeader / #listFooter 列表上下扩展区
|
||||
#infoHeader / #infoTab / #infoFooter 信息区扩展
|
||||
#expandedRowRender 表格行展开`,
|
||||
},
|
||||
];
|
||||
|
||||
// ── 表单示例 ──────────────────────────────────────────
|
||||
const formRef = ref(null);
|
||||
@@ -384,50 +715,77 @@ const detailColumns = ref([
|
||||
{ title: "备注", dataIndex: "remark", span: 2 },
|
||||
]);
|
||||
|
||||
// ── 通用组件示例 ──────────────────────────────────────
|
||||
const handleNormalConfirm = () => {
|
||||
showSuccessTips("已确认操作");
|
||||
};
|
||||
|
||||
const handleImportantConfirm = () => {
|
||||
showSuccessTips("重要操作已确认");
|
||||
};
|
||||
|
||||
// ── ILayoutPage 配置示例 ──────────────────────────────
|
||||
const layoutPageExample = `const config = ref({
|
||||
const layoutPageExample = `<template>
|
||||
<ILayoutPage ref="pageRef" :config="config">
|
||||
<template #listActions="{ refresh }">
|
||||
<a-button type="primary" @click="pageRef.showFormPage('create')">添加</a-button>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-button @click="pageRef.showFormPage('update', record)">编辑</a-button>
|
||||
<IViewConfirm title="确认删除?" @confirm="() => handleDelete(record)">
|
||||
<a-button danger>删除</a-button>
|
||||
</IViewConfirm>
|
||||
</template>
|
||||
</template>
|
||||
</ILayoutPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ILayoutPage from "@/iview/ILayoutPage.vue";
|
||||
import { apiRequest } from "@/iview/utils/request";
|
||||
|
||||
const pageRef = ref(null);
|
||||
|
||||
const config = ref({
|
||||
listPages: [{
|
||||
title: "列表标题",
|
||||
name: "recordList",
|
||||
api: "api.xxx.list", // 列表接口
|
||||
api: "api.xxx.list",
|
||||
rowKey: "guid",
|
||||
isDefault: true,
|
||||
showFilter: true,
|
||||
pagination: { pageSize: 10 },
|
||||
columns: [/* 列配置 */],
|
||||
filters: { fields: [/* 筛选项 */] },
|
||||
columns: [
|
||||
{ title: "名称", dataIndex: "name" },
|
||||
{ title: "操作", dataIndex: "action", bodySlot: true, fixed: "right" },
|
||||
],
|
||||
filters: { fields: [
|
||||
{ name: "keyword", label: "关键词", type: "text" },
|
||||
]},
|
||||
}],
|
||||
formPages: [{
|
||||
name: "create",
|
||||
title: "新增",
|
||||
submitApi: "api.xxx.create",
|
||||
formConfig: { fields: [/* 表单字段 */] },
|
||||
formConfig: { fields: [/* ... */] },
|
||||
}, {
|
||||
name: "update",
|
||||
title: "编辑",
|
||||
paramsKey: ["guid"],
|
||||
recordApi: "api.xxx.detail",
|
||||
submitApi: "api.xxx.update",
|
||||
formConfig: { fields: [/* 表单字段 */] },
|
||||
formConfig: { fields: [/* ... */] },
|
||||
}],
|
||||
detailPages: [{
|
||||
name: "detail",
|
||||
title: "详情",
|
||||
paramsKey: ["guid"],
|
||||
recordApi: "api.xxx.detail",
|
||||
columns: [/* 详情字段 */],
|
||||
columns: [/* ... */],
|
||||
}],
|
||||
});
|
||||
|
||||
// 模板中使用
|
||||
<ILayoutPage ref="pageRef" :config="config">
|
||||
<template #listActions="{ refresh }">
|
||||
<a-button type="primary" @click="pageRef.showFormPage('create')">添加</a-button>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<!-- 自定义列渲染 -->
|
||||
</template>
|
||||
</ILayoutPage>`;
|
||||
<\/script>`;
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -436,24 +794,61 @@ const layoutPageExample = `const config = ref({
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.demo-intro {
|
||||
margin-bottom: 16px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
.demo-hero {
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.demo-intro code {
|
||||
.demo-hero__title {
|
||||
margin: 0 0 8px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
}
|
||||
|
||||
.demo-hero__desc {
|
||||
margin: 0 0 12px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.demo-hero__desc code {
|
||||
padding: 2px 6px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.demo-hero__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
padding: 4px 0 16px;
|
||||
}
|
||||
|
||||
.demo-live {
|
||||
padding: 16px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.demo-subtitle {
|
||||
margin: 20px 0 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
.demo-subtitle:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.demo-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -477,15 +872,16 @@ const layoutPageExample = `const config = ref({
|
||||
|
||||
.demo-code {
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
background: #fafafa;
|
||||
padding: 12px 16px;
|
||||
background: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
line-height: 1.65;
|
||||
overflow-x: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
color: #333;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user