feat(module): 添加新页面
- 增添meili-config页面用于配置melisearch - 将原先的module.vue改为meili-index.vue,页面逻辑不变
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
import { defineModule } from '@directus/extensions-sdk';
|
import { defineModule } from '@directus/extensions-sdk';
|
||||||
import ModuleComponent from './module.vue';
|
import MeiliIndex from './meili-index.vue';
|
||||||
|
import MeiliConfig from './meili-config.vue';
|
||||||
|
|
||||||
export default defineModule({
|
export default defineModule({
|
||||||
id: 'meilisearch',
|
id: 'meilisearch',
|
||||||
@ -8,7 +9,11 @@ export default defineModule({
|
|||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: ModuleComponent,
|
component: MeiliIndex,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'config',
|
||||||
|
component: MeiliConfig,
|
||||||
|
}
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
137
src/meilisearch_module/meili-config.vue
Normal file
137
src/meilisearch_module/meili-config.vue
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<private-view title="MeiliSearch 配置">
|
||||||
|
<template #navigation>
|
||||||
|
<v-list nav :model-value="selected" dense>
|
||||||
|
<v-list-item to="/meilisearch" exact>
|
||||||
|
索引配置
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item to="/meilisearch/config">
|
||||||
|
MeiliSearch 配置
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<v-form collection="meili_search_config" v-model="formData" ref="form">
|
||||||
|
<v-text-field v-model="formData.host" label="MeiliSearch Host" required />
|
||||||
|
<v-text-field v-model="formData.apiKey" label="API Key" required />
|
||||||
|
</v-form>
|
||||||
|
<div class="button-group">
|
||||||
|
<v-button v-if="!pending" color="secondary" @click="testConnection">
|
||||||
|
测试连接
|
||||||
|
</v-button>
|
||||||
|
<v-button v-if="pending" disabled>
|
||||||
|
正在测试... <v-progress-circular indeterminate size="20" />
|
||||||
|
</v-button>
|
||||||
|
<v-button color="primary" @click="saveConfig">
|
||||||
|
保存配置
|
||||||
|
</v-button>
|
||||||
|
</div>
|
||||||
|
<Bounce>
|
||||||
|
<div class="connection-result" v-if="statusMessage">
|
||||||
|
<v-notice :type="statusSuccess ? 'success' : 'error'">
|
||||||
|
{{ statusMessage }}
|
||||||
|
</v-notice>
|
||||||
|
</div>
|
||||||
|
</Bounce>
|
||||||
|
</section>
|
||||||
|
</private-view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { useApi } from '@directus/extensions-sdk';
|
||||||
|
|
||||||
|
const selected = ref(null);
|
||||||
|
|
||||||
|
const api = useApi();
|
||||||
|
const statusMessage = ref<string | null>(null);
|
||||||
|
const statusSuccess = ref(false);
|
||||||
|
const pending = ref(false);
|
||||||
|
|
||||||
|
let configExists = false;
|
||||||
|
|
||||||
|
const formData = ref<{ host: string; apiKey: string }>({
|
||||||
|
host: '',
|
||||||
|
apiKey: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchConfig = async () => {
|
||||||
|
const resp = await api.get('/items/meili_search_config?limit=1');
|
||||||
|
if (resp.data.data) {
|
||||||
|
formData.value.host = resp.data.data.host;
|
||||||
|
formData.value.apiKey = resp.data.data.apiKey;
|
||||||
|
configExists = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const testConnection = async () => {
|
||||||
|
statusMessage.value = '';
|
||||||
|
try {
|
||||||
|
pending.value = true;
|
||||||
|
const resp = await api.post('/meilisearch/connection-test', { host: formData.value.host, apiKey: formData.value.apiKey });
|
||||||
|
if (resp.data.success) {
|
||||||
|
statusSuccess.value = true;
|
||||||
|
statusMessage.value = '连接成功!';
|
||||||
|
} else {
|
||||||
|
statusSuccess.value = false;
|
||||||
|
statusMessage.value = `连接失败:${resp.data.message}`;
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
statusSuccess.value = false;
|
||||||
|
statusMessage.value = `请求出错:${err.message}`;
|
||||||
|
} finally {
|
||||||
|
pending.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveConfig = async () => {
|
||||||
|
// 与之前示例相同的保存逻辑…
|
||||||
|
if (!formData.value.host) {
|
||||||
|
statusSuccess.value = false;
|
||||||
|
statusMessage.value = '请填写 Host';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response;
|
||||||
|
if (configExists) {
|
||||||
|
response = await api.patch('/items/meili_search_config', formData.value);
|
||||||
|
} else {
|
||||||
|
response = await api.post('/items/meili_search_config', formData.value);
|
||||||
|
configExists = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error('保存配置时发生错误');
|
||||||
|
}
|
||||||
|
|
||||||
|
statusSuccess.value = true;
|
||||||
|
statusMessage.value = '配置已保存!';
|
||||||
|
} catch (err: any) {
|
||||||
|
statusSuccess.value = false;
|
||||||
|
statusMessage.value = `保存失败:${err.message}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchConfig();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
section {
|
||||||
|
padding: 0 var(--content-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-result {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
68
src/meilisearch_module/meili-index.vue
Normal file
68
src/meilisearch_module/meili-index.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<private-view title="Meili Sync">
|
||||||
|
<template #title-outer:prepend>
|
||||||
|
<v-icon name="feature_search" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #navigation>
|
||||||
|
<v-list nav :model-value="selected" dense>
|
||||||
|
<v-list-item to="/meilisearch" exact>
|
||||||
|
索引配置
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item to="/meilisearch/config">
|
||||||
|
MeiliSearch 配置
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<v-notice type="info">请选择希望被 MeiliSearch 索引的集合。</v-notice>
|
||||||
|
<v-table :headers="headers" :items="collections" :items-per-page="10" class="mt-4">
|
||||||
|
<template #item.enabled="{ item }">
|
||||||
|
<v-checkbox v-model="item.enabled" :label="item.enabled ? '已启用' : '未启用'" />
|
||||||
|
</template>"
|
||||||
|
</v-table>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</private-view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { useApi } from '@directus/extensions-sdk';
|
||||||
|
|
||||||
|
const api = useApi();
|
||||||
|
const collections = ref([]);
|
||||||
|
const headers = [
|
||||||
|
{ text: '集合名称', value: 'collection' },
|
||||||
|
{ text: '说明', value: 'note' },
|
||||||
|
{ text: '启用索引', value: 'enabled' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// const fetchConfigs = async () => {
|
||||||
|
// const resp = await api.get('/items/meili_index_configs', { params: { limit: -1 } });
|
||||||
|
// configs.value = resp.data.data;
|
||||||
|
// }
|
||||||
|
|
||||||
|
const fetchCollections = async () => {
|
||||||
|
const resp = await api.get('/meilisearch/collections');
|
||||||
|
collections.value = resp.data.map((col: any) => ({
|
||||||
|
...col,
|
||||||
|
enabled: false,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const selected = ref(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchCollections();
|
||||||
|
// fetchConfigs();
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
section {
|
||||||
|
padding: 0 var(--content-padding);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,9 +0,0 @@
|
|||||||
<template>
|
|
||||||
<private-view title="My Custom Module">Content goes here...</private-view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({});
|
|
||||||
</script>
|
|
||||||
Reference in New Issue
Block a user