Merge branch 'ui' of 172.28.1.6:yangjian/chatgpt-plus into ui

This commit is contained in:
廖彦棋 2024-03-07 18:03:08 +08:00
commit 9796a841d9
15 changed files with 1104 additions and 42 deletions

View File

@ -18,7 +18,7 @@ export default function (
const popupProps = (arg: Arg[], getExposed) => { const popupProps = (arg: Arg[], getExposed) => {
return { return {
width: 700, width: 800,
onBeforeOk: async () => { onBeforeOk: async () => {
const exposed = getExposed(); const exposed = getExposed();
const validateRes = await exposed?.formRef.value.validate(); const validateRes = await exposed?.formRef.value.validate();

View File

@ -4,80 +4,112 @@ import {
IconOrderedList, IconOrderedList,
IconCalendar, IconCalendar,
IconSettings, IconSettings,
IconUserGroup,
IconLock,
IconCodepen,
IconWechatpay,
} from "@arco-design/web-vue/es/icon"; } from "@arco-design/web-vue/es/icon";
const menu = [ const menu = [
{ {
path: '/dashboard', path: "/dashboard",
name: 'Dashboard', name: "Dashboard",
meta: { meta: {
title: "仪表盘", title: "仪表盘",
icon: IconDashboard icon: IconDashboard,
}, },
component: () => import('@/views/DashboardView.vue') component: () => import("@/views/DashboardView.vue"),
}, },
{ {
path: '/user', path: "/user",
name: 'User', name: "User",
meta: { meta: {
title: "用户管理", title: "用户管理",
icon: IconUser, icon: IconUser,
}, },
component: () => import('@/views/User/UserContainer.vue') component: () => import("@/views/User/UserContainer.vue"),
}, },
{ {
path: '/order', path: "/Role",
name: 'Order', name: "Role",
meta: {
title: "角色管理",
icon: IconUserGroup,
},
component: () => import("@/views/Role/RoleContainer.vue"),
},
{
path: "/ChatModel",
name: "ChatModel",
meta: {
title: "语言模型",
icon: IconCodepen,
},
component: () => import("@/views/ChatModel/ChatModelContainer.vue"),
},
{
path: "/Product",
name: "Product",
meta: {
title: "充值产品",
icon: IconWechatpay,
},
component: () => import("@/views/Product/ProductContainer.vue"),
},
{
path: "/ApiKey",
name: "ApiKey",
meta: {
title: "APIKEY",
icon: IconLock,
},
component: () => import("@/views/ApiKey/ApiKeyContainer.vue"),
},
{
path: "/order",
name: "Order",
meta: { meta: {
title: "充值订单", title: "充值订单",
icon: IconOrderedList, icon: IconOrderedList,
}, },
component: () => import('@/views/Order/OrderContainer.vue') component: () => import("@/views/Order/OrderContainer.vue"),
}, },
{ {
path: '/reward', path: "/reward",
name: 'Reward', name: "Reward",
meta: { meta: {
title: "众筹管理", title: "众筹管理",
icon: IconCalendar, icon: IconCalendar,
}, },
component: () => import('@/views/Reward/RewardContainer.vue') component: () => import("@/views/Reward/RewardContainer.vue"),
}, },
{ {
path: '/functions', path: "/chats",
name: 'Functions', name: "Chats",
meta: {
title: "函数管理",
icon: IconCalendar,
},
component: () => import('@/views/Functions/FunctionsContainer.vue')
},
{
path: '/chats',
name: 'Chats',
meta: { meta: {
title: "对话管理", title: "对话管理",
icon: IconCalendar, icon: IconCalendar,
}, },
component: () => import('@/views/Chats/ChatsContainer.vue') component: () => import("@/views/Chats/ChatsContainer.vue"),
}, },
{ {
path: '/system', path: "/system",
name: 'System', name: "System",
meta: { meta: {
title: "系统设置", title: "系统设置",
icon: IconSettings, icon: IconSettings,
}, },
component: () => import('@/views/System/SystemContainer.vue') component: () => import("@/views/System/SystemContainer.vue"),
}, },
{ {
path: '/loginLog', path: "/loginLog",
name: 'LoginLog', name: "LoginLog",
meta: { meta: {
title: "登录日志", title: "登录日志",
icon: IconCalendar, icon: IconCalendar,
}, },
component: () => import('@/views/LoginLog.vue') component: () => import("@/views/LoginLog.vue"),
}, },
]; ];

View File

@ -1,4 +1,120 @@
<script lang="ts" setup></script> <script lang="ts" setup>
import { getList, save, deleting, setStatus } from "./api";
import { ref } from "vue";
import ApiKeyForm from "./ApiKeyForm.vue";
import useCustomFormPopup from "@/composables/useCustomFormPopup";
import { Message } from "@arco-design/web-vue";
import SimpleTable from "@/components/SimpleTable/SimpleTable.vue";
import { dateFormat } from "@gpt-vue/packages/utils";
// table
const columns = [
{
title: "所属平台",
dataIndex: "platform",
},
{
title: "名称",
dataIndex: "name",
},
{
title: "key",
dataIndex: "value",
},
{
title: "用途",
dataIndex: "type",
},
{
title: "使用代理",
dataIndex: "use_proxy",
slotName: "proxy",
},
{
title: "最后使用时间",
dataIndex: "last_used_at",
render: ({ record }) => {
return dateFormat(record.last_used_at);
},
},
{
title: "启用状态",
dataIndex: "enabled",
slotName: "status",
},
{
title: "操作",
slotName: "action",
},
];
//
const tableData = ref([]);
const getData = () => {
getList().then(({ code, data }) => {
if (code === 0) {
tableData.value = data;
}
});
};
getData();
//
const popup = useCustomFormPopup(ApiKeyForm, save);
//
const handleDelete = ({ id }, reload) => {
deleting(id).then(({ code }) => {
if (code === 0) {
Message.success("操作成功");
reload();
}
});
};
//
const handleStatusChange = ({ filed, value, record, reload }) => {
setStatus({
id: record.id,
value,
filed,
}).then(({ code }) => {
if (code === 0) {
Message.success("操作成功");
reload();
}
});
};
</script>
<template> <template>
<div></div> <SimpleTable :columns="columns" :request="getList">
<template #action="{ record, reload }">
<a-link @click="popup({ record, reload })">编辑</a-link>
<a-popconfirm content="确定删除?" @ok="handleDelete(record, reload)">
<a-link>删除</a-link>
</a-popconfirm>
</template>
<template #header="{ reload }">
<a-button @click="popup({ reload })" size="small"><icon-plus />新增</a-button>
</template>
<template #status="{ record, reload }">
<a-switch
v-model="record.enabled"
@change="
(value) => {
handleStatusChange({ filed: 'enabled', value, record, reload });
}
"
/>
</template>
<template #proxy="{ record, reload }">
<a-switch
v-model="record.use_proxy"
@change="
(value) => {
handleStatusChange({ filed: 'use_proxy', value, record, reload });
}
"
/>
</template>
</SimpleTable>
</template> </template>

View File

@ -0,0 +1,97 @@
<template>
<a-form ref="formRef" :model="form" :style="{ width: '600px' }" @submit="handleSubmit">
<a-form-item
field="platform"
label="所属平台"
:rules="[{ required: true, message: '请输入所属平台' }]"
:validate-trigger="['change', 'input']"
>
<a-input v-model="form.platform" placeholder="请输入所属平台" />
</a-form-item>
<a-form-item
field="name"
label="名称"
:rules="[{ required: true, message: '请输入名称' }]"
:validate-trigger="['change', 'input']"
showable
>
<a-input v-model="form.name" placeholder="请输入名称" />
</a-form-item>
<a-form-item
field="type"
label="用途"
:rules="[{ required: true, message: '请输入用途' }]"
:validate-trigger="['change', 'input']"
>
<a-select v-model="form.type" placeholder="请输入用途" :options="typeOPtions"> </a-select>
</a-form-item>
<a-form-item
field="value"
label="API KEY"
:rules="[{ required: true, message: '请输入API KEY' }]"
:validate-trigger="['change', 'input']"
>
<a-input v-model="form.value" placeholder="请输入API KEY" />
</a-form-item>
<a-form-item
field="api_url"
label="API URL"
:rules="[{ required: true, message: '请输入API URL' }]"
:validate-trigger="['change', 'input']"
>
<a-input v-model="form.api_url" placeholder="请输入API URL" />
</a-form-item>
<a-form-item field="use_proxy" label="使用代理">
<a-switch v-model="form.use_proxy" />
</a-form-item>
<a-form-item field="enable" label="启用状态">
<a-switch v-model="form.enable" />
</a-form-item>
</a-form>
</template>
<script setup>
import { ref, defineExpose, defineProps } from "vue";
const props = defineProps({
data: {},
});
const formRef = ref();
const form = ref({});
if (props.data?.id) {
form.value = Object.assign({}, props.data);
}
defineExpose({
formRef,
form,
});
const typeOPtions = [
{
label: "聊天",
value: "chart",
},
{
label: "绘图",
value: "img",
},
];
</script>
<style lang="less" scoped>
.content-title {
display: flex;
justify-content: space-between;
align-items: center;
width: 350px;
}
.content-cell {
display: flex;
align-items: center;
width: 350px;
svg {
margin-left: 10px;
}
}
</style>

View File

@ -0,0 +1,29 @@
import http from "@/http/config";
export const getList = (params?: Record<string, unknown>) => {
return http({
url: "/api/admin/apikey/list",
method: "get",
params,
});
};
export const save = (data?: Record<string, unknown>) => {
return http({
url: "/api/admin/apikey/save",
method: "post",
data,
});
};
export const deleting = (id: string | number) => {
return http({
url: `/api/admin/apikey/remove?id=${id}`,
method: "get",
});
};
export const setStatus = (data) => {
return http({
url: `/api/admin/apikey/set`,
method: "post",
data,
});
};

View File

@ -1,4 +1,120 @@
<script lang="ts" setup></script> <script lang="ts" setup>
import { getList, save, deleting, setStatus } from "./api";
import { ref } from "vue";
import ChatModelForm from "./ChatModelForm.vue";
import useCustomFormPopup from "@/composables/useCustomFormPopup";
import { Message } from "@arco-design/web-vue";
import SimpleTable from "@/components/SimpleTable/SimpleTable.vue";
import { dateFormat } from "@gpt-vue/packages/utils";
// table
const columns = [
{
title: "所属平台",
dataIndex: "platform",
},
{
title: "模型名称",
dataIndex: "name",
},
{
title: "模型值",
dataIndex: "value",
},
{
title: "对话权重",
dataIndex: "weight",
},
{
title: "启用状态",
dataIndex: "enabled",
slotName: "status",
},
{
title: "开放状态",
dataIndex: "open",
slotName: "open",
},
{
title: "创建时间",
dataIndex: "created_at",
render: ({ record }) => {
return dateFormat(record.created_at);
},
},
{
title: "操作",
slotName: "action",
},
];
//
const tableData = ref([]);
const getData = () => {
getList().then(({ code, data }) => {
if (code === 0) {
tableData.value = data;
}
});
};
getData();
//
const popup = useCustomFormPopup(ChatModelForm, save);
//
const handleDelete = ({ id }, reload) => {
deleting(id).then(({ code }) => {
if (code === 0) {
Message.success("操作成功");
reload();
}
});
};
//
const handleStatusChange = ({ filed, value, record, reload }) => {
setStatus({
id: record.id,
value,
filed,
}).then(({ code }) => {
if (code === 0) {
Message.success("操作成功");
reload();
}
});
};
</script>
<template> <template>
<div></div> <SimpleTable :columns="columns" :request="getList">
<template #action="{ record, reload }">
<a-link @click="popup({ record, reload })">编辑</a-link>
<a-popconfirm content="确定删除?" @ok="handleDelete(record, reload)">
<a-link>删除</a-link>
</a-popconfirm>
</template>
<template #header="{ reload }">
<a-button @click="popup({ reload })" size="small"><icon-plus />新增</a-button>
</template>
<template #status="{ record, reload }">
<a-switch
v-model="record.enabled"
@change="
(value) => {
handleStatusChange({ filed: 'enabled', value, record, reload });
}
"
/>
</template>
<template #open="{ record, reload }">
<a-switch
v-model="record.open"
@change="
(value) => {
handleStatusChange({ filed: 'open', value, record, reload });
}
"
/>
</template>
</SimpleTable>
</template> </template>

View File

@ -0,0 +1,91 @@
<template>
<a-form ref="formRef" :model="form" :style="{ width: '600px' }" @submit="handleSubmit">
<a-form-item
field="platform"
label="所属平台"
:rules="[{ required: true, message: '请输入所属平台' }]"
:validate-trigger="['change', 'input']"
>
<a-input v-model="form.platform" placeholder="请输入所属平台" />
</a-form-item>
<a-form-item
field="name"
label="名称"
:rules="[{ required: true, message: '请输入名称' }]"
:validate-trigger="['change', 'input']"
showable
>
<a-input v-model="form.name" placeholder="请输入名称" />
</a-form-item>
<a-form-item
field="value"
label="模型值"
:rules="[{ required: true, message: '请输入名称' }]"
:validate-trigger="['change', 'input']"
showable
>
<a-input v-model="form.value" placeholder="请输入名称" />
</a-form-item>
<a-form-item
field="weight"
label="对话权重"
:rules="[{ required: true, message: '请输入对话权重' }]"
:validate-trigger="['change', 'input']"
showable
>
<a-input-number v-model="form.weight" placeholder="请输入对话权重" />
</a-form-item>
<a-form-item field="open" label="开放状态代理">
<a-switch v-model="form.open" />
</a-form-item>
<a-form-item field="enabled" label="启用状态">
<a-switch v-model="form.enabled" />
</a-form-item>
</a-form>
</template>
<script setup>
import { ref, defineExpose, defineProps } from "vue";
const props = defineProps({
data: {},
});
const formRef = ref();
const form = ref({});
if (props.data?.id) {
form.value = Object.assign({}, props.data);
}
defineExpose({
formRef,
form,
});
const typeOPtions = [
{
label: "聊天",
value: "chart",
},
{
label: "绘图",
value: "img",
},
];
</script>
<style lang="less" scoped>
.content-title {
display: flex;
justify-content: space-between;
align-items: center;
width: 350px;
}
.content-cell {
display: flex;
align-items: center;
width: 350px;
svg {
margin-left: 10px;
}
}
</style>

View File

@ -0,0 +1,29 @@
import http from "@/http/config";
export const getList = (params?: Record<string, unknown>) => {
return http({
url: "/api/admin/model/list",
method: "get",
params,
});
};
export const save = (data?: Record<string, unknown>) => {
return http({
url: "/api/admin/model/save",
method: "post",
data,
});
};
export const deleting = (id: string | number) => {
return http({
url: `/api/admin/model/remove?id=${id}`,
method: "get",
});
};
export const setStatus = (data) => {
return http({
url: `/api/admin/model/set`,
method: "post",
data,
});
};

View File

@ -1,4 +1,69 @@
<script lang="ts" setup></script> <script lang="ts" setup>
import http from "@/http/config";
import { ref } from "vue";
const dataSet = {
users: "今日新增用户",
chats: "今日新增对话",
tokens: "今日消耗 Tokens",
income: "今日入账",
};
const data = ref<Record<string, number>>({});
const getData = () => {
http({
url: "api/admin/dashboard/stats",
method: "get",
}).then((res) => {
data.value = res.data;
});
};
getData();
</script>
<template> <template>
<div></div> <div class="dashboard">
<div class="data-card" v-for="(value, key) in dataSet" :key="key">
<span :class="key" class="icon"><icon-user /></span>
<span class="count"
><a-statistic :extra="value" :value="data[key]" :precision="0"
/></span>
</div>
</div>
</template> </template>
<style lang="less" scoped>
.dashboard {
display: flex;
text-align: center;
.data-card {
display: flex;
flex: 0 0 25%;
padding: 0 10px;
box-sizing: border-box;
.icon {
display: inline-block;
font-size: 50px;
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
color: #fff;
}
.users {
background: #2d8cf0;
}
.chats {
background: #64d572;
}
.tokens {
background: #f25e43;
}
.income {
background: #f25e43;
}
.count {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>

View File

@ -1,4 +1,116 @@
<script lang="ts" setup></script> <script lang="ts" setup>
import { getList, save, deleting, setStatus } from "./api";
import { ref } from "vue";
import ProductForm from "./ProductForm.vue";
import useCustomFormPopup from "@/composables/useCustomFormPopup";
import { Message } from "@arco-design/web-vue";
import SimpleTable from "@/components/SimpleTable/SimpleTable.vue";
import { dateFormat } from "@gpt-vue/packages/utils";
// table
const columns = [
{
title: "产品名称",
dataIndex: "name",
},
{
title: "产品价格",
dataIndex: "price",
},
{
title: "优惠金额",
dataIndex: "discount",
},
{
title: "有效期(天)",
dataIndex: "days",
},
{
title: "对话次数",
dataIndex: "calls",
},
{
title: "绘图次数",
dataIndex: "img_calls",
},
{
title: "销量",
dataIndex: "sales",
},
{
title: "启用状态",
dataIndex: "enabled",
slotName: "status",
},
{
title: "更新时间",
dataIndex: "updated_at",
render: ({ record }) => {
return dateFormat(record.updated_at);
},
},
{
title: "操作",
slotName: "action",
},
];
//
const tableData = ref([]);
const getData = () => {
getList().then(({ code, data }) => {
if (code === 0) {
tableData.value = data;
}
});
};
getData();
//
const popup = useCustomFormPopup(ProductForm, save);
//
const handleDelete = ({ id }, reload) => {
deleting(id).then(({ code }) => {
if (code === 0) {
Message.success("操作成功");
reload();
}
});
};
//
const handleStatusChange = ({ value, record, reload }) => {
setStatus({
id: record.id,
enabled: value,
}).then(({ code }) => {
if (code === 0) {
Message.success("操作成功");
reload();
}
});
};
</script>
<template> <template>
<div></div> <SimpleTable :columns="columns" :request="getList">
<template #action="{ record, reload }">
<a-link @click="popup({ record, reload })">编辑</a-link>
<a-popconfirm content="确定删除?" @ok="handleDelete(record, reload)">
<a-link>删除</a-link>
</a-popconfirm>
</template>
<template #header="{ reload }">
<a-button @click="popup({ reload })" size="small"><icon-plus />新增</a-button>
</template>
<template #status="{ record, reload }">
<a-switch
v-model="record.enabled"
@change="
(value) => {
handleStatusChange({ value, record, reload });
}
"
/>
</template>
</SimpleTable>
</template> </template>

View File

@ -0,0 +1,87 @@
<template>
<a-form ref="formRef" :model="form" :style="{ width: '600px' }" @submit="handleSubmit">
<a-form-item
field="name"
label="产品名称"
:rules="[{ required: true, message: '请输入产品名称' }]"
:validate-trigger="['change', 'input']"
>
<a-input v-model="form.name" placeholder="请输入产品名称" />
</a-form-item>
<a-form-item
field="price"
label="产品价格"
:rules="[{ required: true, message: '请输入产品价格' }]"
:validate-trigger="['change', 'input']"
showable
>
<a-input-number v-model="form.price" placeholder="请输入产品价格" />
</a-form-item>
<a-form-item
field="discount"
label="优惠金额"
:rules="[{ required: true, message: '请输入优惠金额' }]"
:validate-trigger="['change', 'input']"
showable
>
<a-input-number v-model="form.discount" placeholder="请输入优惠金额" />
</a-form-item>
<a-form-item
field="days"
label="有效期(天)"
:rules="[{ required: true, message: '请输入有效期(天)' }]"
:validate-trigger="['change', 'input']"
showable
>
<a-input-number v-model="form.days" placeholder="请输入有效期(天)" />
</a-form-item>
<a-form-item field="calls" label="对话次数" :validate-trigger="['change', 'input']" showable>
<a-input-number v-model="form.calls" placeholder="请输入对话次数" />
</a-form-item>
<a-form-item
field="img_calls"
label="绘图次数"
:validate-trigger="['change', 'input']"
showable
>
<a-input-number v-model="form.img_calls" placeholder="请输入绘图次数" />
</a-form-item>
<a-form-item field="enabled" label="启用状态">
<a-switch v-model="form.enabled" />
</a-form-item>
</a-form>
</template>
<script setup>
import { ref, defineExpose, defineProps } from "vue";
const props = defineProps({
data: {},
});
const formRef = ref();
const form = ref({});
if (props.data?.id) {
form.value = Object.assign({}, props.data);
}
defineExpose({
formRef,
form,
});
</script>
<style lang="less" scoped>
.content-title {
display: flex;
justify-content: space-between;
align-items: center;
width: 350px;
}
.content-cell {
display: flex;
align-items: center;
width: 350px;
svg {
margin-left: 10px;
}
}
</style>

View File

@ -0,0 +1,29 @@
import http from "@/http/config";
export const getList = (params?: Record<string, unknown>) => {
return http({
url: "/api/admin/product/list",
method: "get",
params,
});
};
export const save = (data?: Record<string, unknown>) => {
return http({
url: "/api/admin/product/save",
method: "post",
data,
});
};
export const deleting = (id: string | number) => {
return http({
url: `/api/admin/product/remove?id=${id}`,
method: "get",
});
};
export const setStatus = (data) => {
return http({
url: `/api/admin/product/enable`,
method: "post",
data,
});
};

View File

@ -1,4 +1,118 @@
<script lang="ts" setup></script> <script lang="ts" setup>
import { getList, save, deleting, setStatus } from "./api";
import { reactive, ref } from "vue";
import RoleForm from "./RoleForm.vue";
import useCustomFormPopup from "@/composables/useCustomFormPopup";
import { Message } from "@arco-design/web-vue";
import SimpleTable from "@/components/SimpleTable/SimpleTable.vue";
// table
const columns = [
{
title: "角色名称",
dataIndex: "name",
},
{
title: "角色标识",
dataIndex: "key",
},
{
title: "启用状态",
dataIndex: "enable",
slotName: "status",
},
{
title: "角色图标",
dataIndex: "icon",
},
{
title: "打招呼信息",
dataIndex: "hello_msg",
},
{
title: "操作",
slotName: "action",
},
];
const expandable = reactive({
title: "",
width: 80,
});
//
const tableData = ref([]);
const getData = () => {
getList().then(({ code, data }) => {
if (code === 0) {
tableData.value = data;
}
});
};
getData();
//table
const expandColumns = [
{
dataIndex: "role",
title: "对话角色",
width: 120,
},
{
dataIndex: "content",
title: "对话内容",
},
];
//
const popup = useCustomFormPopup(RoleForm, save);
//
const handleDelete = ({ id }, reload) => {
deleting(id).then(({ code }) => {
if (code === 0) {
Message.success("操作成功");
reload();
}
});
};
//
const handleStatusChange = ({ value, record, reload }) => {
setStatus({
id: record.id,
value,
filed: "enable",
}).then(({ code }) => {
if (code === 0) {
Message.success("操作成功");
reload();
}
});
};
</script>
<template> <template>
<div></div> <SimpleTable :columns="columns" :request="getList" :expandable="expandable">
<template #expand-row="{ record }">
<a-table :columns="expandColumns" :data="record.context || []" :pagination="false"></a-table>
</template>
<template #action="{ record, reload }">
<a-link @click="popup({ record, reload })">编辑</a-link>
<a-popconfirm content="确定删除?" @ok="handleDelete(record, reload)">
<a-link>删除</a-link>
</a-popconfirm>
</template>
<template #header="{ reload }">
<a-button @click="popup({ reload })" size="small"><icon-plus />新增</a-button>
</template>
<template #status="{ record, reload }">
<a-switch
v-model="record.enable"
@change="
(value) => {
handleStatusChange({ value, record, reload });
}
"
/>
</template>
</SimpleTable>
</template> </template>

View File

@ -0,0 +1,116 @@
<template>
<a-form ref="formRef" :model="form" :style="{ width: '600px' }" @submit="handleSubmit">
<a-form-item
field="name"
label="角色名称"
:rules="[{ required: true, message: '请输入角色名称' }]"
:validate-trigger="['change', 'input']"
>
<a-input v-model="form.name" placeholder="请输入角色名称" />
</a-form-item>
<a-form-item
field="key"
label="角色标志"
:rules="[{ required: true, message: '请输入角色标志' }]"
:validate-trigger="['change', 'input']"
showable
>
<a-input v-model="form.key" placeholder="请输入角色标志" />
</a-form-item>
<a-form-item
field="icon"
label="角色图标"
:rules="[{ required: true, message: '请输入角色图标' }]"
:validate-trigger="['change', 'input']"
>
<a-input v-model="form.icon" placeholder="请输入角色图标" />
</a-form-item>
<a-form-item
field="hello_msg"
label="打招呼信息"
:rules="[{ required: true, message: '请输入打招呼信息' }]"
:validate-trigger="['change', 'input']"
>
<a-input v-model="form.hello_msg" placeholder="请输入打招呼信息" />
</a-form-item>
<a-form-item field="username" label="上下文信息" :validate-trigger="['change', 'input']">
<a-table :data="form.context || []" :pagination="false">
<template #columns>
<a-table-column title="对话角色">
<template #cell="{ record }">
<a-input v-model="record.role" />
</template>
</a-table-column>
<a-table-column width="350">
<template #title>
<div class="content-title">
<span>对话内容</span>
<a-button @click="addContext" type="primary">增加一行</a-button>
</div>
</template>
<template #cell="{ record }">
<div class="content-cell">
<a-input v-model="record.content" /><icon-minus-circle
@click="removeContext(record)"
/>
</div>
</template>
</a-table-column>
</template>
</a-table>
</a-form-item>
<a-form-item field="enable" label="启用状态">
<a-switch v-model="form.enable" />
</a-form-item>
</a-form>
</template>
<script setup>
import { ref, defineExpose, defineProps } from "vue";
const props = defineProps({
data: {},
});
const formRef = ref();
const form = ref({});
if (props.data?.id) {
form.value = Object.assign({}, props.data);
}
const addContext = () => {
form.value.context = form.value.context || [];
form.value.context.push({
role: "",
content: "",
});
};
const removeContext = (record) => {
const index = form.value.context.findIndex((item) => {
return item === record;
});
if (index > -1) {
form.value.context.splice(index, 1);
}
};
defineExpose({
formRef,
form,
});
</script>
<style lang="less" scoped>
.content-title {
display: flex;
justify-content: space-between;
align-items: center;
width: 350px;
}
.content-cell {
display: flex;
align-items: center;
width: 350px;
svg {
margin-left: 10px;
}
}
</style>

View File

@ -0,0 +1,29 @@
import http from "@/http/config";
export const getList = (params?: Record<string, unknown>) => {
return http({
url: "/api/admin/role/list",
method: "get",
params,
});
};
export const save = (data?: Record<string, unknown>) => {
return http({
url: "/api/admin/role/save",
method: "post",
data,
});
};
export const deleting = (id: string | number) => {
return http({
url: `/api/admin/role/remove?id=${id}`,
method: "get",
});
};
export const setStatus = (data) => {
return http({
url: `/api/admin/role/set`,
method: "post",
data,
});
};