mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-18 09:16:39 +08:00
feat(ui): 函数管理
This commit is contained in:
parent
a36f14eb94
commit
8e7413da97
@ -60,6 +60,9 @@ importers:
|
||||
'@vitejs/plugin-vue-jsx':
|
||||
specifier: ^3.1.0
|
||||
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':
|
||||
specifier: ^12.0.0
|
||||
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==}
|
||||
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):
|
||||
resolution: {integrity: sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==}
|
||||
engines: {node: ^14.17.0 || >=16.0.0}
|
||||
@ -1670,6 +1685,32 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
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):
|
||||
resolution: {integrity: sha512-7wCXv5zuVnBtZE/74z4yZ0CM8AjH6bk4MQGm7hZjUC2DBppKU5ioeOk5LGSg/s9a1ZJnIsdPLJpXnu1Rc+cVHg==}
|
||||
engines: {node: ^14.17.0 || >=16.0.0}
|
||||
@ -1788,6 +1829,10 @@ packages:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
dev: true
|
||||
|
||||
/fast-diff@1.3.0:
|
||||
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
|
||||
dev: true
|
||||
|
||||
/fast-glob@3.3.2:
|
||||
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
@ -2451,6 +2496,19 @@ packages:
|
||||
engines: {node: '>= 0.8.0'}
|
||||
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:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
dev: false
|
||||
|
@ -1,14 +1,28 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
require("@rushstack/eslint-patch/modern-module-resolution");
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript'
|
||||
extends: [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/eslint-config-typescript",
|
||||
"@vue/eslint-config-prettier",
|
||||
],
|
||||
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",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"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 type { TableRequest, TableOriginalProps } from "./useAsyncTable";
|
||||
|
||||
export interface SimpleTable extends /* @vue-ignore */ TableOriginalProps {
|
||||
interface SimpleTable extends /* @vue-ignore */ TableOriginalProps {
|
||||
request: TableRequest<Record<string, unknown>>;
|
||||
params?: Record<string, unknown>;
|
||||
columns?: TableOriginalProps["columns"];
|
||||
}
|
||||
|
||||
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')
|
||||
},
|
||||
{
|
||||
path: '/functions',
|
||||
name: 'Functions',
|
||||
meta: {
|
||||
title: "函数管理",
|
||||
icon: IconCalendar,
|
||||
},
|
||||
component: () => import('@/views/Functions/FunctionsContainer.vue')
|
||||
},
|
||||
{
|
||||
path: '/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>
|
||||
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 SimpleTable from "@/components/SimpleTable/SimpleTable.vue";
|
||||
import { getList } from "./api";
|
||||
import { getList, remove } from "./api";
|
||||
|
||||
const columns: TableColumnData[] = [
|
||||
{
|
||||
@ -38,22 +38,38 @@ const columns: TableColumnData[] = [
|
||||
title: "操作",
|
||||
slotName: "actions",
|
||||
fixed: "right",
|
||||
width: 80,
|
||||
},
|
||||
];
|
||||
|
||||
const handleRemove = async (id, reload) => {
|
||||
await remove({ id });
|
||||
Message.success("删除成功");
|
||||
await reload();
|
||||
return true;
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<SimpleTable :request="getList" :columns="columns">
|
||||
<template #updated_at="{ record }">
|
||||
<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 #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"
|
||||
<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-popconfirm
|
||||
content="是否删除?"
|
||||
position="left"
|
||||
type="warning"
|
||||
:on-before-ok="() => handleRemove(record.id, reload)"
|
||||
>
|
||||
<a-link status="danger">删除</a-link>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</SimpleTable>
|
||||
</template>
|
||||
|
@ -6,4 +6,12 @@ export const getList = (params?: Record<string, unknown>) => {
|
||||
method: "get",
|
||||
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"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"strict": false,
|
||||
"noImplicitAny": false,
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
Loading…
Reference in New Issue
Block a user