mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-18 17:26:38 +08:00
feat(ui): 函数管理
This commit is contained in:
parent
a36f14eb94
commit
8e7413da97
@ -60,6 +60,9 @@ importers:
|
|||||||
'@vitejs/plugin-vue-jsx':
|
'@vitejs/plugin-vue-jsx':
|
||||||
specifier: ^3.1.0
|
specifier: ^3.1.0
|
||||||
version: 3.1.0(vite@5.1.5)(vue@3.4.21)
|
version: 3.1.0(vite@5.1.5)(vue@3.4.21)
|
||||||
|
'@vue/eslint-config-prettier':
|
||||||
|
specifier: ^7.0.0
|
||||||
|
version: 7.1.0(eslint@8.57.0)(prettier@3.2.5)
|
||||||
'@vue/eslint-config-typescript':
|
'@vue/eslint-config-typescript':
|
||||||
specifier: ^12.0.0
|
specifier: ^12.0.0
|
||||||
version: 12.0.0(eslint-plugin-vue@9.22.0)(eslint@8.57.0)(typescript@5.3.3)
|
version: 12.0.0(eslint-plugin-vue@9.22.0)(eslint@8.57.0)(typescript@5.3.3)
|
||||||
@ -1245,6 +1248,18 @@ packages:
|
|||||||
resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
|
resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@vue/eslint-config-prettier@7.1.0(eslint@8.57.0)(prettier@3.2.5):
|
||||||
|
resolution: {integrity: sha512-Pv/lVr0bAzSIHLd9iz0KnvAr4GKyCEl+h52bc4e5yWuDVtLgFwycF7nrbWTAQAS+FU6q1geVd07lc6EWfJiWKQ==}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: '>= 7.28.0'
|
||||||
|
prettier: '>= 2.0.0'
|
||||||
|
dependencies:
|
||||||
|
eslint: 8.57.0
|
||||||
|
eslint-config-prettier: 8.10.0(eslint@8.57.0)
|
||||||
|
eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.2.5)
|
||||||
|
prettier: 3.2.5
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@vue/eslint-config-typescript@12.0.0(eslint-plugin-vue@9.22.0)(eslint@8.57.0)(typescript@5.3.3):
|
/@vue/eslint-config-typescript@12.0.0(eslint-plugin-vue@9.22.0)(eslint@8.57.0)(typescript@5.3.3):
|
||||||
resolution: {integrity: sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==}
|
resolution: {integrity: sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==}
|
||||||
engines: {node: ^14.17.0 || >=16.0.0}
|
engines: {node: ^14.17.0 || >=16.0.0}
|
||||||
@ -1670,6 +1685,32 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/eslint-config-prettier@8.10.0(eslint@8.57.0):
|
||||||
|
resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
eslint: '>=7.0.0'
|
||||||
|
dependencies:
|
||||||
|
eslint: 8.57.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.2.5):
|
||||||
|
resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: '>=7.28.0'
|
||||||
|
eslint-config-prettier: '*'
|
||||||
|
prettier: '>=2.0.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
eslint-config-prettier:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
eslint: 8.57.0
|
||||||
|
eslint-config-prettier: 8.10.0(eslint@8.57.0)
|
||||||
|
prettier: 3.2.5
|
||||||
|
prettier-linter-helpers: 1.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-vue@9.22.0(eslint@8.57.0):
|
/eslint-plugin-vue@9.22.0(eslint@8.57.0):
|
||||||
resolution: {integrity: sha512-7wCXv5zuVnBtZE/74z4yZ0CM8AjH6bk4MQGm7hZjUC2DBppKU5ioeOk5LGSg/s9a1ZJnIsdPLJpXnu1Rc+cVHg==}
|
resolution: {integrity: sha512-7wCXv5zuVnBtZE/74z4yZ0CM8AjH6bk4MQGm7hZjUC2DBppKU5ioeOk5LGSg/s9a1ZJnIsdPLJpXnu1Rc+cVHg==}
|
||||||
engines: {node: ^14.17.0 || >=16.0.0}
|
engines: {node: ^14.17.0 || >=16.0.0}
|
||||||
@ -1788,6 +1829,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/fast-diff@1.3.0:
|
||||||
|
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/fast-glob@3.3.2:
|
/fast-glob@3.3.2:
|
||||||
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
|
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
|
||||||
engines: {node: '>=8.6.0'}
|
engines: {node: '>=8.6.0'}
|
||||||
@ -2451,6 +2496,19 @@ packages:
|
|||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/prettier-linter-helpers@1.0.0:
|
||||||
|
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
dependencies:
|
||||||
|
fast-diff: 1.3.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/prettier@3.2.5:
|
||||||
|
resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/proxy-from-env@1.1.0:
|
/proxy-from-env@1.1.0:
|
||||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -1,14 +1,28 @@
|
|||||||
/* eslint-env node */
|
/* eslint-env node */
|
||||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
require("@rushstack/eslint-patch/modern-module-resolution");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
'extends': [
|
extends: [
|
||||||
'plugin:vue/vue3-essential',
|
"plugin:vue/vue3-essential",
|
||||||
'eslint:recommended',
|
"eslint:recommended",
|
||||||
'@vue/eslint-config-typescript'
|
"@vue/eslint-config-typescript",
|
||||||
|
"@vue/eslint-config-prettier",
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 'latest'
|
ecmaVersion: "latest",
|
||||||
}
|
sourceType: "module",
|
||||||
}
|
parser: "@typescript-eslint/parser",
|
||||||
|
ecmaFeatures: {
|
||||||
|
jsx: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: ["vue", "@typescript-eslint"],
|
||||||
|
rules: {
|
||||||
|
"prettier/prettier": "warn",
|
||||||
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
|
"vue/multi-word-component-names": "off",
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"no-undef": "off",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
9
gpt-vue/projects/vue-admin/.prettierrc.json
Normal file
9
gpt-vue/projects/vue-admin/.prettierrc.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 100,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"singleQuote": false,
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"bracketSpacing": true
|
||||||
|
}
|
@ -24,6 +24,7 @@
|
|||||||
"@types/node": "^20.11.10",
|
"@types/node": "^20.11.10",
|
||||||
"@vitejs/plugin-vue": "^5.0.3",
|
"@vitejs/plugin-vue": "^5.0.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
|
"@vue/eslint-config-prettier": "^7.0.0",
|
||||||
"@vue/eslint-config-typescript": "^12.0.0",
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
"@vue/tsconfig": "^0.5.1",
|
"@vue/tsconfig": "^0.5.1",
|
||||||
"eslint": "^8.49.0",
|
"eslint": "^8.49.0",
|
||||||
|
37
gpt-vue/projects/vue-admin/src/components/ConfirmSwitch.vue
Normal file
37
gpt-vue/projects/vue-admin/src/components/ConfirmSwitch.vue
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { Message, type SwitchInstance } from "@arco-design/web-vue";
|
||||||
|
import type { BaseResponse } from "@gpt-vue/packages/type";
|
||||||
|
|
||||||
|
type OriginProps = SwitchInstance["$props"];
|
||||||
|
|
||||||
|
interface Props extends /* @vue-ignore */ OriginProps {
|
||||||
|
modelValue: boolean | string | number;
|
||||||
|
api: (params?: any) => Promise<BaseResponse<any>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
|
const emits = defineEmits(["update:modelValue"]);
|
||||||
|
|
||||||
|
const _value = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (v) => {
|
||||||
|
emits("update:modelValue", v);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onBeforeChange = async (params) => {
|
||||||
|
try {
|
||||||
|
await props.api({ ...params, value: !_value.value });
|
||||||
|
Message.success("操作成功");
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<a-switch v-bind="{ ...props, ...$attrs }" v-model="_value" :before-change="onBeforeChange" />
|
||||||
|
</template>
|
@ -5,9 +5,10 @@ import { useTableScroll } from "@/components/SearchTable/utils";
|
|||||||
import { Message } from "@arco-design/web-vue";
|
import { Message } from "@arco-design/web-vue";
|
||||||
import type { TableRequest, TableOriginalProps } from "./useAsyncTable";
|
import type { TableRequest, TableOriginalProps } from "./useAsyncTable";
|
||||||
|
|
||||||
export interface SimpleTable extends /* @vue-ignore */ TableOriginalProps {
|
interface SimpleTable extends /* @vue-ignore */ TableOriginalProps {
|
||||||
request: TableRequest<Record<string, unknown>>;
|
request: TableRequest<Record<string, unknown>>;
|
||||||
params?: Record<string, unknown>;
|
params?: Record<string, unknown>;
|
||||||
|
columns?: TableOriginalProps["columns"];
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<SimpleTable>();
|
const props = defineProps<SimpleTable>();
|
||||||
|
29
gpt-vue/projects/vue-admin/src/composables/useSubmit.ts
Normal file
29
gpt-vue/projects/vue-admin/src/composables/useSubmit.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { ref, reactive, unref } from "vue";
|
||||||
|
import { Message } from "@arco-design/web-vue";
|
||||||
|
import type { BaseResponse } from "@gpt-vue/packages/type";
|
||||||
|
function useSubmit<T extends Record<string, unknown>, R = any>(defaultData: T) {
|
||||||
|
const formRef = ref();
|
||||||
|
const formData = reactive<T>({ ...defaultData });
|
||||||
|
const submitting = ref(false);
|
||||||
|
|
||||||
|
const handleSubmit = async (api: (params?: any) => Promise<BaseResponse<R>>, params) => {
|
||||||
|
submitting.value = true;
|
||||||
|
try {
|
||||||
|
const hasError = await formRef.value?.validate();
|
||||||
|
if (!hasError) {
|
||||||
|
const { data, message } = await api({ ...formData, ...unref(params) });
|
||||||
|
Message.success(message);
|
||||||
|
return Promise.resolve({ formData, data });
|
||||||
|
}
|
||||||
|
return Promise.reject(false);
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(err);
|
||||||
|
} finally {
|
||||||
|
submitting.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { formRef, formData, handleSubmit, submitting };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useSubmit;
|
@ -42,6 +42,15 @@ const menu = [
|
|||||||
},
|
},
|
||||||
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: '/loginLog',
|
path: '/loginLog',
|
||||||
name: 'LoginLog',
|
name: 'LoginLog',
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { Message, type TableColumnData } from "@arco-design/web-vue";
|
||||||
|
import SimpleTable from "@/components/SimpleTable/SimpleTable.vue";
|
||||||
|
import ConfirmSwitch from "@/components/ConfirmSwitch.vue";
|
||||||
|
import usePopup from "@/composables/usePopup";
|
||||||
|
import { getList, remove, setStatus, save } from "./api";
|
||||||
|
import FunctionsForm from "./FunctionsForm.vue";
|
||||||
|
|
||||||
|
const columns: TableColumnData[] = [
|
||||||
|
{
|
||||||
|
dataIndex: "name",
|
||||||
|
title: "函数名称",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: "label",
|
||||||
|
title: "函数别名",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: "description",
|
||||||
|
title: "功能描述",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: "enabled",
|
||||||
|
title: "启用状态",
|
||||||
|
slotName: "switch",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
slotName: "actions",
|
||||||
|
fixed: "right",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const openFormModal = usePopup(FunctionsForm, {
|
||||||
|
nodeProps: ([_, record]) => ({ record }),
|
||||||
|
popupProps: ([reload, record], exposed) => ({
|
||||||
|
title: `${record.id ? "编辑" : "新增"}函数`,
|
||||||
|
width: "800px",
|
||||||
|
onBeforeOk: async (done) => {
|
||||||
|
await exposed()?.handleSubmit(save, {
|
||||||
|
id: record.id,
|
||||||
|
parameters: exposed()?.parameters(),
|
||||||
|
});
|
||||||
|
await reload();
|
||||||
|
done(true);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleRemove = async (id, reload) => {
|
||||||
|
await remove({ id });
|
||||||
|
Message.success("删除成功");
|
||||||
|
await reload();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<a-button type="primary" @click="openFormModal">新增</a-button>
|
||||||
|
<SimpleTable :request="getList" :columns="columns" :pagination="false">
|
||||||
|
<template #switch="{ record, column }">
|
||||||
|
<ConfirmSwitch
|
||||||
|
v-model="record[column.dataIndex]"
|
||||||
|
:api="(p) => setStatus({ ...p, id: record.id, filed: 'enabled' })"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #exchange="{ record }">
|
||||||
|
<a-tag v-if="record.exchange.calls > 0">聊天{{ record.exchange.calls }}次</a-tag>
|
||||||
|
<a-tag v-else-if="record.exchange.img_calls > 0" color="green"
|
||||||
|
>绘图{{ record.exchange.img_calls }}次</a-tag
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #actions="{ record, reload }">
|
||||||
|
<a-link @click="openFormModal(reload, record)">编辑</a-link>
|
||||||
|
<a-popconfirm
|
||||||
|
content="是否删除?"
|
||||||
|
position="left"
|
||||||
|
type="warning"
|
||||||
|
:on-before-ok="() => handleRemove(record.id, reload)"
|
||||||
|
>
|
||||||
|
<a-link status="danger">删除</a-link>
|
||||||
|
</a-popconfirm>
|
||||||
|
</template>
|
||||||
|
</SimpleTable>
|
||||||
|
</template>
|
@ -0,0 +1,74 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watchEffect } from "vue";
|
||||||
|
import useSubmit from "@/composables/useSubmit";
|
||||||
|
import FunctionsFormTable from "./FunctionsFormTable.vue";
|
||||||
|
import translateTableData from "./translateTableData";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
record: Object,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableData = ref([]);
|
||||||
|
const { formRef, formData, handleSubmit, submitting } = useSubmit({
|
||||||
|
name: "",
|
||||||
|
label: "",
|
||||||
|
description: "",
|
||||||
|
action: "",
|
||||||
|
token: "",
|
||||||
|
parameters: {},
|
||||||
|
enabled: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
name: [{ required: true, message: "请输入函数名称" }],
|
||||||
|
label: [{ required: true, message: "请输入函数标签" }],
|
||||||
|
description: [{ required: true, message: "请输入函数功能描述" }],
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
Object.assign(formData, props.record ?? {});
|
||||||
|
tableData.value = translateTableData.get(formData.parameters);
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
handleSubmit,
|
||||||
|
parameters: () => translateTableData.set(tableData.value),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<a-spin :loading="submitting" style="width: 100%">
|
||||||
|
<a-form ref="formRef" :model="formData" auto-label-width :rules="rules">
|
||||||
|
<a-form-item field="name" label="函数名称">
|
||||||
|
<a-input v-model="formData.name" placeholder="函数名称最好为英文" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="label" label="函数标签">
|
||||||
|
<a-input v-model="formData.label" placeholder="函数的中文名称" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="description" label="功能描述">
|
||||||
|
<a-input v-model="formData.description" placeholder="函数的中文名称" />
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item field="parameters" label="函数参数">
|
||||||
|
<FunctionsFormTable v-model="tableData" />
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item field="action" label="API 地址">
|
||||||
|
<a-input v-model="formData.action" placeholder="该函数实现的API地址,可以是第三方服务API" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="token" label="API Token">
|
||||||
|
<a-input-search v-model="formData.token" placeholder="API授权Token">
|
||||||
|
<template #append>
|
||||||
|
<a-tooltip
|
||||||
|
content="只有本地服务才可以使用自动生成Token第三方服务请填写第三方服务API Token"
|
||||||
|
>
|
||||||
|
<a-button>生成Token</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</a-input-search>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="enabled" label="启用状态">
|
||||||
|
<a-switch v-model="formData.enabled" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
@ -0,0 +1,72 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { IconDelete } from "@arco-design/web-vue/es/icon";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits(["update:modelValue"]);
|
||||||
|
|
||||||
|
const handleCreateRow = () => {
|
||||||
|
emits("update:modelValue", [
|
||||||
|
...(props.modelValue ?? []),
|
||||||
|
{ name: "", type: "", description: "", required: false },
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveRow = (index) => {
|
||||||
|
emits(
|
||||||
|
"update:modelValue",
|
||||||
|
props.modelValue.filter((_, i) => i !== index)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<a-space direction="vertical" style="width: 100%">
|
||||||
|
<a-table :data="modelValue" size="small" style="width: 100%" :pagination="false">
|
||||||
|
<template #columns>
|
||||||
|
<a-table-column title="参数名称" :width="120">
|
||||||
|
<template #cell="scope">
|
||||||
|
<a-input v-model="scope.record.name" />
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
<a-table-column title="参数类型" :width="120">
|
||||||
|
<template #cell="scope">
|
||||||
|
<a-select
|
||||||
|
v-model="scope.record.type"
|
||||||
|
placeholder="参数类型"
|
||||||
|
:options="['string', 'number']"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
<a-table-column title="参数描述">
|
||||||
|
<template #cell="scope">
|
||||||
|
<a-input v-model="scope.record.description" />
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
|
||||||
|
<a-table-column title="必填参数" :width="100">
|
||||||
|
<template #cell="scope">
|
||||||
|
<a-checkbox v-model="scope.record.required" />
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
|
||||||
|
<a-table-column title="操作" :width="80">
|
||||||
|
<template #cell="scope">
|
||||||
|
<a-button
|
||||||
|
status="danger"
|
||||||
|
:icon="IconDelete"
|
||||||
|
circle
|
||||||
|
@click="handleRemoveRow(scope.rowIndex)"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<a-button type="primary" long @click="handleCreateRow">新增参数</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
41
gpt-vue/projects/vue-admin/src/views/Functions/api.ts
Normal file
41
gpt-vue/projects/vue-admin/src/views/Functions/api.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import http from "@/http/config";
|
||||||
|
|
||||||
|
export const getList = (params) => {
|
||||||
|
return http({
|
||||||
|
url: "/api/admin/function/list",
|
||||||
|
method: "get",
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const save = (data) => {
|
||||||
|
return http({
|
||||||
|
url: "/api/admin/function/save",
|
||||||
|
method: "post",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const remove = (params) => {
|
||||||
|
return http({
|
||||||
|
url: "/api/admin/function/remove",
|
||||||
|
method: "get",
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setStatus = (data) => {
|
||||||
|
return http({
|
||||||
|
url: "/api/admin/function/set",
|
||||||
|
method: "post",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const token = (data) => {
|
||||||
|
return http({
|
||||||
|
url: "/api/admin/function/token",
|
||||||
|
method: "post",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
const get = (origin) => {
|
||||||
|
const { properties, required, type } = origin;
|
||||||
|
if (type === "object") {
|
||||||
|
const array = Object.keys(properties).reduce((prev, name) => {
|
||||||
|
return [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
...properties[name],
|
||||||
|
required: required.includes(name),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const set = (tableData) => {
|
||||||
|
const properties = tableData.reduce((prev, curr) => {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[curr.name]: {
|
||||||
|
description: curr.description,
|
||||||
|
type: curr.type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
const required = tableData.filter((i) => i.required).map((i) => i.name);
|
||||||
|
return { properties, required, type: "object" }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { get, set }
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { TableColumnData } from "@arco-design/web-vue";
|
import { Message, type TableColumnData } from "@arco-design/web-vue";
|
||||||
import { dateFormat } from "@gpt-vue/packages/utils";
|
import { dateFormat } from "@gpt-vue/packages/utils";
|
||||||
import SimpleTable from "@/components/SimpleTable/SimpleTable.vue";
|
import SimpleTable from "@/components/SimpleTable/SimpleTable.vue";
|
||||||
import { getList } from "./api";
|
import { getList, remove } from "./api";
|
||||||
|
|
||||||
const columns: TableColumnData[] = [
|
const columns: TableColumnData[] = [
|
||||||
{
|
{
|
||||||
@ -38,22 +38,38 @@ const columns: TableColumnData[] = [
|
|||||||
title: "操作",
|
title: "操作",
|
||||||
slotName: "actions",
|
slotName: "actions",
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
|
width: 80,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleRemove = async (id, reload) => {
|
||||||
|
await remove({ id });
|
||||||
|
Message.success("删除成功");
|
||||||
|
await reload();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<SimpleTable :request="getList" :columns="columns">
|
<SimpleTable :request="getList" :columns="columns">
|
||||||
<template #updated_at="{ record }">
|
<template #updated_at="{ record }">
|
||||||
<span v-if="record.status">{{ dateFormat(record.updated_at) }}</span>
|
<span v-if="record.status">{{ dateFormat(record.updated_at) }}</span>
|
||||||
<a-tag v-else>未核销</a-tag>
|
<a-tag v-else color="blue">未核销</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #exchange="{ record }">
|
<template #exchange="{ record }">
|
||||||
<a-tag v-if="record.exchange.calls > 0"
|
<a-tag v-if="record.exchange.calls > 0">聊天{{ record.exchange.calls }}次</a-tag>
|
||||||
>聊天{{ record.exchange.calls }}次</a-tag
|
<a-tag v-else-if="record.exchange.img_calls > 0" color="green"
|
||||||
>
|
|
||||||
<a-tag v-else-if="record.exchange.img_calls > 0"
|
|
||||||
>绘图{{ record.exchange.img_calls }}次</a-tag
|
>绘图{{ record.exchange.img_calls }}次</a-tag
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
<template #actions="{ record, reload }">
|
||||||
|
<a-popconfirm
|
||||||
|
content="是否删除?"
|
||||||
|
position="left"
|
||||||
|
type="warning"
|
||||||
|
:on-before-ok="() => handleRemove(record.id, reload)"
|
||||||
|
>
|
||||||
|
<a-link status="danger">删除</a-link>
|
||||||
|
</a-popconfirm>
|
||||||
|
</template>
|
||||||
</SimpleTable>
|
</SimpleTable>
|
||||||
</template>
|
</template>
|
||||||
|
@ -7,3 +7,11 @@ export const getList = (params?: Record<string, unknown>) => {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const remove = (params?: Record<string, unknown>) => {
|
||||||
|
return http({
|
||||||
|
url: "/api/admin/reward/remove",
|
||||||
|
method: "get",
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||||
"exclude": ["src/**/__tests__/*"],
|
"exclude": ["src/**/__tests__/*"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"strict": false,
|
||||||
|
"noImplicitAny": false,
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
"playwright.config.*"
|
"playwright.config.*"
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||||
|
Loading…
Reference in New Issue
Block a user