1.  
[Vue warn]: Invalid prop: type check failed for prop "right". Expected Number with value 15, got String with value "15".
at <ElBacktop target=".layout-backtop-header-fixed .el-scrollbar__wrap" right="15" >
at <ElMain class="layout-main" style="height: calc(100% - 85px)" >
at <LayoutMain ref="layoutMainRef" >

错误的写法: 

  <el-backtop :target="setBacktopClass" right=15 />
正确的写法
  <el-backtop :target="setBacktopClass" :right=15 />

Backtop 回到顶部 | Element Plus (element-plus.org)

2.

Missing required prop: "modelValue"
at <Admin/org/menu onNodeClick=fn<onOrgNodeClick> class="my-flex-fill" select-first-node="" >
at <AsyncComponentWrapper onNodeClick=fn<onOrgNodeClick> class="my-flex-fill" select-first-node="" >

 OrgMenu  和<org-menu> 的关系是什么?

const OrgMenu = defineAsyncComponent(() => import('/@/views/admin/org/components/org-menu.vue'))
<org-menu @node-click="onOrgNodeClick" class="my-flex-fill" select-first-node></org-menu>
 
在vue组件里定义了property
interface Props {
  modelValue: number[] | null | undefined
  selectFirstNode: boolean
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: () => [],
  selectFirstNode: false,
})

改成: 

 <org-menu @node-click="onOrgNodeClick" class="my-flex-fill" select-first-node :modelValue=null></org-menu>
 
3.  把中台admin的用户管理页面,改成dynamicFilter
const state = reactive({
  loading: false,
  userFormTitle: '',
  filterModel: {
    name: '',
  },
  total: 0,
  pageInput: {
    currentPage: 1,
    pageSize: 20,
    filter: {
      orgId: null,
    },
    dynamicFilter: {},
  } as PageInputUserGetPageDto,
  userListData: [] as Array<UserGetPageOutput>,
  filters: [
  {
    field: 'name',
    operator: 'Contains',
    description: '姓名',
    componentName: 'el-input',
    defaultSelect: true,
  },
  {
    field: 'mobile',
    operator: 'Contains',
    description: '手机号',
    componentName: 'el-input',
  },
  {
    field: 'email',
    operator: 'Contains',
    description: '邮箱',
    componentName: 'el-input',
  },
  {
    field: 'userName',
    operator: 'Contains',
    description: '用户名',
    componentName: 'el-input',
  },
  ] as Array<DynamicFilterInfo>,
})
  
                <el-form-item>
                  <my-select-input v-model="state.pageInput.dynamicFilter" :filters="state.filters" @search="onQuery" />
                </el-form-item>
引用组件
const MySelectInput = defineAsyncComponent(() => import('/@/components/my-select-input/index.vue'))
 
在types.views.d.ts 文件最后加上
declare type ComponentEnum = 'el-input'
declare type OperatorEnum =
  | 'Contains'
  | 'StartsWith'
  | 'EndsWith'
  | 'NotContains'
  | 'NotStartsWith'
  | 'NotEndsWith'
  | 'Equal'
  | 'Equals'
  | 'Eq'
  | 'NotEqual'
  | 'GreaterThan'
  | 'GreaterThanOrEqual'
  | 'LessThan'
  | 'LessThanOrEqual'
  | 'Range'
  | 'DateRange'
  | 'Any'
  | 'NotAny'
  | 'Custom'

declare type DynamicFilterInfo = {
  field: string
  operator: OperatorEnum = 'Eq'
  value: string
  description: string
  defaultSelect: boolean
  componentName: ComponentEnum = 'el-input'
}

组件component\my-select-input

<template>
  <el-input v-model="state.filter.value" class="my-input-with-select" clearable @keyup.enter="onSearch" v-bind="$attrs">
    <template v-if="state.filters.length > 0" #prepend>
      <el-select v-model="state.filter.field" style="width: 100px" @change="onChange">
        <el-option v-for="field in state.filters" :key="field.field" :label="field.description" :value="field.field" />
      </el-select>
    </template>
  </el-input>
</template>

<script lang="ts" setup name="my-select-input">
import { reactive, PropType, watch } from 'vue'
import { cloneDeep } from 'lodash-es'

const props = defineProps({
  modelValue: Object as PropType<any | undefined | null>,
  filters: {
    type: Array<DynamicFilterInfo>,
    default() {
      return []
    },
  },
})

const emits = defineEmits(['update:modelValue', 'search'])

const filters = props.filters.filter((a) => a.componentName === 'el-input')
let filter = {} as DynamicFilterInfo
if (filters.length > 0) {
  filter = cloneDeep(filters.find((a) => a.defaultSelect) || filters[0])
}

const state = reactive({
  filters: filters,
  filter: {
    field: props.modelValue?.field || filter.field,
    operator: props.modelValue?.operator || filter.operator,
    value: props.modelValue?.value || filter.value,
  } as DynamicFilterInfo,
})

const onChange = () => {
  state.filter.value = ''
}

const onSearch = () => {
  emits('search', cloneDeep(state.filter))
}

watch(
  () => state.filter,
  () => {
    emits('update:modelValue', cloneDeep(state.filter))
  },
  { deep: true }
)
</script>

<style scoped lang="scss">
.my-input-with-select :deep(.el-input-group__prepend) {
  background-color: var(--el-fill-color-blank);
}
</style>
my-select-input

 

4.  my-select-input 的文本框里输入内容后,会自动加一个suffix 删除图标,导致整个输入框宽度变了,界面跳动。能否固定宽度?

把:clearable=false, 就不会变,但不友好。

 A:  vue3 element-plus 输入框 clearable属性 聚焦时宽度会变化 - 掘金 (juejin.cn)

