push
This commit is contained in:
4
lib/paas/component/index.ts
Normal file
4
lib/paas/component/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
export { PageTitle } from '/nerv-lib/paas/component/page-title';
|
||||
export { NsRadioGroupApi } from '../../paas/component/radio';
|
||||
4
lib/paas/component/page-title/index.ts
Normal file
4
lib/paas/component/page-title/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import pageTitle from './page-title.vue';
|
||||
import { withInstall } from '/nerv-lib/util';
|
||||
|
||||
export const PageTitle = withInstall(pageTitle);
|
||||
38
lib/paas/component/page-title/page-title.vue
Normal file
38
lib/paas/component/page-title/page-title.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="page-title">
|
||||
<h5>{{ title }}</h5>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'pageTitle',
|
||||
props: {
|
||||
title: String,
|
||||
},
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
h5 {
|
||||
position: relative;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
margin: 0 24px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 2px;
|
||||
height: 12px;
|
||||
background-color: #00acff;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
9
lib/paas/component/radio/index.ts
Normal file
9
lib/paas/component/radio/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
import type { App } from 'vue';
|
||||
import nsRadioGroupApi from './radio-group-api.vue';
|
||||
|
||||
export const NsRadioGroupApi = function (app: App) {
|
||||
app.component(nsRadioGroupApi.name, nsRadioGroupApi);
|
||||
return app;
|
||||
};
|
||||
271
lib/paas/component/radio/radio-group-api.vue
Normal file
271
lib/paas/component/radio/radio-group-api.vue
Normal file
@@ -0,0 +1,271 @@
|
||||
<template>
|
||||
<a-radio-group option-type="button"
|
||||
v-bind="getBindValue" :options="getOptions" v-model:value="modelValue"
|
||||
>
|
||||
</a-radio-group>
|
||||
<template v-if="tips">
|
||||
<p class="tips">{{tips}}</p>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {computed, defineComponent, nextTick, PropType, ref, unref, watch} from 'vue';
|
||||
import { PropTypes, tuple } from '/nerv-lib/util/type';
|
||||
import {HttpRequestConfig, useApi} from "/nerv-lib/use";
|
||||
import {cloneDeep, get, isArray, isEqual, isFunction, isString, isUndefined} from "lodash-es";
|
||||
type ChangeValue = string | number | undefined | string[] | number[];
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NsRadioGroupApi',
|
||||
props: {
|
||||
radioType: PropTypes.oneOf(tuple('radio', 'radioButton')).def('radioButton'),
|
||||
prefixCls: PropTypes.string,
|
||||
defaultValue: PropTypes.any,
|
||||
value: PropTypes.any,
|
||||
size: PropTypes.oneOf(tuple('large', 'default', 'small')).def('default'),
|
||||
// options: PropTypes.array,
|
||||
disabled: PropTypes.looseBool,
|
||||
name: PropTypes.string,
|
||||
buttonStyle: PropTypes.oneOf(tuple('outline', 'solid')).def('solid'),
|
||||
onChange: PropTypes.func,
|
||||
api: {
|
||||
type: [String, Object, Function] as PropType<string | Function | HttpRequestConfig>,
|
||||
required: true,
|
||||
},
|
||||
field: String,
|
||||
params: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
resultField: {
|
||||
type: String,
|
||||
default: 'data.data',
|
||||
},
|
||||
firstOption: {
|
||||
type: Object,
|
||||
},
|
||||
numberToString: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
paramsRequired: {
|
||||
type: [Boolean, Object],
|
||||
default: false,
|
||||
},
|
||||
labelField: {
|
||||
type: [String, Function],
|
||||
default: 'label',
|
||||
},
|
||||
valueField: {
|
||||
type: String,
|
||||
default: 'value',
|
||||
},
|
||||
autoSelectFirst: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
//数据筛选函数
|
||||
filterData: {
|
||||
type: Function,
|
||||
},
|
||||
tips: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['change', 'validateChange'],
|
||||
// emits: ['update:value', 'change'],
|
||||
setup(props, { attrs, emit }) {
|
||||
let isLoading = false;
|
||||
const isLoad = ref(false);
|
||||
const options = ref([]);
|
||||
let isFirstLoad = !!props.api; // 是否第一次加载
|
||||
const changeValue = ref<any>(undefined);
|
||||
const filterFiledRef = ref<string | undefined>(undefined);
|
||||
|
||||
|
||||
const getBindValue = computed(() => {
|
||||
return {
|
||||
...props,
|
||||
...attrs,
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* 根据请求得到的data获取options
|
||||
*/
|
||||
const getOptions = computed(() => {
|
||||
const { firstOption, labelField, valueField, numberToString } = props;
|
||||
const sourceOptions = [];
|
||||
firstOption && sourceOptions.push(firstOption);
|
||||
return unref(options).reduce((acc, next: Recordable) => {
|
||||
if (isString(next)) {
|
||||
//值是字符串类型
|
||||
const option = {
|
||||
label: next,
|
||||
value: next,
|
||||
};
|
||||
acc.push(option);
|
||||
return acc;
|
||||
} else {
|
||||
const value = get(next, valueField);
|
||||
const option = {
|
||||
...next,
|
||||
label: isFunction(labelField) ? labelField(next) : get(next, labelField as string),
|
||||
value: numberToString ? `${value}` : value,
|
||||
};
|
||||
acc.push(option);
|
||||
return acc;
|
||||
}
|
||||
console.log(acc)
|
||||
}, sourceOptions);
|
||||
});
|
||||
/**
|
||||
* 获取数据
|
||||
*/
|
||||
const fetch = () => {
|
||||
isLoading = true;
|
||||
const requestConfig: HttpRequestConfig = { method: 'get' };
|
||||
const {
|
||||
api,
|
||||
params: _params,
|
||||
resultField,
|
||||
filterData,
|
||||
} = props;
|
||||
const params: Recordable = cloneDeep(_params);
|
||||
const { httpRequest } = useApi();
|
||||
httpRequest({ api, params, requestConfig })
|
||||
.then((res: Recordable) => {
|
||||
emit('validateChange', { help: undefined });
|
||||
if (resultField) {
|
||||
let data = get(res, resultField) || [];
|
||||
// data = data.splice(Math.floor(Math.random() * 3), Math.floor(Math.random() * 5 + 5));
|
||||
if (isFunction(filterData)) {
|
||||
data = data.filter(filterData);
|
||||
}
|
||||
options.value = data;
|
||||
|
||||
}
|
||||
isLoad.value = true;
|
||||
isLoading = false;
|
||||
})
|
||||
.catch((error: any) => {
|
||||
if (error?.response?.status === 403) {
|
||||
emit('validateChange', { help: '暂无权限', validateStatus: 'error' });
|
||||
nextTick(() => {
|
||||
//清空编辑初始值
|
||||
modelValue.value = undefined;
|
||||
});
|
||||
}
|
||||
options.value = [];
|
||||
isLoading = false;
|
||||
});
|
||||
};
|
||||
|
||||
fetch();
|
||||
|
||||
let lastParams: any = undefined;
|
||||
|
||||
/**
|
||||
** 绑定value
|
||||
*/
|
||||
const modelValue = computed({
|
||||
set(value: ChangeValue) {
|
||||
if (isEqual(value, changeValue.value)) return;
|
||||
changeValue.value = value;
|
||||
triggerChange(value);
|
||||
},
|
||||
get() {
|
||||
return changeValue.value;
|
||||
},
|
||||
});
|
||||
/**
|
||||
* 传入值需要
|
||||
* 前提option已获取到数据
|
||||
*/
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
if (isLoad.value) {
|
||||
modelValue.value = props.value;
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => getOptions.value,
|
||||
() => {
|
||||
const { value, autoSelectFirst } = props;
|
||||
// 首次加载如果有值则选中值
|
||||
if (isFirstLoad && !isUndefined(value)) {
|
||||
modelValue.value = value;
|
||||
}else if (!filterFiledRef.value) {
|
||||
if (autoSelectFirst) {
|
||||
modelValue.value = getOptions.value[0]?.value;
|
||||
}
|
||||
}
|
||||
isFirstLoad = false;
|
||||
}
|
||||
);
|
||||
/**
|
||||
* 重写change ant 初始化数据、删除数据时不触发change
|
||||
* @param value
|
||||
*/
|
||||
function triggerChange(value: ChangeValue) {
|
||||
if (isUndefined(value)) {
|
||||
emit('change', value, undefined);
|
||||
} else if (isArray(value)) {
|
||||
const options: Record<string, any>[] = [];
|
||||
value.forEach((v) => {
|
||||
getOptions.value.forEach((option) => {
|
||||
if (option.value === v) {
|
||||
options.push(option);
|
||||
}
|
||||
});
|
||||
});
|
||||
emit('change', value, options);
|
||||
} else {
|
||||
let op = {};
|
||||
getOptions.value.forEach((option) => {
|
||||
if (option.value === value) {
|
||||
op = option;
|
||||
}
|
||||
});
|
||||
emit('change', value, op);
|
||||
}
|
||||
}
|
||||
/**
|
||||
** 联动 immediate 为是否主动获取数据
|
||||
*/
|
||||
watch(
|
||||
[() => props.params, () => props.api],
|
||||
async () => {
|
||||
const { params } = props;
|
||||
if (!isEqual(lastParams, params)) {
|
||||
if (props.immediate || true) {
|
||||
//todo 暂时全设为主动获取
|
||||
lastParams = cloneDeep(params);
|
||||
await fetch();
|
||||
}
|
||||
isLoad.value = false; // 设置成false 点击下拉才会触发
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: props.immediate }
|
||||
);
|
||||
return {
|
||||
getBindValue,
|
||||
getOptions,
|
||||
modelValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.tips {
|
||||
color: #7f7e7e;
|
||||
line-height: 20px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user