mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-11-14 21:23:47 +08:00
发布v2.16.10版本,更新内容请查看:https://github.com/bufanyun/hotgo/blob/v2.0/docs/guide-zh-CN/start-update-log.md
This commit is contained in:
144
web/src/components/ComplexMemberPicker/index.vue
Normal file
144
web/src/components/ComplexMemberPicker/index.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-bind="$props"
|
||||
:style="{ width: '68%' }"
|
||||
v-model:value="memberId"
|
||||
:options="memberOption"
|
||||
:render-label="renderLabel"
|
||||
:filter="handleReceiverFilter"
|
||||
@update:value="handleChangeMemberId"
|
||||
clearable
|
||||
filterable
|
||||
/>
|
||||
<n-select
|
||||
:consistent-menu-width="false"
|
||||
:style="{ width: '32%', 'min-width': '90px' }"
|
||||
:options="selectOptions"
|
||||
v-model:value="optVal"
|
||||
@update:value="handleUpdateOptions"
|
||||
/>
|
||||
</n-input-group>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h, onMounted, ref, watch } from 'vue';
|
||||
import { GetMemberOption } from '@/api/org/user';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { NText, SelectRenderLabel } from 'naive-ui';
|
||||
import { basicProps } from './props';
|
||||
|
||||
const props = defineProps({
|
||||
...basicProps,
|
||||
});
|
||||
const emit = defineEmits(['update:value']);
|
||||
const userStore = useUserStore();
|
||||
const memberId = ref(null);
|
||||
const optVal = ref('-1');
|
||||
const memberOption = ref([]);
|
||||
const selectOptions = [
|
||||
{
|
||||
label: '查全部',
|
||||
value: '-1',
|
||||
},
|
||||
{
|
||||
label: '查本人',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '查下级',
|
||||
value: '2',
|
||||
},
|
||||
];
|
||||
|
||||
const renderLabel: SelectRenderLabel = (option: { username: ''; label: '' }) => {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
padding: '4px 0',
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
marginRight: '4px',
|
||||
},
|
||||
},
|
||||
[option.username as string]
|
||||
),
|
||||
h(
|
||||
NText,
|
||||
{ depth: 3, tag: 'div' },
|
||||
{
|
||||
default: () => option.label as string,
|
||||
}
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
function handleReceiverFilter(pattern: string, option: object): boolean {
|
||||
const isPatternInLabel = option.label.includes(pattern);
|
||||
const isPatternInUsername = option.username.includes(pattern);
|
||||
const isValueEqual = option.value.toString() === pattern;
|
||||
return isPatternInLabel || isPatternInUsername || isValueEqual;
|
||||
}
|
||||
|
||||
function handleChangeMemberId(v: string) {
|
||||
memberId.value = v;
|
||||
handleUpdateValue();
|
||||
}
|
||||
|
||||
function handleUpdateOptions(value: string) {
|
||||
optVal.value = value;
|
||||
handleUpdateValue();
|
||||
}
|
||||
|
||||
function handleUpdateValue() {
|
||||
if (memberId.value) {
|
||||
emit('update:value', [memberId.value, optVal.value]);
|
||||
} else {
|
||||
emit('update:value', null);
|
||||
}
|
||||
}
|
||||
|
||||
function resetFields() {
|
||||
memberId.value = null;
|
||||
optVal.value = '-1';
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(v) => {
|
||||
if (!v) {
|
||||
resetFields();
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
GetMemberOption().then((res) => {
|
||||
if (res) {
|
||||
memberOption.value = res;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
||||
13
web/src/components/ComplexMemberPicker/props.ts
Normal file
13
web/src/components/ComplexMemberPicker/props.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { NSelect } from 'naive-ui';
|
||||
|
||||
export const basicProps = {
|
||||
...NSelect.props,
|
||||
defaultValue: {
|
||||
type: [Array],
|
||||
default: null,
|
||||
},
|
||||
value: {
|
||||
type: [Array],
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
@@ -66,6 +66,13 @@
|
||||
v-bind="getComponentProps(schema)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="schema.component === 'ComplexMemberPicker'">
|
||||
<ComplexMemberPicker
|
||||
:class="{ isFull: schema.isFull !== false && getProps.isFull }"
|
||||
v-model:value="formModel[schema.field]"
|
||||
v-bind="getComponentProps(schema)"
|
||||
/>
|
||||
</template>
|
||||
<!--动态渲染表单组件-->
|
||||
<component
|
||||
v-else
|
||||
@@ -147,18 +154,16 @@
|
||||
import { createPlaceholderMessage } from './helper';
|
||||
import { useFormEvents } from './hooks/useFormEvents';
|
||||
import { useFormValues } from './hooks/useFormValues';
|
||||
|
||||
import ComplexMemberPicker from '../../ComplexMemberPicker/index.vue';
|
||||
import { basicProps } from './props';
|
||||
import { DownOutlined, UpOutlined, QuestionCircleOutlined } from '@vicons/antd';
|
||||
|
||||
import type { Ref } from 'vue';
|
||||
import type { GridProps } from 'naive-ui/lib/grid';
|
||||
import type { FormSchema, FormProps, FormActionType } from './types/form';
|
||||
|
||||
import {isArray, isBoolean, isFunction} from '@/utils/is';
|
||||
import { isArray, isBoolean, isFunction } from '@/utils/is';
|
||||
import { deepMerge } from '@/utils';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import {ActionItem} from "@/components/Table";
|
||||
import { ActionItem } from '@/components/Table';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicForm',
|
||||
@@ -237,7 +242,7 @@
|
||||
});
|
||||
|
||||
const getBindValue = computed(
|
||||
() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable)
|
||||
() => ({ ...attrs, ...props, ...unref(getProps) }) as Recordable
|
||||
);
|
||||
|
||||
const getSchema = computed((): FormSchema[] => {
|
||||
|
||||
@@ -25,4 +25,5 @@ export type ComponentType =
|
||||
| 'NIconPicker'
|
||||
| 'NRender'
|
||||
| 'NSlider'
|
||||
| 'NRate';
|
||||
| 'NRate'
|
||||
| 'ComplexMemberPicker';
|
||||
|
||||
@@ -34,7 +34,7 @@ export const RedirectRoute: AppRouteRecordRaw = {
|
||||
children: [
|
||||
{
|
||||
path: '/redirect/:path(.*)',
|
||||
name: RedirectName,
|
||||
name: `${RedirectName}Son`,
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
title: RedirectName,
|
||||
|
||||
@@ -183,7 +183,6 @@ export const renderPopoverMemberSumma = (member: MemberSumma | null | undefined)
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
strong: true,
|
||||
size: 'small',
|
||||
text: true,
|
||||
iconPlacement: 'right',
|
||||
|
||||
@@ -146,6 +146,10 @@ export function isNullOrUnDef(val: unknown): val is null | undefined {
|
||||
return isUnDef(val) || isNull(val);
|
||||
}
|
||||
|
||||
export function isEmpty(value: any): boolean {
|
||||
return value === undefined || value === null || value === '';
|
||||
}
|
||||
|
||||
// 判断字串符是否以字母开头
|
||||
export function isLetterBegin(str) {
|
||||
return /^[A-z]/.test(str);
|
||||
|
||||
@@ -81,7 +81,7 @@ export default () => {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
createSocket();
|
||||
}, 2000);
|
||||
}, 1000 * 10);
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
|
||||
@@ -106,7 +106,7 @@ export const columns = [
|
||||
{
|
||||
title: '文件名称',
|
||||
key: 'name',
|
||||
width: 120,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '文件',
|
||||
@@ -157,7 +157,7 @@ export const columns = [
|
||||
{
|
||||
title: '扩展类型',
|
||||
key: 'mimeType',
|
||||
width: 120,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1280"
|
||||
:scroll-x="scrollX"
|
||||
:resizeHeightOffset="-20000"
|
||||
>
|
||||
<template #tableTitle>
|
||||
@@ -77,7 +77,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, onMounted, reactive, ref } from 'vue';
|
||||
import { computed, h, onMounted, reactive, ref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
@@ -93,6 +93,7 @@
|
||||
import FileUpload from '@/components/FileChooser/src/Upload.vue';
|
||||
import MultipartUpload from '@/components/Upload/multipartUpload.vue';
|
||||
import { Attachment } from '@/components/FileChooser/src/model';
|
||||
import { adaTableScrollX } from '@/utils/hotgo';
|
||||
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
@@ -106,7 +107,7 @@
|
||||
const multipartUploadRef = ref();
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 120,
|
||||
width: 132,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
@@ -128,6 +129,10 @@
|
||||
},
|
||||
});
|
||||
|
||||
const scrollX = computed(() => {
|
||||
return adaTableScrollX(columns, actionColumn.width);
|
||||
});
|
||||
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 100,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { h } from 'vue';
|
||||
import { NAvatar, NAvatarGroup, NTooltip } from 'naive-ui';
|
||||
import { renderOptionTag } from '@/utils';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
|
||||
const dict = useDictStore();
|
||||
export const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
@@ -106,7 +104,3 @@ export const columns = [
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export function loadOptions() {
|
||||
dict.loadOptions(['sys_normal_disable']);
|
||||
}
|
||||
|
||||
215
web/src/views/apply/notice/edit.vue
Normal file
215
web/src/views/apply/notice/edit.vue
Normal file
@@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-drawer v-model:show="showModal" :width="dialogWidth">
|
||||
<n-drawer-content closable>
|
||||
<template #header>
|
||||
{{
|
||||
formValue.id > 0
|
||||
? '编辑' + dict.getLabel('noticeTypeOptions', formValue.type) + ' #' + formValue.id
|
||||
: '发送' + dict.getLabel('noticeTypeOptions', formValue.type)
|
||||
}}
|
||||
</template>
|
||||
<n-scrollbar style="max-height: 87vh" class="pr-5">
|
||||
<n-spin :show="loading" description="请稍候...">
|
||||
<n-alert :show-icon="false" type="info">
|
||||
消息发送成功后如果接收人在线会立即收到一条消息通知,编辑已发送的消息不会再次通知
|
||||
</n-alert>
|
||||
<n-form
|
||||
:model="formValue"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
:label-placement="settingStore.isMobile ? 'top' : 'left'"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="消息标题" path="title">
|
||||
<n-input placeholder="请输入消息标题" v-model:value="formValue.title" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="接收人" path="receiver" v-if="formValue.type === 3">
|
||||
<n-select
|
||||
multiple
|
||||
:options="options"
|
||||
:render-label="renderLabel"
|
||||
:render-tag="renderMultipleSelectTag"
|
||||
v-model:value="formValue.receiver"
|
||||
filterable
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="消息内容" path="content">
|
||||
<template v-if="formValue.type === 1">
|
||||
<n-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 10 }"
|
||||
placeholder="请输入通知内容"
|
||||
v-model:value="formValue.content"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Editor style="height: 320px" v-model:value="formValue.content" />
|
||||
</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-gi>
|
||||
<n-form-item label="标签" path="tag">
|
||||
<n-select
|
||||
clearable
|
||||
placeholder="可以不填"
|
||||
:render-tag="renderTag"
|
||||
v-model:value="formValue.tag"
|
||||
:options="dict.getOptionUnRef('noticeTagOptions')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input-number style="width: 100%" v-model:value="formValue.sort" clearable />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="formValue.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in statusOptions"
|
||||
:key="status.value"
|
||||
:value="status.value"
|
||||
:label="status.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="备注" path="remark">
|
||||
<n-input
|
||||
type="textarea"
|
||||
placeholder="请输入备注,没有可以不填"
|
||||
v-model:value="formValue.remark"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</n-scrollbar>
|
||||
<template #footer>
|
||||
<n-space>
|
||||
<n-button @click="closeForm"> 取消 </n-button>
|
||||
<n-button type="primary" :loading="formBtnLoading" @click="confirmForm">
|
||||
立即发送
|
||||
</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-drawer-content>
|
||||
</n-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { personOption, renderLabel, renderMultipleSelectTag } from '@/enums/systemMessageEnum';
|
||||
import Editor from '@/components/Editor/editor.vue';
|
||||
import { statusOptions } from '@/enums/optionsiEnum';
|
||||
import { GetMemberOption } from '@/api/org/user';
|
||||
import { MaxSort, EditLetter, EditNotice, EditNotify } from '@/api/apply/notice';
|
||||
import { renderTag } from '@/utils';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
import { State, newState, rules } from './model';
|
||||
|
||||
const emit = defineEmits(['reloadTable']);
|
||||
const message = useMessage();
|
||||
const settingStore = useProjectSettingStore();
|
||||
const dict = useDictStore();
|
||||
const loading = ref(false);
|
||||
const showModal = ref(false);
|
||||
const formValue = ref<State>(newState(null));
|
||||
const formRef = ref<any>({});
|
||||
const formBtnLoading = ref(false);
|
||||
const options = ref<personOption[]>();
|
||||
const dialogWidth = ref(adaModalWidth(840));
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
switch (formValue.value.type) {
|
||||
case 1:
|
||||
EditNotify(formValue.value).then((_res) => {
|
||||
confirmComplete();
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
EditNotice(formValue.value).then((_res) => {
|
||||
confirmComplete();
|
||||
});
|
||||
break;
|
||||
case 3:
|
||||
EditLetter(formValue.value).then((_res) => {
|
||||
confirmComplete();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
message.error('公告类型不支持');
|
||||
}
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function confirmComplete() {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
closeForm();
|
||||
emit('reloadTable');
|
||||
});
|
||||
}
|
||||
|
||||
function getMemberOption() {
|
||||
GetMemberOption().then((res) => {
|
||||
options.value = res;
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭抽屉
|
||||
function closeForm() {
|
||||
showModal.value = false;
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
// 打开抽屉
|
||||
function openModal(state: State, type: number) {
|
||||
showModal.value = true;
|
||||
dialogWidth.value = adaModalWidth(840);
|
||||
getMemberOption();
|
||||
|
||||
// 新增
|
||||
if (!state || state.id < 1) {
|
||||
formValue.value = newState(state);
|
||||
formValue.value.type = type;
|
||||
|
||||
loading.value = true;
|
||||
MaxSort()
|
||||
.then((res) => {
|
||||
formValue.value.sort = res.sort;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 编辑
|
||||
formValue.value = newState(state);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
openModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
@@ -26,7 +26,7 @@
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1280"
|
||||
:scroll-x="scrollX"
|
||||
:resizeHeightOffset="-20000"
|
||||
>
|
||||
<template #tableTitle>
|
||||
@@ -88,109 +88,8 @@
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
:block-scroll="false"
|
||||
:mask-closable="false"
|
||||
preset="dialog"
|
||||
:title="
|
||||
formParams.id > 0
|
||||
? '编辑' + dict.getLabel('noticeTypeOptions', formParams.type) + ' #' + formParams.id
|
||||
: '发送' + dict.getLabel('noticeTypeOptions', formParams.type)
|
||||
"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<n-alert :show-icon="false" type="info">
|
||||
消息发送成功后如果接收人在线会立即收到一条消息通知,编辑已发送的消息不会再次通知
|
||||
</n-alert>
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-placement="left"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="消息标题" path="title">
|
||||
<n-input placeholder="请输入消息标题" v-model:value="formParams.title" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="接收人" path="receiver" v-if="formParams.type === 3">
|
||||
<n-select
|
||||
multiple
|
||||
:options="options"
|
||||
:render-label="renderLabel"
|
||||
:render-tag="renderMultipleSelectTag"
|
||||
v-model:value="formParams.receiver"
|
||||
filterable
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="消息内容" path="content">
|
||||
<template v-if="formParams.type === 1">
|
||||
<n-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 30 }"
|
||||
placeholder="请输入通知内容"
|
||||
v-model:value="formParams.content"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Editor style="height: 450px" v-model:value="formParams.content" />
|
||||
</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-gi>
|
||||
<n-form-item label="标签" path="tag">
|
||||
<n-select
|
||||
clearable
|
||||
placeholder="可以不填"
|
||||
:render-tag="renderTag"
|
||||
v-model:value="formParams.tag"
|
||||
:options="dict.getOptionUnRef('noticeTagOptions')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input-number style="width: 100%" v-model:value="formParams.sort" clearable />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="formParams.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in statusOptions"
|
||||
:key="status.value"
|
||||
:value="status.value"
|
||||
:label="status.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="备注" path="remark">
|
||||
<n-input
|
||||
type="textarea"
|
||||
placeholder="请输入备注,没有可以不填"
|
||||
v-model:value="formParams.remark"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="() => (showModal = false)">取消</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">立即发送</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</n-card>
|
||||
<Edit ref="editRef" @reload-table="reloadTable" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -198,117 +97,25 @@
|
||||
import { computed, h, onMounted, reactive, ref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
import {
|
||||
Delete,
|
||||
EditNotify,
|
||||
EditLetter,
|
||||
EditNotice,
|
||||
List,
|
||||
MaxSort,
|
||||
Status,
|
||||
} from '@/api/apply/notice';
|
||||
import { columns, loadOptions } from './columns';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
import { Delete, List, Status } from '@/api/apply/notice';
|
||||
import { BellOutlined, DeleteOutlined, NotificationOutlined, SendOutlined } from '@vicons/antd';
|
||||
import { statusOptions } from '@/enums/optionsiEnum';
|
||||
import { personOption, renderLabel, renderMultipleSelectTag } from '@/enums/systemMessageEnum';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
import { renderTag } from '@/utils';
|
||||
import Editor from '@/components/Editor/editor.vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { GetMemberOption } from '@/api/org/user';
|
||||
import { adaTableScrollX } from '@/utils/hotgo';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
|
||||
const dict = useDictStore();
|
||||
const rules = {
|
||||
title: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入消息标题',
|
||||
},
|
||||
};
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'type',
|
||||
component: 'NSelect',
|
||||
label: '消息类型',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择消息类型',
|
||||
options: dict.getOption('noticeTypeOptions'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'title',
|
||||
component: 'NInput',
|
||||
label: '消息标题',
|
||||
componentProps: {
|
||||
placeholder: '请输入消息标题',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入消息标题', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'content',
|
||||
component: 'NInput',
|
||||
label: '消息内容',
|
||||
componentProps: {
|
||||
placeholder: '请输入消息内容关键词',
|
||||
showButton: false,
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '状态',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择类型',
|
||||
options: dict.getOption('sys_normal_disable'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
import { columns } from './columns';
|
||||
import { schemas, loadOptions } from './model';
|
||||
import Edit from './edit.vue';
|
||||
|
||||
const { hasPermission } = usePermission();
|
||||
const message = useMessage();
|
||||
const dict = useDictStore();
|
||||
const actionRef = ref();
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref<any>({});
|
||||
const formRef = ref<any>({});
|
||||
const editRef = ref();
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
const options = ref<personOption[]>();
|
||||
const dialogWidth = computed(() => {
|
||||
return adaModalWidth();
|
||||
});
|
||||
|
||||
const resetFormParams = {
|
||||
id: 0,
|
||||
title: '',
|
||||
type: 1,
|
||||
tag: 0,
|
||||
content: '',
|
||||
receiver: null,
|
||||
remark: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
};
|
||||
let formParams = ref<any>(cloneDeep(resetFormParams));
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 200,
|
||||
@@ -351,6 +158,10 @@
|
||||
},
|
||||
});
|
||||
|
||||
const scrollX = computed(() => {
|
||||
return adaTableScrollX(columns, actionColumn.width);
|
||||
});
|
||||
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 80,
|
||||
@@ -358,12 +169,7 @@
|
||||
});
|
||||
|
||||
function addTable(type) {
|
||||
showModal.value = true;
|
||||
formParams.value = cloneDeep(resetFormParams);
|
||||
formParams.value.type = type;
|
||||
MaxSort().then((res) => {
|
||||
formParams.value.sort = res.sort;
|
||||
});
|
||||
editRef.value.openModal(null, type);
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
@@ -379,52 +185,8 @@
|
||||
actionRef.value.reload();
|
||||
}
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
switch (formParams.value.type) {
|
||||
case 1:
|
||||
EditNotify(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
EditNotice(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 3:
|
||||
EditLetter(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
message.error('公告类型不支持');
|
||||
}
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
showModal.value = true;
|
||||
formParams.value = cloneDeep(record);
|
||||
editRef.value.openModal(record, record.type);
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
@@ -474,13 +236,8 @@
|
||||
});
|
||||
}
|
||||
|
||||
async function getMemberOption() {
|
||||
options.value = await GetMemberOption();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
onMounted(() => {
|
||||
loadOptions();
|
||||
await getMemberOption();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
113
web/src/views/apply/notice/model.ts
Normal file
113
web/src/views/apply/notice/model.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
|
||||
const dict = useDictStore();
|
||||
|
||||
export class State {
|
||||
id: number;
|
||||
title: string;
|
||||
type: number;
|
||||
tag: number = 1;
|
||||
content: string;
|
||||
receiver: number[];
|
||||
remark: string;
|
||||
sort: number;
|
||||
status: number = 1;
|
||||
createdBy: number;
|
||||
updatedBy: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
readCount: number;
|
||||
receiverGroup: Receiver[];
|
||||
|
||||
constructor(state?: Partial<State>) {
|
||||
if (state) {
|
||||
Object.assign(this, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Receiver {
|
||||
name: string;
|
||||
src: string;
|
||||
}
|
||||
|
||||
export function newState(state: State | Record<string, any> | null): State {
|
||||
if (state !== null) {
|
||||
if (state instanceof State) {
|
||||
return cloneDeep(state);
|
||||
}
|
||||
return new State(state);
|
||||
}
|
||||
return new State();
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
export const rules = {
|
||||
title: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入消息标题',
|
||||
},
|
||||
};
|
||||
|
||||
// 表格搜索表单
|
||||
export const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'type',
|
||||
component: 'NSelect',
|
||||
label: '消息类型',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择消息类型',
|
||||
options: dict.getOption('noticeTypeOptions'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'title',
|
||||
component: 'NInput',
|
||||
label: '消息标题',
|
||||
componentProps: {
|
||||
placeholder: '请输入消息标题',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入消息标题', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'content',
|
||||
component: 'NInput',
|
||||
label: '消息内容',
|
||||
componentProps: {
|
||||
placeholder: '请输入消息内容关键词',
|
||||
showButton: false,
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '状态',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择类型',
|
||||
options: dict.getOption('sys_normal_disable'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// 加载字典数据选项
|
||||
export function loadOptions() {
|
||||
dict.loadOptions(['sys_normal_disable']);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { h } from 'vue';
|
||||
import { NTag } from 'naive-ui';
|
||||
import { renderPopoverMemberSumma } from '@/utils';
|
||||
|
||||
const msgMap = {
|
||||
1: '处理中',
|
||||
@@ -29,20 +30,12 @@ export const columns = [
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
key: 'memberUser',
|
||||
render(row) {
|
||||
return row.memberUser;
|
||||
},
|
||||
title: '申请人',
|
||||
key: 'memberId',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'memberName',
|
||||
render(row) {
|
||||
return row.memberName;
|
||||
return renderPopoverMemberSumma(row.memberBySumma);
|
||||
},
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '提现金额',
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
</n-carousel>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="提现状态" path="status">
|
||||
<n-form-item label="变更提现状态" path="status">
|
||||
<n-radio-group v-model:value="paymentParams.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in statusOptions"
|
||||
@@ -187,16 +187,15 @@
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'memberId',
|
||||
component: 'NInput',
|
||||
label: '管理员ID',
|
||||
field: 'complexMemberId',
|
||||
component: 'ComplexMemberPicker',
|
||||
label: '申请人',
|
||||
componentProps: {
|
||||
placeholder: '请输入管理员ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
placeholder: '请选择申请人',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入管理员ID', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'ip',
|
||||
|
||||
@@ -2,18 +2,18 @@ import { ref } from 'vue';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { defRangeShortcuts } from '@/utils/dateUtil';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
import { renderOptionTag } from '@/utils';
|
||||
import { renderOptionTag, renderPopoverMemberSumma } from '@/utils';
|
||||
|
||||
const dict = useDictStore();
|
||||
|
||||
export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'memberId',
|
||||
component: 'NInput',
|
||||
label: '管理员ID',
|
||||
field: 'complexMemberId',
|
||||
component: 'ComplexMemberPicker',
|
||||
label: '选择用户',
|
||||
componentProps: {
|
||||
placeholder: '请输入管理员ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
placeholder: '请选择用户',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
@@ -21,10 +21,10 @@ export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'creditGroup',
|
||||
component: 'NSelect',
|
||||
label: '组别',
|
||||
label: '变动组别',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择变动的组别',
|
||||
placeholder: '请选择变动组别',
|
||||
options: dict.getOption('creditGroup'),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
@@ -86,9 +86,12 @@ export const columns = [
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '管理员ID',
|
||||
title: '用户',
|
||||
key: 'memberId',
|
||||
width: 100,
|
||||
render(row) {
|
||||
return renderPopoverMemberSumma(row.memberBySumma);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '变动类型',
|
||||
@@ -99,7 +102,7 @@ export const columns = [
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '组别',
|
||||
title: '变动组别',
|
||||
key: 'creditGroup',
|
||||
render(row) {
|
||||
return renderOptionTag('creditGroup', row.creditGroup);
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
}
|
||||
|
||||
const emit = defineEmits(['reloadTable', 'updateShowModal']);
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showModal: false,
|
||||
formParams: () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { cloneDeep } from 'lodash-es';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { defRangeShortcuts } from '@/utils/dateUtil';
|
||||
import { useDictStore } from '@/store/modules/dict';
|
||||
import { renderOptionTag } from '@/utils';
|
||||
import { MemberSumma, renderOptionTag, renderPopoverMemberSumma } from '@/utils';
|
||||
|
||||
export interface State {
|
||||
id: number;
|
||||
@@ -20,6 +20,7 @@ export interface State {
|
||||
refundReason: string;
|
||||
rejectRefundReason: string;
|
||||
payLogPayType: string;
|
||||
memberBySumma?: null | MemberSumma;
|
||||
}
|
||||
|
||||
export const defaultState = {
|
||||
@@ -51,12 +52,12 @@ export const rules = {};
|
||||
|
||||
export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'memberId',
|
||||
component: 'NInput',
|
||||
label: '管理员ID',
|
||||
field: 'complexMemberId',
|
||||
component: 'ComplexMemberPicker',
|
||||
label: '下单用户',
|
||||
componentProps: {
|
||||
placeholder: '请输入管理员ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
placeholder: '请选择下单用户',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
@@ -99,25 +100,18 @@ export const schemas = ref<FormSchema[]>([
|
||||
]);
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: '订单ID',
|
||||
key: 'id',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '管理员ID',
|
||||
key: 'memberId',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '业务订单号',
|
||||
key: 'orderSn',
|
||||
width: 260,
|
||||
width: 220,
|
||||
},
|
||||
{
|
||||
title: '商户订单号',
|
||||
key: 'payLogOutTradeNo',
|
||||
width: 260,
|
||||
title: '下单用户',
|
||||
key: 'memberId',
|
||||
width: 100,
|
||||
render(row: State) {
|
||||
return renderPopoverMemberSumma(row.memberBySumma);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '支付方式',
|
||||
@@ -143,6 +137,11 @@ export const columns = [
|
||||
},
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '商户订单号',
|
||||
key: 'payLogOutTradeNo',
|
||||
width: 220,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createdAt',
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { h } from 'vue';
|
||||
import { NTag, NEllipsis, NSpace } from 'naive-ui';
|
||||
import { timestampToTime } from '@/utils/dateUtil';
|
||||
import { renderHtmlTooltip } from '@/utils';
|
||||
import Column from './components/Column.vue';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
@@ -14,49 +12,10 @@ export const columns = [
|
||||
key: 'name',
|
||||
width: 180,
|
||||
render(row) {
|
||||
const operator =
|
||||
row.memberId === 0 ? row.memberName : row.memberName + '(' + row.memberId + ')';
|
||||
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: {
|
||||
maxWidth: '180px',
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
NSpace,
|
||||
{ vertical: true },
|
||||
{
|
||||
default: () => [
|
||||
h('div', {
|
||||
innerHTML: '<div><p>' + operator + '</p></div>',
|
||||
}),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>IP:' + row.ip + '</p></div>',
|
||||
}),
|
||||
row.cityLabel != ''
|
||||
? h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: 'primary',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.cityLabel,
|
||||
}
|
||||
)
|
||||
: null,
|
||||
],
|
||||
}
|
||||
),
|
||||
}
|
||||
);
|
||||
return h(Column, {
|
||||
state: row,
|
||||
column: 'visitor',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -64,43 +23,10 @@ export const columns = [
|
||||
key: 'name',
|
||||
width: 260,
|
||||
render(row) {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: {
|
||||
maxWidth: '260px',
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
NSpace,
|
||||
{ vertical: true },
|
||||
{
|
||||
default: () => [
|
||||
h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.method,
|
||||
}
|
||||
),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>接口:' + row.url + '</p></div>',
|
||||
}),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>名称:' + row.tags + ' / ' + row.summary + '</p></div>',
|
||||
}),
|
||||
],
|
||||
}
|
||||
),
|
||||
}
|
||||
);
|
||||
return h(Column, {
|
||||
state: row,
|
||||
column: 'request',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -108,39 +34,10 @@ export const columns = [
|
||||
key: 'name',
|
||||
width: 260,
|
||||
render(row) {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: {
|
||||
maxWidth: '260px',
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
NSpace,
|
||||
{ vertical: true },
|
||||
{
|
||||
default: () => [
|
||||
renderHtmlTooltip(
|
||||
'<div style="width: 240px"><p>状态码:' +
|
||||
row.errorMsg +
|
||||
'(' +
|
||||
row.errorCode +
|
||||
')' +
|
||||
'</p></div>'
|
||||
),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>处理耗时:' + row.takeUpTime + 'ms</p></div>',
|
||||
}),
|
||||
h('div', {
|
||||
innerHTML: '<div><p>响应时间:' + timestampToTime(row.timestamp) + '</p></div>',
|
||||
}),
|
||||
],
|
||||
}
|
||||
),
|
||||
}
|
||||
);
|
||||
return h(Column, {
|
||||
state: row,
|
||||
column: 'response',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
77
web/src/views/log/log/components/Column.vue
Normal file
77
web/src/views/log/log/components/Column.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<template v-if="column === 'visitor'">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row mb-1">
|
||||
<div class="text">
|
||||
{{
|
||||
state.memberId === 0
|
||||
? state.memberName
|
||||
: state.memberName + '(' + state.memberId + ')'
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div>访问IP:</div>
|
||||
<div class="text">{{ state.ip }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text">
|
||||
{{ state.cityLabel !== '' ? state.cityLabel : '局域网' }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="column === 'request'">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row">
|
||||
<div class="text mr-1 mb-1">
|
||||
<n-button :type="state.method === 'GET' ? 'tertiary' : 'primary'" size="tiny">
|
||||
{{ state.method }}
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="text">{{ state.url }}</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="text">{{ state.tags }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ state.summary }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="column === 'response'">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row">
|
||||
<div class="text mr-1 mb-1">
|
||||
<n-button v-if="state.errorCode === 0" type="tertiary" size="tiny">
|
||||
{{ state.errorMsg }}
|
||||
</n-button>
|
||||
<n-button v-else type="error" size="tiny">
|
||||
{{ state.errorCode }} → {{ state.errorMsg }}
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="text">处理耗时:{{ state.takeUpTime }}ms</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="text">响应时间:{{ timestampToTime(state.timestamp) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { basicProps } from './props';
|
||||
import { timestampToTime } from '@/utils/dateUtil';
|
||||
|
||||
const props = defineProps(basicProps);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.text {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
12
web/src/views/log/log/components/props.ts
Normal file
12
web/src/views/log/log/components/props.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { State } from '@/views/log/log/model';
|
||||
|
||||
export const basicProps = {
|
||||
state: {
|
||||
type: State,
|
||||
default: null,
|
||||
},
|
||||
column: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
};
|
||||
@@ -53,7 +53,6 @@
|
||||
const dialog = useDialog();
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
|
||||
const router = useRouter();
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
|
||||
@@ -48,16 +48,15 @@ export const schemas = ref<FormSchema[]>([
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'memberId',
|
||||
component: 'NInput',
|
||||
field: 'complexMemberId',
|
||||
component: 'ComplexMemberPicker',
|
||||
label: '操作人',
|
||||
componentProps: {
|
||||
placeholder: '请输入操作人ID',
|
||||
placeholder: '请选择操作人',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'url',
|
||||
|
||||
@@ -129,18 +129,12 @@
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请填写API路径地址,可同时作用于server端接口鉴权和web端细粒度权限。一次添加多个权限用,分割
|
||||
请填写API路径地址,可同时作用于server端接口鉴权和web端细粒度权限
|
||||
</n-tooltip>
|
||||
分配权限
|
||||
</template>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<!-- <n-gi>-->
|
||||
<!-- <n-form-item label="权限名称" path="permissionName">-->
|
||||
<!-- <n-input placeholder="权限名称" v-model:value="formParams.permissionName" />-->
|
||||
<!-- <template #feedback>分配权限存在多个时,权限名称只绑定到第一个权限</template>-->
|
||||
<!-- </n-form-item>-->
|
||||
<!-- </n-gi>-->
|
||||
</n-grid>
|
||||
|
||||
<n-grid cols="2 300:1 600:2">
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
ref="formRef"
|
||||
label-placement="top"
|
||||
>
|
||||
<n-divider title-placement="left">基础设置</n-divider>
|
||||
<n-form-item label="默认驱动" path="uploadDrive">
|
||||
<n-select
|
||||
placeholder="默认驱动"
|
||||
@@ -16,46 +15,16 @@
|
||||
v-model:value="formValue.uploadDrive"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="图片大小限制" path="uploadImageSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadImageSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="文件大小限制" path="uploadFileSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadFileSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="图片类型限制" path="uploadImageType">
|
||||
<n-input v-model:value="formValue.uploadImageType" placeholder="" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="文件类型限制" path="uploadFileType">
|
||||
<n-input v-model:value="formValue.uploadFileType" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-tabs type="card" size="small" v-model:value="tabName">
|
||||
<n-tab-pane name="local">
|
||||
<template #tab> 本地存储</template>
|
||||
<n-divider title-placement="left">本地存储</n-divider>
|
||||
<n-tab-pane name="local" tab="本地存储">
|
||||
<n-form-item label="本地存储路径" path="uploadLocalPath">
|
||||
<n-input v-model:value="formValue.uploadLocalPath" placeholder="" />
|
||||
<template #feedback>填对外访问的相对路径</template>
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="oss">
|
||||
<template #tab> 阿里云OSS存储</template>
|
||||
<n-divider title-placement="left">阿里云OSS存储</n-divider>
|
||||
<n-tab-pane name="oss" tab="阿里云OSS">
|
||||
<n-form-item label="AccessKey ID" path="uploadOssSecretId">
|
||||
<n-input
|
||||
type="password"
|
||||
@@ -102,9 +71,7 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="cos">
|
||||
<template #tab> 腾讯云COS存储</template>
|
||||
<n-divider title-placement="left">腾讯云COS存储</n-divider>
|
||||
<n-tab-pane name="cos" tab="腾讯云COS">
|
||||
<n-form-item label="APPID" path="uploadCosSecretId">
|
||||
<n-input v-model:value="formValue.uploadCosSecretId" />
|
||||
<template #feedback>
|
||||
@@ -138,9 +105,7 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="qiniu">
|
||||
<template #tab> 七牛云对象存储</template>
|
||||
<n-divider title-placement="left">七牛云对象存储</n-divider>
|
||||
<n-tab-pane name="qiniu" tab="七牛云对象存储">
|
||||
<n-form-item label="AccessKey" path="uploadQiNiuAccessKey">
|
||||
<n-input
|
||||
type="password"
|
||||
@@ -183,9 +148,7 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="ucloud">
|
||||
<template #tab> ucloud对象存储</template>
|
||||
<n-divider title-placement="left">ucloud对象存储</n-divider>
|
||||
<n-tab-pane name="ucloud" tab="UC对象存储">
|
||||
<n-form-item label="公钥" path="uploadUCloudPublicKey">
|
||||
<n-input
|
||||
type="password"
|
||||
@@ -237,9 +200,7 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane name="minio">
|
||||
<template #tab> minio对象存储</template>
|
||||
<n-divider title-placement="left">minio对象存储</n-divider>
|
||||
<n-tab-pane name="minio" tab="MinIO">
|
||||
<n-form-item label="AccessKey ID" path="uploadMinioAccessKey">
|
||||
<n-input
|
||||
type="password"
|
||||
@@ -295,6 +256,45 @@
|
||||
</n-form-item>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
<n-grid x-gap="24" :cols="4" class="mt-4">
|
||||
<n-gi>
|
||||
<n-form-item label="图片大小限制" path="uploadImageSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadImageSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi :span="3">
|
||||
<n-form-item label="图片类型限制" path="uploadImageType">
|
||||
<n-input v-model:value="formValue.uploadImageType" placeholder="" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="4">
|
||||
<n-gi>
|
||||
<n-form-item label="文件大小限制" path="uploadFileSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadFileSize"
|
||||
>
|
||||
<template #suffix> MB</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi :span="3">
|
||||
<n-form-item label="文件类型限制" path="uploadFileType">
|
||||
<n-input v-model:value="formValue.uploadFileType" placeholder="" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
|
||||
Reference in New Issue
Block a user