:deep.el-input.el-input--default.el-input--suffix {
  // 固定宽度
  width: 200px !important;
}

 

 5. 下拉框从数据字典取值 

http://localhost:8000/api/admin/dictionary/get-list?name=tax-rate 

 根据字典对象的name,value 来生成下拉框

1、getCurrentInstance 只能在 setup生命周期钩子中使用

2、ctx 和 proxy 都是 getCurrentInstance() 对象中的属性,通过解构赋值的方式拿到。可以看到,2者有所区别。ctx 是普通对象,proxy 是 Proxy 对象。

3、getCurrentInstance 是一个 function 方法,getCurrentInstance() 是一个对象,proxy 也是一个对象。proxy 是 getCurrentInstance() 对象中的一个属性,通过对象的解构赋值方式拿到 proxy

proxy.$dict 这个方法在哪里定义???
//aibpm.ui.plus-main\src\globalProperties\index.ts

import modal from './modal'

import { getDict } from './dict.js'  
export default function installGlobalProperties(app: any) {
  // 模态框对象
  app.config.globalProperties.$modal = modal
  
  //数据字典
  app.config.globalProperties.$dict = getDict;          // 2,引入字典封装
}

如何只取数据字典里enable的项,禁用项不显示呢?

后台代码在 \platform\ZhonTai.Admin\AI.Ext\Services\Dictionary的方法 public async Task<List<DictionaryListOutput>> GetListAsync(string name)
默认取所有,不过滤的,前台也是通过data-contract调用这个方法,加多一个参数??

ad_dictionary的表的对象只有name 和value有用? code没有用??
const { proxy } = getCurrentInstance() as any
const { tax_rate } = proxy.$dict("tax-rate"); 
            <el-form-item label="税率" prop="sku" :rules="[{ required: true, message: '请输入税率', trigger: ['blur', 'change'] }]">
              <el-select v-model="form.shortDescription" placeholder="请选择" size="default" style="width: 90px" >
                <el-option v-for="(item, index) in tax_rate" :key="index" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>
            </el-select>
            </el-form-item>

 todo: 为啥dictionary里的value是字符串,假如product表的tax-rate是decimal, 绑定就类型对不上。

A:将v-model值从数字转换为字符串-腾讯云开发者社区-腾讯云 (tencent.com)

A: 

              <el-select v-model="form.taxRate" placeholder="请选择" size="default" style="width: 90px" >
                <!-- <el-option v-for="(item, index) in tax_rate" :key="item.label" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option> -->
                
                <el-option label="13%" :value=0.13></el-option>
                <el-option label="9%" :value=0.09></el-option>
                <el-option label="6%" :value=0.06></el-option>
                <el-option label="0%" :value="0"></el-option>
            </el-select>
            </el-form-item>

或者更优雅的方法:

const { form } = toRefs(state)

const getTaxRate = computed(()=>{
  return  form.value.taxRate?.toString();
});

              <el-select v-model="getTaxRate" placeholder="请选择" size="default" style="width: 90px" >
                <el-option v-for="(item, index) in tax_rate" :key="item.label" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>
                
            </el-select>
            </el-form-item>

 

6.如果出现这个错误,【Vue warn】Record with path “/“ is either missing a “component(s)“ or “children“ property.

应该是你把一个vue页面,copy了一个副本在同一个目录。

 7.   计算属性的基本用法和可读写用法

 

computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容,它可以设置 getter 和 setter。

watch 监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。

计算属性一般用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑


 

//计算属性的基本用法
// const getTaxRate = computed(()=>{
//   return  form.value.taxRate?.toString();
// });

 

 // 修改计算属性的值
 const getTaxRate = computed({
      get () {
        // 如果读取计算属性的值,默认调用get方法
        return form.value.taxRate?.toString();
      },
      set (v) {
        // v是计算属性下传递的实参
        // 如果要想修改计算属性的值,默认调用set方法
        form.value.taxRate = (v==undefined? 0 :parseFloat(v))
      }
    })

 8. 多语言的实现


main.ts 里引入 

app.use(pinia).use(router).use(ElementPlus, { i18n: i18n.global.t }).use(i18n).use(VueGridLayout).use(globalProperties).use(FormControls).mount('#app')

 vue3中使用vue-i18n及注意事项简记 - 掘金 (juejin.cn)

在template 里使用

:label="$t('message.erp.one1')"  或者   {{$t('message.erp.delete')}}
 

在script中使用

import { useI18n } from 'vue-i18n'
const { t } = useI18n() 
title: t('menus.wIndex') 

 

语言文件里的标志不要重复就好
export default {
  erp: {
    one1: '简体中文1',
    two2: '简体中文2',
  },
}

 9.  DTO ProductAddInput 的字段默认是required的,如果不想必填,则类型要声明为可空的,比如string?

10. el-input 如何设置默认值?

 11. <el-form-item>的label宽度如何指定不换行?

 

 <el-form label-width="80px">

 

12.  slot 插槽, 根据名字来替换html的dom 

header

设置 header,也可以通过 slot#header 传入 DOM

<el-card> <div slot="header" class="clearfix">

<span>Card Header</span>

<el-button style="float: right; padding: 3px 0" type="text">Operation button</el-button> </div>

<!-- 卡片内容 --> <div>This is a card content</div>

</el-card>

 

13. 通过改变数组,来改变<el-table>的行数

const onAdd = () => {
  state.form.details?.push({ productId:1,lineNo:10,unit:'kg',unitPrice:123,saleCnt:456,lineAmount:123*456});
}

 

 

 

posted on 2023-11-11 22:12  Gu  阅读(103)  评论(0编辑  收藏  举报