fix(ts): 收敛 CRM/BPM/IOT 局部类型

- CRM 商机状态 VO 合并:statuses 改为 BusinessStatusVO[],defaultStatus 改为 endStatus
- BPM form-create 对齐 v-model:api,用 @form-create/element-ui 的 Api 类型替代 ApiAttrs 并移除 @ts-ignore
- IOT OTA 任务 status 改可选、deviceScope 保持必填,详情页去掉假默认值
- 修复 SpuSelect expandRowKeys 类型,补 CRM 统计表格类型,移除 UserSignList 冗余 nickname 筛选
- 集合对比清理 vue-tsc 增量缓存后确认 0 新增错误

ts:check 133 → 85,无新增类型错误
master
YunaiV 2026-06-21 05:52:14 -07:00
parent 08abd54ca0
commit 361f4d8d15
27 changed files with 83 additions and 84 deletions

View File

@ -1,14 +1,18 @@
import request from '@/config/axios'
export interface BusinessStatusTypeVO {
id: number
id?: number
name: string
deptIds: number[]
statuses?: {
id: number
name: string
percent: number
}
statuses: BusinessStatusVO[]
}
export interface BusinessStatusVO {
id?: number
name: string
percent?: number
endStatus?: number
key?: string
}
export const DEFAULT_STATUSES = [
@ -30,7 +34,7 @@ export const DEFAULT_STATUSES = [
name: '无效',
percent: 0
}
]
] satisfies BusinessStatusVO[]
// 查询商机状态组列表
export const getBusinessStatusPage = async (params: any) => {

View File

@ -6,8 +6,8 @@ export interface OtaTask {
name: string // 任务名称
description?: string // 任务描述
firmwareId?: number // 固件编号
status: number // 任务状态
deviceScope?: number // 升级范围
status?: number // 任务状态
deviceScope: number // 升级范围
deviceIds?: number[] // 指定设备ID列表当升级范围为指定设备时使用
deviceTotalCount?: number // 设备总共数量
deviceSuccessCount?: number // 设备成功数量

View File

@ -28,7 +28,12 @@
<Icon class="mr-5px" icon="ep:refresh" />
重置
</el-button>
<el-button v-hasPermi="['bpm:form:create']" plain type="primary" @click="openForm">
<el-button
v-hasPermi="['bpm:form:create']"
plain
type="primary"
@click="openForm('create')"
>
<Icon class="mr-5px" icon="ep:plus" />
新增
</el-button>
@ -114,7 +119,7 @@ const { currentRoute, push } = useRouter() // 路由
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const list = ref<FormApi.FormVO[]>([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,

View File

@ -85,13 +85,11 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as FormApi from '@/api/bpm/form'
import { setConfAndFields2 } from '@/utils/formCreate'
import { BpmModelFormType } from '@/utils/constants'
import type { Rule } from '@form-create/element-ui'
const props = defineProps({
formList: {
type: Array,
required: true
}
})
defineProps<{
formList: FormApi.FormVO[]
}>()
const formRef = ref()
@ -101,7 +99,7 @@ const modelData = defineModel<any>()
//
const formPreview = ref({
formData: {},
rule: [],
rule: [] as Rule[],
option: {
submitBtn: false,
resetBtn: false,
@ -117,7 +115,7 @@ watch(
const data = await FormApi.getForm(newFormId)
setConfAndFields2(formPreview.value, data.conf, data.fields)
//
formPreview.value.rule.forEach((item: any) => {
formPreview.value.rule.forEach((item) => {
item.props = { ...item.props, disabled: true }
})
} else {

View File

@ -83,7 +83,7 @@ import {
import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue'
import ProcessInstanceSimpleViewer from '../detail/ProcessInstanceSimpleViewer.vue'
import ProcessInstanceTimeline from '../detail/ProcessInstanceTimeline.vue'
import type { ApiAttrs } from '@form-create/element-ui/types/config'
import type { Api as FormCreateApi } from '@form-create/element-ui'
import { useTagsViewStore } from '@/store/modules/tagsView'
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import * as DefinitionApi from '@/api/bpm/definition'
@ -105,7 +105,7 @@ const detailForm: any = ref({
option: {},
value: {}
}) //
const fApi = ref<ApiAttrs>()
const fApi = ref<FormCreateApi>()
//
const startUserSelectTasks: any = ref([]) //
const startUserSelectAssignees = ref({}) //
@ -234,12 +234,10 @@ const getApprovalDetail = async (row: any) => {
const setFieldPermission = (field: string, permission: string) => {
if (permission === FieldPermissionType.READ) {
// 1.
//@ts-ignore
fApi.value?.disabled(true, field)
// 2.
// fApi.value?.updateValidate(field, []);
try {
//@ts-ignore
const rule = fApi.value?.getRule(field)
if (rule) {
// false
@ -254,11 +252,9 @@ const setFieldPermission = (field: string, permission: string) => {
}
}
if (permission === FieldPermissionType.WRITE) {
//@ts-ignore
fApi.value?.disabled(false, field)
}
if (permission === FieldPermissionType.NONE) {
//@ts-ignore
fApi.value?.hidden(true, field)
}
}

View File

@ -48,7 +48,7 @@
<!-- 弹窗表单 -->
<Dialog title="表单详情" v-model="taskFormVisible" width="600">
<form-create
ref="fApi"
v-model:api="fApi"
v-model="taskForm.value"
:option="taskForm.option"
:rule="taskForm.rule"
@ -59,7 +59,7 @@
import { dateFormatter, formatPast2 } from '@/utils/formatTime'
import { propTypes } from '@/utils/propTypes'
import { DICT_TYPE } from '@/utils/dict'
import type { ApiAttrs } from '@form-create/element-ui/types/config'
import type { Api as FormCreateApi } from '@form-create/element-ui'
import { setConfAndFields2 } from '@/utils/formCreate'
import * as TaskApi from '@/api/bpm/task'
@ -72,7 +72,7 @@ const props = defineProps({
const tasks = ref([]) //
/** 查看表单 */
const fApi = ref<ApiAttrs>() // form-create API
const fApi = ref<FormCreateApi>() // form-create API
const taskForm = ref({
rule: [],
option: {},
@ -86,9 +86,9 @@ const handleFormDetail = async (row: any) => {
taskFormVisible.value = true
//
await nextTick()
fApi.value.fapi.btn.show(false)
fApi.value?.fapi?.resetBtn.show(false)
fApi.value?.fapi?.disabled(true)
fApi.value?.btn.show(false)
fApi.value?.resetBtn.show(false)
fApi.value?.disabled(true)
}
/** 只有 loading 完成时,才去加载流程列表 */

View File

@ -138,7 +138,7 @@ import { DICT_TYPE } from '@/utils/dict'
import { BpmModelType, BpmModelFormType } from '@/utils/constants'
import { setConfAndFields2 } from '@/utils/formCreate'
import { registerComponent } from '@/utils/routerHelper'
import type { ApiAttrs } from '@form-create/element-ui/types/config'
import type { Api as FormCreateApi } from '@form-create/element-ui'
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import * as UserApi from '@/api/system/user'
import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue'
@ -174,7 +174,7 @@ const auditIconsMap = {
}
// ========== ==========
const fApi = ref<ApiAttrs>() //
const fApi = ref<FormCreateApi>() //
const detailForm = ref({
rule: [],
option: {},
@ -235,7 +235,6 @@ const getApprovalDetail = async () => {
nextTick().then(() => {
fApi.value?.btn.show(false)
fApi.value?.resetBtn.show(false)
//@ts-ignore
fApi.value?.disabled(true)
//
if (formFieldsPermission) {
@ -276,17 +275,14 @@ const getProcessModelView = async () => {
/** 设置表单权限 */
const setFieldPermission = (field: string, permission: string) => {
if (permission === FieldPermissionType.READ) {
//@ts-ignore
fApi.value?.disabled(true, field)
}
if (permission === FieldPermissionType.WRITE) {
//@ts-ignore
fApi.value?.disabled(false, field)
//
writableFields.push(field)
}
if (permission === FieldPermissionType.NONE) {
//@ts-ignore
fApi.value?.hidden(true, field)
}
}

View File

@ -59,9 +59,9 @@
>
<el-option
v-for="item in statusTypeList"
:key="item.id"
:key="item.id!"
:label="item.name"
:value="item.id"
:value="item.id!"
/>
</el-select>
</el-form-item>
@ -194,7 +194,7 @@ watch(
const totalProductPrice = val.products.reduce((prev, curr) => prev + curr.totalPrice, 0)
const discountPrice =
val.discountPercent != null
? erpPriceMultiply(totalProductPrice, val.discountPercent / 100.0)
? (erpPriceMultiply(totalProductPrice, (val.discountPercent ?? 0) / 100.0) ?? 0)
: 0
const totalPrice = totalProductPrice - discountPrice
//

View File

@ -11,9 +11,9 @@
<el-select v-model="formData.status" placeholder="请选择商机阶段" class="w-1/1">
<el-option
v-for="item in statusList"
:key="item.id"
:key="item.id!"
:label="item.name + '(赢单率:' + item.percent + '%)'"
:value="item.id"
:value="item.id!"
/>
<el-option
v-for="item in BusinessStatusApi.DEFAULT_STATUSES"
@ -48,8 +48,7 @@ const formRules = reactive({
status: [{ required: true, message: '商机阶段不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
type BusinessStatus = NonNullable<BusinessStatusApi.BusinessStatusTypeVO['statuses']>
const statusList = ref<BusinessStatus[]>([]) //
const statusList = ref<BusinessStatusApi.BusinessStatusVO[]>([]) //
/** 打开弹窗 */
const open = async (business: BusinessApi.BusinessVO) => {

View File

@ -62,7 +62,7 @@
<!-- 关联商机选择弹框 -->
<BusinessListModal
ref="businessModalRef"
:customer-id="props.customerId"
:customer-id="props.customerId!"
@success="createContactBusinessList"
/>
</template>

View File

@ -5,7 +5,7 @@
</el-button>
<el-button
v-if="permissionListRef?.validateWrite"
:disabled="business.endStatus"
:disabled="!!business.endStatus"
type="success"
@click="openStatusForm()"
>

View File

@ -32,7 +32,7 @@
>
<el-table-column align="center" label="阶段" width="70">
<template #default="scope">
<el-text v-if="!scope.row.defaultStatus"> {{ scope.$index + 1 }}</el-text>
<el-text v-if="!scope.row.endStatus"> {{ scope.$index + 1 }}</el-text>
<el-text v-else></el-text>
</template>
</el-table-column>
@ -94,7 +94,7 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
const formData = ref<BusinessStatusApi.BusinessStatusTypeVO>({
id: undefined,
name: '',
deptIds: [],
@ -142,7 +142,7 @@ const submitForm = async () => {
//
formLoading.value = true
try {
const data = formData.value as unknown as BusinessStatusApi.BusinessStatusTypeVO
const data = formData.value
data.deptIds = treeRef.value.getCheckedKeys(false)
if (formType.value === 'create') {
await BusinessStatusApi.createBusinessStatus(data)

View File

@ -257,7 +257,7 @@ watch(
const totalProductPrice = val.products.reduce((prev, curr) => prev + curr.totalPrice, 0)
const discountPrice =
val.discountPercent != null
? erpPriceMultiply(totalProductPrice, val.discountPercent / 100.0)
? (erpPriceMultiply(totalProductPrice, (val.discountPercent ?? 0) / 100.0) ?? 0)
: 0
const totalPrice = totalProductPrice - discountPrice
//

View File

@ -77,7 +77,8 @@ const list = ref([]) // 列表的数据
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
customerId: undefined as unknown // undefined + number
customerId: undefined as number | undefined,
businessId: undefined as number | undefined
})
/** 查询列表 */
@ -86,6 +87,7 @@ const getList = async () => {
try {
//
queryParams.customerId = undefined
queryParams.businessId = undefined
//
let data = { list: [], total: 0 }
switch (props.bizType) {

View File

@ -33,7 +33,7 @@
:src="url"
:preview-src-list="scope.row.picUrls"
class="w-10 h-10 mr-1"
:initial-index="index"
:initial-index="Number(index)"
fit="cover"
preview-teleported
/>

View File

@ -84,7 +84,7 @@
<el-option
v-for="data in receivablePlanList"
:key="data.id"
:disabled="data.receivableId"
:disabled="!!data.receivableId"
:label="'第 ' + data.period + ' 期'"
:value="data.id!"
/>
@ -207,7 +207,9 @@ const open = async (
formData.value.customerId = receivablePlan.customerId
await handleCustomerChange(receivablePlan.customerId)
formData.value.contractId = receivablePlan.contractId
await handleContractChange(receivablePlan.contractId)
if (receivablePlan.contractId) {
await handleContractChange(receivablePlan.contractId)
}
if (receivablePlan.id) {
formData.value.planId = receivablePlan.id
formData.value.price = receivablePlan.price

View File

@ -93,7 +93,7 @@ onMounted(async () => {
close()
return
}
receivableId.value = id
receivableId.value = Number(id)
await getReceivable(receivableId.value)
})
</script>

View File

@ -180,7 +180,6 @@ const echartsOption = reactive<EChartsOption>({
type: 'value',
name: '赢单转化率',
axisTick: {
alignWithLabel: true,
lineStyle: { width: 0 }
},
axisLabel: {
@ -199,7 +198,6 @@ const echartsOption = reactive<EChartsOption>({
type: 'value',
name: '商机数',
axisTick: {
alignWithLabel: true,
lineStyle: { width: 0 }
},
axisLabel: {

View File

@ -120,7 +120,6 @@ const echartsOption = reactive<EChartsOption>({
type: 'value',
name: '',
axisTick: {
alignWithLabel: true,
lineStyle: {
width: 0
}
@ -195,8 +194,12 @@ const loadData = async () => {
}
//
const columnsData = reactive([])
const tableData = reactive([
type TableColumn = { label: string; prop: string }
type TableRow = { title: string; [key: string]: string | number }
const columnsData = reactive<TableColumn[]>([])
const tableData = reactive<TableRow[]>([
{ title: '当月合同数量统计(个)' },
{ title: '上月合同数量统计(个)' },
{ title: '去年当月合同数量统计(个)' },

View File

@ -120,7 +120,6 @@ const echartsOption = reactive<EChartsOption>({
type: 'value',
name: '',
axisTick: {
alignWithLabel: true,
lineStyle: {
width: 0
}
@ -195,8 +194,12 @@ const loadData = async () => {
}
//
const columnsData = reactive([])
const tableData = reactive([
type TableColumn = { label: string; prop: string }
type TableRow = { title: string; [key: string]: string | number }
const columnsData = reactive<TableColumn[]>([])
const tableData = reactive<TableRow[]>([
{ title: '当月合同金额统计(元)' },
{ title: '上月合同金额统计(元)' },
{ title: '去年当月合同金额统计(元)' },

View File

@ -120,7 +120,6 @@ const echartsOption = reactive<EChartsOption>({
type: 'value',
name: '',
axisTick: {
alignWithLabel: true,
lineStyle: {
width: 0
}
@ -195,8 +194,12 @@ const loadData = async () => {
}
//
const columnsData = reactive([])
const tableData = reactive([
type TableColumn = { label: string; prop: string }
type TableRow = { title: string; [key: string]: string | number }
const columnsData = reactive<TableColumn[]>([])
const tableData = reactive<TableRow[]>([
{ title: '当月回款金额统计(元)' },
{ title: '上月回款金额统计(元)' },
{ title: '去年当月回款金额统计(元)' },

View File

@ -15,7 +15,6 @@
class="!w-240px"
type="year"
value-format="YYYY"
:default-time="[new Date().getFullYear()]"
/>
</el-form-item>
<el-form-item label="归属部门" prop="deptId">

View File

@ -87,8 +87,9 @@
<!-- 任务管理 -->
<OtaTaskList
v-if="firmwareId && firmware?.productId"
:firmware-id="firmwareId"
:product-id="firmware?.productId"
:product-id="firmware.productId"
@success="getStatistics"
/>
</div>

View File

@ -6,10 +6,10 @@
<el-descriptions-item label="任务编号">{{ task.id }}</el-descriptions-item>
<el-descriptions-item label="任务名称">{{ task.name }}</el-descriptions-item>
<el-descriptions-item label="升级范围">
<dict-tag :type="DICT_TYPE.IOT_OTA_TASK_DEVICE_SCOPE" :value="task.deviceScope" />
<dict-tag :type="DICT_TYPE.IOT_OTA_TASK_DEVICE_SCOPE" :value="task.deviceScope!" />
</el-descriptions-item>
<el-descriptions-item label="任务状态">
<dict-tag :type="DICT_TYPE.IOT_OTA_TASK_STATUS" :value="task.status" />
<dict-tag :type="DICT_TYPE.IOT_OTA_TASK_STATUS" :value="task.status!" />
</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ task.createTime ? formatDate(task.createTime) : '-' }}

View File

@ -150,7 +150,7 @@ const spuListRef = ref<InstanceType<typeof ElTable>>()
const skuListRef = ref<InstanceType<typeof SkuList>>() // Ref
const spuData = ref<ProductSpuApi.Spu>() //
const isExpand = ref(false) // SKU
const expandRowKeys = ref<number[]>() // row-key 使 keys
const expandRowKeys = ref<string[]>() // row-key 使 keys
//============ ============
const selectedSpuId = ref<number>(0) // spuId
@ -210,7 +210,7 @@ const expandChange = async (row: ProductSpuApi.Spu, expandedRows?: ProductSpuApi
if (selectedSpuId.value !== 0) {
if (row.id !== selectedSpuId.value) {
message.warning('你已选择商品请先取消')
expandRowKeys.value = [selectedSpuId.value]
expandRowKeys.value = [String(selectedSpuId.value)]
return
}
// skuList spu skuList
@ -238,7 +238,7 @@ const expandChange = async (row: ProductSpuApi.Spu, expandedRows?: ProductSpuApi
propertyList.value = getPropertyList(res)
spuData.value = res
isExpand.value = true
expandRowKeys.value = [row.id!]
expandRowKeys.value = [String(row.id!)]
}
//

View File

@ -3,7 +3,7 @@
<el-table-column label="地址编号" align="center" prop="id" width="150px" />
<el-table-column label="收件人名称" align="center" prop="name" width="150px" />
<el-table-column label="手机号" align="center" prop="mobile" width="150px" />
<el-table-column label="地区编码" align="center" prop="areaId" width="150px" />
<el-table-column label="所在地区" align="center" prop="areaName" width="150px" />
<el-table-column label="收件详细地址" align="center" prop="detailAddress" />
<el-table-column label="是否默认" align="center" prop="defaultStatus" width="150px">
<template #default="scope">

View File

@ -8,15 +8,6 @@
:inline="true"
label-width="68px"
>
<el-form-item label="签到用户" prop="nickname">
<el-input
v-model="queryParams.nickname"
placeholder="请输入签到用户"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="签到天数" prop="day">
<el-input
v-model="queryParams.day"
@ -90,7 +81,6 @@ const queryParams = reactive({
pageNo: 1,
pageSize: 10,
userId: NaN,
nickname: null,
day: null,
createTime: []
})