mirror of
https://gitee.com/yudaocode/yudao-ui-admin-vben.git
synced 2025-12-30 10:32:25 +00:00
merge: 合并远程 origin/dev 分支代码
This commit is contained in:
@@ -19,7 +19,7 @@ const routes: RouteRecordRaw[] = [
|
||||
activePath: '/iot/device/product',
|
||||
},
|
||||
component: () =>
|
||||
import('#/views/iot/product/product/modules/detail/index.vue'),
|
||||
import('#/views/iot/product/product/detail/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'device/detail/:id',
|
||||
|
||||
@@ -14,18 +14,13 @@ import { getSimpleProductCategoryList } from '#/api/iot/product/category';
|
||||
|
||||
/** 产品分类列表缓存 */
|
||||
let categoryList: IotProductCategoryApi.ProductCategory[] = [];
|
||||
|
||||
/** 加载产品分类数据 */
|
||||
async function loadCategoryData() {
|
||||
categoryList = await getSimpleProductCategoryList();
|
||||
}
|
||||
|
||||
// 初始化加载分类数据
|
||||
// TODO @haohao:可以参考 /Users/yunai/Java/yudao-ui-admin-vben-v5/apps/web-antd/src/views/system/tenant/data.ts 简洁一点。
|
||||
loadCategoryData();
|
||||
getSimpleProductCategoryList().then((data) => (categoryList = data));
|
||||
|
||||
/** 新增/修改产品的表单 */
|
||||
export function useFormSchema(formApi?: any): VbenFormSchema[] {
|
||||
export function useFormSchema(
|
||||
formApi?: any,
|
||||
generateProductKey?: () => string,
|
||||
): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
component: 'Input',
|
||||
@@ -59,7 +54,9 @@ export function useFormSchema(formApi?: any): VbenFormSchema[] {
|
||||
{
|
||||
type: 'default',
|
||||
onClick: () => {
|
||||
formApi?.setFieldValue('productKey', generateProductKey());
|
||||
if (generateProductKey) {
|
||||
formApi?.setFieldValue('productKey', generateProductKey());
|
||||
}
|
||||
},
|
||||
},
|
||||
{ default: () => '重新生成' },
|
||||
@@ -175,7 +172,10 @@ export function useFormSchema(formApi?: any): VbenFormSchema[] {
|
||||
}
|
||||
|
||||
/** 基础表单字段(不含图标、图片、描述) */
|
||||
export function useBasicFormSchema(formApi?: any): VbenFormSchema[] {
|
||||
export function useBasicFormSchema(
|
||||
formApi?: any,
|
||||
generateProductKey?: () => string,
|
||||
): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
component: 'Input',
|
||||
@@ -208,7 +208,9 @@ export function useBasicFormSchema(formApi?: any): VbenFormSchema[] {
|
||||
{
|
||||
type: 'default',
|
||||
onClick: () => {
|
||||
formApi?.setFieldValue('productKey', generateProductKey());
|
||||
if (generateProductKey) {
|
||||
formApi?.setFieldValue('productKey', generateProductKey());
|
||||
}
|
||||
},
|
||||
},
|
||||
{ default: () => '重新生成' },
|
||||
@@ -299,6 +301,7 @@ export function useBasicFormSchema(formApi?: any): VbenFormSchema[] {
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
},
|
||||
defaultValue: 0,
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
@@ -339,7 +342,6 @@ export function useAdvancedFormSchema(): VbenFormSchema[] {
|
||||
placeholder: '请输入产品描述',
|
||||
rows: 3,
|
||||
},
|
||||
formItemClass: 'col-span-2', // 让描述占满两列
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -404,13 +406,3 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
|
||||
];
|
||||
}
|
||||
|
||||
/** 生成 ProductKey(包含大小写字母和数字) */
|
||||
export function generateProductKey(): string {
|
||||
const chars =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
for (let i = 0; i < 16; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ const activeTab = ref('info');
|
||||
provide('product', product); // 提供产品信息给子组件
|
||||
|
||||
/** 获取产品详情 */
|
||||
// TODO @haohao:因为 detail 是独立界面,所以不放在 modules 里,应该放在 web-antd/src/views/iot/product/product/detail/index.vue 里,更合理一些哈。
|
||||
async function getProductData(productId: number) {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -91,3 +90,4 @@ onMounted(async () => {
|
||||
</Tabs>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Button, Card, Descriptions, message, Modal } from 'ant-design-vue';
|
||||
|
||||
import { updateProductStatus } from '#/api/iot/product/product';
|
||||
|
||||
import Form from '../../form.vue';
|
||||
import Form from '../../modules/form.vue';
|
||||
|
||||
interface Props {
|
||||
product: IotProductApi.Product;
|
||||
@@ -51,11 +51,8 @@ async function loadCategories() {
|
||||
function handleSearch() {
|
||||
if (viewMode.value === 'list') {
|
||||
gridApi.formApi.setValues(queryParams.value);
|
||||
gridApi.query();
|
||||
} else {
|
||||
// TODO @haohao:要不 search 也改成 query 方法,更统一一点哈。
|
||||
cardViewRef.value?.search(queryParams.value);
|
||||
}
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 重置搜索 */
|
||||
@@ -67,11 +64,7 @@ function handleReset() {
|
||||
|
||||
/** 刷新表格 */
|
||||
function handleRefresh() {
|
||||
if (viewMode.value === 'list') {
|
||||
gridApi.query();
|
||||
} else {
|
||||
cardViewRef.value?.reload();
|
||||
}
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 导出表格 */
|
||||
@@ -149,6 +142,17 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
} as VxeTableGridOptions<IotProductApi.Product>,
|
||||
});
|
||||
|
||||
// 包装 gridApi.query() 方法,统一列表视图和卡片视图的查询接口
|
||||
const originalQuery = gridApi.query.bind(gridApi);
|
||||
gridApi.query = async (params?: Record<string, any>) => {
|
||||
if (viewMode.value === 'list') {
|
||||
return await originalQuery(params);
|
||||
} else {
|
||||
// 卡片视图:调用卡片组件的 query 方法
|
||||
cardViewRef.value?.query();
|
||||
}
|
||||
};
|
||||
|
||||
/** 初始化 */
|
||||
onMounted(() => {
|
||||
loadCategories();
|
||||
|
||||
@@ -85,7 +85,7 @@ function getDeviceTypeColor(deviceType: number) {
|
||||
|
||||
defineExpose({
|
||||
reload: getList,
|
||||
search: () => {
|
||||
query: () => {
|
||||
queryParams.value.pageNo = 1;
|
||||
getList();
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { IotProductApi } from '#/api/iot/product/product';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, nextTick, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
@@ -15,11 +15,18 @@ import {
|
||||
} from '#/api/iot/product/product';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import {
|
||||
generateProductKey,
|
||||
useAdvancedFormSchema,
|
||||
useBasicFormSchema,
|
||||
} from '../data';
|
||||
import { useAdvancedFormSchema, useBasicFormSchema } from '../data';
|
||||
|
||||
/** 生成 ProductKey(包含大小写字母和数字) */
|
||||
function generateProductKey(): string {
|
||||
const chars =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
for (let i = 0; i < 16; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const formData = ref<IotProductApi.Product>();
|
||||
@@ -37,10 +44,9 @@ const [Form, formApi] = useVbenForm({
|
||||
layout: 'horizontal',
|
||||
schema: [],
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
wrapperClass: 'grid-cols-1',
|
||||
});
|
||||
|
||||
// TODO @haohao:这个要不还是一行一个?这样样式好看点哈。
|
||||
const [AdvancedForm, advancedFormApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: { class: 'w-full' },
|
||||
@@ -48,12 +54,24 @@ const [AdvancedForm, advancedFormApi] = useVbenForm({
|
||||
layout: 'horizontal',
|
||||
schema: useAdvancedFormSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
wrapperClass: 'grid-cols-1',
|
||||
});
|
||||
|
||||
/** 基础表单需要 formApi 引用,所以通过 setState 设置 schema */
|
||||
// TODO haohao:@haohao:要不要把 generateProductKey 拿到这个 vue 里,作为参数传递到 useBasicFormSchema 里?
|
||||
formApi.setState({ schema: useBasicFormSchema(formApi) });
|
||||
formApi.setState({ schema: useBasicFormSchema(formApi, generateProductKey) });
|
||||
|
||||
/** 获取高级表单的值(如果表单未挂载,则从 formData 中获取) */
|
||||
async function getAdvancedFormValues() {
|
||||
if (advancedFormApi.isMounted) {
|
||||
return await advancedFormApi.getValues();
|
||||
}
|
||||
// 表单未挂载(折叠状态),从 formData 中获取
|
||||
return {
|
||||
icon: formData.value?.icon,
|
||||
picUrl: formData.value?.picUrl,
|
||||
description: formData.value?.description,
|
||||
};
|
||||
}
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
@@ -62,18 +80,9 @@ const [Modal, modalApi] = useVbenModal({
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
// 合并两个表单的值
|
||||
// 合并两个表单的值(字段不冲突,可直接合并)
|
||||
const basicValues = await formApi.getValues();
|
||||
// TODO @haohao:有 linter 修复下;“formData.value?.id”;另外,这里直接两个表单合并,是不是就可以了呀?因为 2 个 schema 本身不同,字段就不同,不会冲突。
|
||||
const advancedValues = activeKey.value.includes('advanced')
|
||||
? await advancedFormApi.getValues()
|
||||
: formData.value?.id
|
||||
? {
|
||||
icon: formData.value.icon,
|
||||
picUrl: formData.value.picUrl,
|
||||
description: formData.value.description,
|
||||
}
|
||||
: {};
|
||||
const advancedValues = await getAdvancedFormValues();
|
||||
const data = {
|
||||
...basicValues,
|
||||
...advancedValues,
|
||||
@@ -96,12 +105,9 @@ const [Modal, modalApi] = useVbenModal({
|
||||
// 加载数据
|
||||
const data = modalApi.getData<IotProductApi.Product>();
|
||||
if (!data || !data.id) {
|
||||
// 新增:设置默认值
|
||||
// TODO @AI:
|
||||
// 新增:设置默认值(status 通过 schema 中的 defaultValue 自动设置为 0)
|
||||
await formApi.setValues({
|
||||
// TODO @haohao:要不要把 generateProductKey 拿到这个 vue 里,作为参数传递到 useBasicFormSchema 里?
|
||||
productKey: generateProductKey(),
|
||||
status: 0, // TODO @haohao:通过 defaultValue 即可;
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -110,22 +116,10 @@ const [Modal, modalApi] = useVbenModal({
|
||||
try {
|
||||
formData.value = await getProduct(data.id);
|
||||
await formApi.setValues(formData.value);
|
||||
// 设置高级表单(不等待)
|
||||
// TODO @haohao:直接把 formData 传过去?没关系的哈。因为会 filter 掉不存在的值,可以试试哈。
|
||||
// TODO @haohao:这里是不是要 await 下呀?有黄色的告警;
|
||||
advancedFormApi.setValues({
|
||||
icon: formData.value.icon,
|
||||
picUrl: formData.value.picUrl,
|
||||
description: formData.value.description,
|
||||
});
|
||||
// 有高级字段时自动展开
|
||||
// TODO @haohao:默认不用展开哈。
|
||||
if (
|
||||
formData.value.icon ||
|
||||
formData.value.picUrl ||
|
||||
formData.value.description
|
||||
) {
|
||||
activeKey.value = ['advanced'];
|
||||
// 设置高级表单(如果已挂载)
|
||||
await nextTick();
|
||||
if (advancedFormApi.isMounted) {
|
||||
await advancedFormApi.setValues(formData.value);
|
||||
}
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
|
||||
Reference in New Issue
Block a user