代码示例
API 定义
反例
getTreeData(`/framework-server2/menuGroupManager/orgListWithMenuByType/${state.MenuGLOBAL}`, 'get')getTreeData(`/framework-server2/menuGroupManager/orgListWithMenuByType/${state.MenuGLOBAL}`, 'get')正例
import { server4A, frameworkEngin } from '@/utils/gap3-common'
export async function getInfo() {
return request({
url: `${server4A}/restapi/4a/view/userInfo`,
method: 'get',
})
}import { server4A, frameworkEngin } from '@/utils/gap3-common'
export async function getInfo() {
return request({
url: `${server4A}/restapi/4a/view/userInfo`,
method: 'get',
})
}loading 设置
操作类:提交、保存、审批、暂存、确认、删除批量类:批量设置、导出在 api 定义时,增加 headers: { loading: true }标识
export async function savePmProjectAp(params = {}, data = {}) {
return request({
url: `${myGlobal.GIC_BASE_URL}/projectInfo/saveProjectInfo`,
method: 'post',
params,
data,
headers: { loading: true },
})
}export async function savePmProjectAp(params = {}, data = {}) {
return request({
url: `${myGlobal.GIC_BASE_URL}/projectInfo/saveProjectInfo`,
method: 'post',
params,
data,
headers: { loading: true },
})
}API headers 参数说明
目前 headers 设置支持两类,loading 和 getHeaders loading:启用 loading getHeaders:返回整个 response,用于导出时取 headers 中的文件名,默认只返回 respinse.data
// 启用loading
headers: { loading: true },
headers: { getHeaders: true, loading: true },// 启用loading
headers: { loading: true },
headers: { getHeaders: true, loading: true },代码规范
组件引用一律使用大驼峰命名
正例
<CreateView :selectList="selectList" :table-configs="tableConfigs"></CreateView>
<script lang="ts" setup>
import { CreateView } from 'ctj-ui-next'
</script><CreateView :selectList="selectList" :table-configs="tableConfigs"></CreateView>
<script lang="ts" setup>
import { CreateView } from 'ctj-ui-next'
</script>反例
<create-form-view></create-form-view>
<script lang="ts" setup>
import createFormView from '@/components/gic/UIViews/createFormView/index.vue'
</script><create-form-view></create-form-view>
<script lang="ts" setup>
import createFormView from '@/components/gic/UIViews/createFormView/index.vue'
</script>弹窗都支持拖动,一律添加 v-dialogDrag 指令
正例:
<a-modal
class="gic-modal info-modal"
v-model:visible="modalchooseVisible"
title="退回意见"
width="640px"
:force-render="true"
@cancel="hideChooseProModal"
@ok="doBackPurchase"
>
<template #footer>
<a-button key="submit" type="primary" @click="doBackPurchase">确定</a-button>
</template>
<div class="modal-content" v-dialogDrag></div>
</a-modal><a-modal
class="gic-modal info-modal"
v-model:visible="modalchooseVisible"
title="退回意见"
width="640px"
:force-render="true"
@cancel="hideChooseProModal"
@ok="doBackPurchase"
>
<template #footer>
<a-button key="submit" type="primary" @click="doBackPurchase">确定</a-button>
</template>
<div class="modal-content" v-dialogDrag></div>
</a-modal>操作按钮统一添加 loading 状态或系统级 loading
正例 1:操作按钮添加防抖指令,不等待接口返回
<!--默认加载1.5s -->
<a-button v-btnLoading type="primary">确定</a-button>
<!--加载3s -->
<a-button v-btnLoading="3" type="primary">确定</a-button><!--默认加载1.5s -->
<a-button v-btnLoading type="primary">确定</a-button>
<!--加载3s -->
<a-button v-btnLoading="3" type="primary">确定</a-button>正例 2:按钮自带 loading 属性,防重
<a-button :loading="isLoading" type="primary">保存</a-button>
<script lang="ts" setup>
const isLoading = ref(false)
const handleClick = async () => {
isLoading.value = true
const res = await getData()
isLoading.value = false
}
</script><a-button :loading="isLoading" type="primary">保存</a-button>
<script lang="ts" setup>
const isLoading = ref(false)
const handleClick = async () => {
isLoading.value = true
const res = await getData()
isLoading.value = false
}
</script>正例 3:数据批量或响应时间长的,等待结果返回,使用系统级全屏 loading
<script lang="ts" setup>
import { show, hide } from '@/hooks/loading'
Modal.confirm({
title: '提示',
content: '是否确认挑选?',
okText: '确认',
cancelText: '取消',
async onOk() {
show()
const res: any = await save()
hide()
},
})
</script><script lang="ts" setup>
import { show, hide } from '@/hooks/loading'
Modal.confirm({
title: '提示',
content: '是否确认挑选?',
okText: '确认',
cancelText: '取消',
async onOk() {
show()
const res: any = await save()
hide()
},
})
</script>正例 4:antdesign a-spin 的使用说明:单据新增时加载二级视图页面需要添加 loading 状态,由于新增时会同时请求多个接口,若在 api 上统一处理,会存在本身添加了 loading 的接口并未请求完就已经关闭了 loading,此时可以使用 a-spin 包裹二级页面,自行处理 loading 的开关时间参考天津津南 163 V1.6.3 分支 @/views/gic/expense/billForm/billForm.vue
<a-spin :spinning="isLoading">二级视图组件</a-spin>
<script lang="ts" setup>
const isLoading = ref(false)
const handleClick = async () => {
isLoading.value = true
const res = await getData()
isLoading.value = false
}
</script><a-spin :spinning="isLoading">二级视图组件</a-spin>
<script lang="ts" setup>
const isLoading = ref(false)
const handleClick = async () => {
isLoading.value = true
const res = await getData()
isLoading.value = false
}
</script>获取当前用户信息,使用公共 hook 方法
正例:
<script lang="ts" setup>
import { getUserInfoCom } from '@/hooks/useComData'
// 获取当前登录人信息
const getUserInfo = async () => {
const useCom = await getUserInfoCom()
}
</script><script lang="ts" setup>
import { getUserInfoCom } from '@/hooks/useComData'
// 获取当前登录人信息
const getUserInfo = async () => {
const useCom = await getUserInfoCom()
}
</script>反例
<script lang="ts" setup>
import { getUser } from '@/api/gic/common'
// 获取当前登录人信息
const getUserInfo = async () => {
const res: any = await getUser()
}
</script><script lang="ts" setup>
import { getUser } from '@/api/gic/common'
// 获取当前登录人信息
const getUserInfo = async () => {
const res: any = await getUser()
}
</script>获取 UUID,前端生成
正例
import { useUUID } from '@/hooks/useUUID'
let uuId = useUUID()import { useUUID } from '@/hooks/useUUID'
let uuId = useUUID()反例
export async function getUUID() {
return request({
url: `${myGlobal.GIC_BASE_URL}/public/getUUID`,
method: 'get',
})
}export async function getUUID() {
return request({
url: `${myGlobal.GIC_BASE_URL}/public/getUUID`,
method: 'get',
})
}随意定义全局变量
反例 正例
变量定义随便
反例
const getBillTypeIdList = ref([]) //获取单据类型数据
const selectControl_assets = xxx
let currentId = ref('') // 发票idconst getBillTypeIdList = ref([]) //获取单据类型数据
const selectControl_assets = xxx
let currentId = ref('') // 发票id正例
const billTypeIdList = ref( []);// 单据类型数据
const selectControlAssets = xxx;
const invoiceId = ref("") // 发票idconst billTypeIdList = ref( []);// 单据类型数据
const selectControlAssets = xxx;
const invoiceId = ref("") // 发票id弹框数据混用
接口重复请求
反例 正例
一级组件(CreateView)示例
正例 http://172.16.22.196:8080/web/#/15/719
二级视图组件(create-from-view)规范
正例 http://172.16.22.196:8080/web/#/15/721
赋值表达式
逻辑运算符和赋值表达式(&&=,||=,??=)反例
data.flowModuleId ? '' : (data.flowModuleId = me.flowId)data.flowModuleId ? '' : (data.flowModuleId = me.flowId)正例
// 1、逻辑或赋值运算符
data.flowModuleId ||= me.flowId
// 2、常规
if (!data.flowModuleId) {
data.flowModuleId = me.flowId
}// 1、逻辑或赋值运算符
data.flowModuleId ||= me.flowId
// 2、常规
if (!data.flowModuleId) {
data.flowModuleId = me.flowId
}赋值表达式扩展
知识扩展逻辑运算符和赋值表达式(&&=,||=,??=) (1) &&=:逻辑与赋值运算符 x &&= y 等价于 x && (x=y):意思是当 x 为真时,x = y。 (2) ||=:逻辑或赋值运算符 x ||= y 等价于 x || (x = y):意思是仅在 x 为 false 的时候,x = y。 (3) ??=:逻辑空赋值运算符 x ??= y 等价于 x ?? (x = y):意思是仅在 x 为 null 或 undefined 的时候,x = y。
let a = 1
a &&= 2
console.log(a) // 2
const aa = { duration: 50, title: '' }
aa.duration ||= 10
console.log(aa.duration) // 50
aa.title ||= 'title is empty.'
console.log(aa.title) // "title is empty"
const a = { duration: 50 }
ac.duration ??= 10
console.log(ac.duration) // 50
ac.speed ??= 25
console.log(ac.speed) // 25let a = 1
a &&= 2
console.log(a) // 2
const aa = { duration: 50, title: '' }
aa.duration ||= 10
console.log(aa.duration) // 50
aa.title ||= 'title is empty.'
console.log(aa.title) // "title is empty"
const a = { duration: 50 }
ac.duration ??= 10
console.log(ac.duration) // 50
ac.speed ??= 25
console.log(ac.speed) // 25统一影响拦截处理
由于平台、内控及第三方对接时,接口影响结果中的状态码、结果消息不一致,导致应用上判断不通一如:内控{data:[],reason:'',status_code:'0000'},平台{data:[],message:'',code:'0000'},单据引擎{data:[],message:'',code:'00000'} 处理方式,在 response 统一拦截处理
/**
*统一处理返回结果,方便业务代码对结果集的统一处理
*内控结果{data:[],reason:'',status_code:'0000'}
*非内控如平台等其他情况统一处理为上述结构
*/
if (response.data) {
const code = response?.data?.status_code || response?.data?.code || '0000';
response.data.status_code = code == '00000' ? '0000' : code;
const reason = response.data.reason || response.data.message || null;
response.data.reason = reason;
}/**
*统一处理返回结果,方便业务代码对结果集的统一处理
*内控结果{data:[],reason:'',status_code:'0000'}
*非内控如平台等其他情况统一处理为上述结构
*/
if (response.data) {
const code = response?.data?.status_code || response?.data?.code || '0000';
response.data.status_code = code == '00000' ? '0000' : code;
const reason = response.data.reason || response.data.message || null;
response.data.reason = reason;
}使用示例:
平台接口:if (res.code == ResStatus.PtSuccess)
内控接口:if (resExtra.status_code === ResStatus.success)
转换后可统一使用
if (resExtra.status_code === ResStatus.success)平台接口:if (res.code == ResStatus.PtSuccess)
内控接口:if (resExtra.status_code === ResStatus.success)
转换后可统一使用
if (resExtra.status_code === ResStatus.success)属性安全性
对象为空时,做属性、循环等操作引起的 js 脚本异常,阻断页面的正常展示与加载 反例:
// 在biButtons为空时,会导致js错误中断页面操作
uiView.uiButtons.forEach(uiButton => {})// 在biButtons为空时,会导致js错误中断页面操作
uiView.uiButtons.forEach(uiButton => {})正例:可使用可选链运算符(?.)避免异常
示例1:
uiView.uiButtons && uiView.uiButtons.forEach(uiButton => {})
示例2(推荐):
uiView.uiButtons?.forEach(uiButton => {})示例1:
uiView.uiButtons && uiView.uiButtons.forEach(uiButton => {})
示例2(推荐):
uiView.uiButtons?.forEach(uiButton => {})