mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	feat(ui):apiKey 语言模型 角色管理 产品
This commit is contained in:
		@@ -18,7 +18,7 @@ export default function (
 | 
			
		||||
 | 
			
		||||
  const popupProps = (arg: Arg[], getExposed) => {
 | 
			
		||||
    return {
 | 
			
		||||
      width: 700,
 | 
			
		||||
      width: 800,
 | 
			
		||||
      onBeforeOk: async () => {
 | 
			
		||||
        const exposed = getExposed();
 | 
			
		||||
        const validateRes = await exposed?.formRef.value.validate();
 | 
			
		||||
 
 | 
			
		||||
@@ -4,80 +4,112 @@ import {
 | 
			
		||||
  IconOrderedList,
 | 
			
		||||
  IconCalendar,
 | 
			
		||||
  IconSettings,
 | 
			
		||||
  IconUserGroup,
 | 
			
		||||
  IconLock,
 | 
			
		||||
  IconCodepen,
 | 
			
		||||
  IconWechatpay,
 | 
			
		||||
} from "@arco-design/web-vue/es/icon";
 | 
			
		||||
 | 
			
		||||
const menu = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '/dashboard',
 | 
			
		||||
    name: 'Dashboard',
 | 
			
		||||
    path: "/dashboard",
 | 
			
		||||
    name: "Dashboard",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "仪表盘",
 | 
			
		||||
      icon: IconDashboard
 | 
			
		||||
      icon: IconDashboard,
 | 
			
		||||
    },
 | 
			
		||||
    component: () => import('@/views/DashboardView.vue')
 | 
			
		||||
    component: () => import("@/views/DashboardView.vue"),
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '/user',
 | 
			
		||||
    name: 'User',
 | 
			
		||||
    path: "/user",
 | 
			
		||||
    name: "User",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "用户管理",
 | 
			
		||||
      icon: IconUser,
 | 
			
		||||
    },
 | 
			
		||||
    component: () => import('@/views/User/UserContainer.vue')
 | 
			
		||||
    component: () => import("@/views/User/UserContainer.vue"),
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '/order',
 | 
			
		||||
    name: 'Order',
 | 
			
		||||
    path: "/Role",
 | 
			
		||||
    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: {
 | 
			
		||||
      title: "充值订单",
 | 
			
		||||
      icon: IconOrderedList,
 | 
			
		||||
    },
 | 
			
		||||
    component: () => import('@/views/Order/OrderContainer.vue')
 | 
			
		||||
    component: () => import("@/views/Order/OrderContainer.vue"),
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    path: '/reward',
 | 
			
		||||
    name: 'Reward',
 | 
			
		||||
    path: "/reward",
 | 
			
		||||
    name: "Reward",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "众筹管理",
 | 
			
		||||
      icon: IconCalendar,
 | 
			
		||||
    },
 | 
			
		||||
    component: () => import('@/views/Reward/RewardContainer.vue')
 | 
			
		||||
    component: () => import("@/views/Reward/RewardContainer.vue"),
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '/functions',
 | 
			
		||||
    name: 'Functions',
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "函数管理",
 | 
			
		||||
      icon: IconCalendar,
 | 
			
		||||
    },
 | 
			
		||||
    component: () => import('@/views/Functions/FunctionsContainer.vue')
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '/chats',
 | 
			
		||||
    name: 'Chats',
 | 
			
		||||
    path: "/chats",
 | 
			
		||||
    name: "Chats",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "对话管理",
 | 
			
		||||
      icon: IconCalendar,
 | 
			
		||||
    },
 | 
			
		||||
    component: () => import('@/views/Chats/ChatsContainer.vue')
 | 
			
		||||
    component: () => import("@/views/Chats/ChatsContainer.vue"),
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '/system',
 | 
			
		||||
    name: 'System',
 | 
			
		||||
    path: "/system",
 | 
			
		||||
    name: "System",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "系统设置",
 | 
			
		||||
      icon: IconSettings,
 | 
			
		||||
    },
 | 
			
		||||
    component: () => import('@/views/System/SystemContainer.vue')
 | 
			
		||||
    component: () => import("@/views/System/SystemContainer.vue"),
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '/loginLog',
 | 
			
		||||
    name: 'LoginLog',
 | 
			
		||||
    path: "/loginLog",
 | 
			
		||||
    name: "LoginLog",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "登录日志",
 | 
			
		||||
      icon: IconCalendar,
 | 
			
		||||
    },
 | 
			
		||||
    component: () => import('@/views/LoginLog.vue')
 | 
			
		||||
    component: () => import("@/views/LoginLog.vue"),
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
  <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>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										97
									
								
								gpt-vue/projects/vue-admin/src/views/ApiKey/ApiKeyForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								gpt-vue/projects/vue-admin/src/views/ApiKey/ApiKeyForm.vue
									
									
									
									
									
										Normal 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>
 | 
			
		||||
							
								
								
									
										29
									
								
								gpt-vue/projects/vue-admin/src/views/ApiKey/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								gpt-vue/projects/vue-admin/src/views/ApiKey/api.ts
									
									
									
									
									
										Normal 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,
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
@@ -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>
 | 
			
		||||
  <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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
							
								
								
									
										29
									
								
								gpt-vue/projects/vue-admin/src/views/ChatModel/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								gpt-vue/projects/vue-admin/src/views/ChatModel/api.ts
									
									
									
									
									
										Normal 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,
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
@@ -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>
 | 
			
		||||
  <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>
 | 
			
		||||
<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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
  <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>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										87
									
								
								gpt-vue/projects/vue-admin/src/views/Product/ProductForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								gpt-vue/projects/vue-admin/src/views/Product/ProductForm.vue
									
									
									
									
									
										Normal 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>
 | 
			
		||||
							
								
								
									
										29
									
								
								gpt-vue/projects/vue-admin/src/views/Product/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								gpt-vue/projects/vue-admin/src/views/Product/api.ts
									
									
									
									
									
										Normal 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,
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
@@ -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>
 | 
			
		||||
  <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>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										116
									
								
								gpt-vue/projects/vue-admin/src/views/Role/RoleForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								gpt-vue/projects/vue-admin/src/views/Role/RoleForm.vue
									
									
									
									
									
										Normal 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>
 | 
			
		||||
							
								
								
									
										29
									
								
								gpt-vue/projects/vue-admin/src/views/Role/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								gpt-vue/projects/vue-admin/src/views/Role/api.ts
									
									
									
									
									
										Normal 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,
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user