merge: 合并远程 origin/dev 分支代码

pull/304/MERGE
YunaiV 2025-12-16 13:35:38 +08:00
commit eb17976e96
8 changed files with 69 additions and 79 deletions

View File

@ -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',

View File

@ -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;
}

View File

@ -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>

View File

@ -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;

View File

@ -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();

View File

@ -85,7 +85,7 @@ function getDeviceTypeColor(deviceType: number) {
defineExpose({
reload: getList,
search: () => {
query: () => {
queryParams.value.pageNo = 1;
getList();
},

View File

@ -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();