Merge pull request #63 from Learnware-LAMDA/feat(frontend)/heter_search

Feat(frontend)/heter search
This commit is contained in:
AnnyTerfect 2023-10-30 21:17:52 +08:00 committed by GitHub
commit d15586608c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 94 additions and 78 deletions

View File

@ -2,6 +2,7 @@ import { createApp } from "vue";
import router from "./router";
import App from "./App.vue";
import vuetify from "./plugins/vuetify";
import "./plugins/dayjs";
import store from "@main/store";
import i18n from "@main/i18n";

View File

@ -0,0 +1,14 @@
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import UpdateLocale from "dayjs/plugin/updateLocale";
import zhCn from "dayjs/locale/zh-cn";
dayjs.extend(relativeTime);
dayjs.extend(UpdateLocale);
dayjs.updateLocale("zh-cn", zhCn);
const language =
JSON.parse(localStorage.getItem("vuex") || "{}")?.i18n?.locale ||
(navigator.language || "en").toLocaleLowerCase();
dayjs.locale(language);

View File

@ -109,7 +109,7 @@ const Router = createRouter({
},
children: [
{
path: "/language/zh",
path: "/language/zh-cn",
name: "Chinese",
component: (): Promise<Component> => import("@main/views/ChangeLanguage.vue"),
meta: {

View File

@ -4,4 +4,6 @@ export default {
SearchByName: "Search by name",
LearnwareName: "Learnware Name",
UploadStatisticalRequirement: "Upload statistical requirement",
SpecificationScore: "Specification score",
Updated: "Updated",
};

View File

@ -1,2 +1,2 @@
export { default as zh } from "./zh";
export { default as zhCn } from "./zh-cn";
export { default as en } from "./en";

View File

@ -4,4 +4,6 @@ export default {
SearchByName: "按名称查找",
LearnwareName: "学件名称",
UploadStatisticalRequirement: "上传统计需求",
SpecificationScore: "规约匹配分数",
Updated: "更新于",
};

View File

@ -9,9 +9,7 @@ import ImageBtn from "../../assets/images/specification/dataType/image.svg?compo
import TableBtn from "../../assets/images/specification/dataType/table.svg?component";
import { downloadLearnwareSync } from "../../utils";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import type { LearnwareCardInfo, Filter } from "@beiming-system/types/learnware";
dayjs.extend(relativeTime);
const { t } = useI18n();
@ -75,23 +73,17 @@ function handleClickDelete(id: string): void {
</script>
<template>
<v-card
flat
:density="greaterThanXs ? 'comfortable' : 'compact'"
class="card"
:class="item.matchScore && item.matchScore >= 0 ? ['pt-2'] : ['py-2']"
>
<div class="first-row">
<v-card-title class="title flex" :class="item.username ? '' : 'items-center'">
<v-avatar :size="greaterThanSm ? 'default' : 'small'" class="mr-2" rounded="0">
<component :is="avatar" :class="item.username ? 'w-1/1' : 'w-4/5'" class="opacity-70" />
</v-avatar>
<div>
<div>{{ item.name }}</div>
<div v-if="item.username" class="text-sm text-gray-600">{{ item.username }}</div>
</div>
</v-card-title>
</div>
<v-card flat :density="greaterThanXs ? 'comfortable' : 'compact'" class="card py-2">
<v-card-title class="title flex" :class="item.username ? '' : 'items-center'">
<v-avatar :size="greaterThanSm ? 'default' : 'small'" class="mr-2" rounded="0">
<component :is="avatar" :class="item.username ? 'w-1/1' : 'w-4/5'" class="opacity-70" />
</v-avatar>
<div class="w-full overflow-hidden">
<div class="w-full truncate">{{ item.name }}</div>
<div v-if="item.username" class="text-sm text-gray-600">{{ item.username }}</div>
</div>
</v-card-title>
<v-card-subtitle>
<div style="color: red">
{{ item.verifyStatus != undefined && item.verifyStatus != "SUCCESS" ? "Unverified" : "" }}
@ -158,43 +150,41 @@ function handleClickDelete(id: string): void {
<v-card-text class="card-text">
<div class="description">{{ item.description }}</div>
</v-card-text>
<v-card-title
class="last-row"
:class="{ 'justify-between': item.matchScore && item.matchScore >= 0 }"
>
<div v-if="item.matchScore && item.matchScore >= 0" class="xl: text-xl lg:text-lg text-1rem">
Specification score
<span class="ml-2 text-xl" :style="`color: ${getColorByScore(item.matchScore)}`">{{
item.matchScore
}}</span>
<v-card-text class="flex justify-between items-end py-2">
<div>
<div v-if="item.matchScore && item.matchScore >= 0" class="xl:text-lg lg:text-lg text-base">
{{ t("Search.SpecificationScore") }}:
<span :style="`color: ${getColorByScore(item.matchScore)}`">{{ item.matchScore }}</span>
</div>
<span class="text-gray-500 text-xs">
{{ t("Search.Updated") }} {{ dayjs(item.lastModify).fromNow() }}
</span>
</div>
<div class="actions">
<v-btn
v-if="isAdmin"
flat
icon="mdi-pencil"
:size="greaterThanXs ? undefined : 'small'"
@click.stop="() => handleClickEdit(item.id)"
></v-btn>
<v-btn
v-if="showDownload"
flat
icon="mdi-download"
:size="greaterThanXs ? undefined : 'small'"
@click.stop="() => downloadLearnwareSync(item.id)"
></v-btn>
<v-btn
v-if="isAdmin"
flat
icon="mdi-delete"
:size="greaterThanXs ? undefined : 'small'"
@click.stop="handleClickDelete(item.id)"
></v-btn>
</div>
</v-card-title>
<v-card-text>
<div style="color: gray; font-size: xx-small">
Updated {{ dayjs(item.lastModify).fromNow() }}
<div class="flex items-center">
<div class="actions -mr-3 -mb-2">
<v-btn
v-if="isAdmin"
flat
icon="mdi-pencil"
:size="greaterThanXs ? undefined : 'small'"
@click.stop="() => handleClickEdit(item.id)"
></v-btn>
<v-btn
v-if="showDownload"
flat
icon="mdi-download"
:size="greaterThanXs ? undefined : 'small'"
@click.stop="() => downloadLearnwareSync(item.id)"
></v-btn>
<v-btn
v-if="isAdmin"
flat
icon="mdi-delete"
:size="greaterThanXs ? undefined : 'small'"
@click.stop="handleClickDelete(item.id)"
></v-btn>
</div>
</div>
</v-card-text>
</v-card>
@ -212,18 +202,6 @@ function handleClickDelete(id: string): void {
}
}
.last-row {
@apply flex items-center absolute right-0 bottom-0;
.actions {
@apply flex flex-row justify-end;
* {
@apply <sm: mx-0;
}
}
}
.card-text {
@apply flex flex-wrap items-center pt-0 pb-2 text-gray-700;

View File

@ -114,10 +114,10 @@ function getColorByScore(score: number): string {
</v-card-title>
<v-btn
variant="flat"
size="x-large"
class="!px-4 text-body-2 !text-1em border-1"
@click.stop="() => downloadAll()"
>
size="x-large">
<span v-if="!downloading">
<v-icon icon="mdi-download"></v-icon>
Download All

View File

@ -56,7 +56,7 @@ watch(
</script>
<template>
<div class="flex flex-col w-1/1 md:max-w-460px sm:border-r-1">
<div class="flex flex-col w-1/1 lg:max-w-460px sm:border-r-1">
<div class="filter">
<slot name="prepend" />
<div class="my-3 text-h6">

View File

@ -150,7 +150,7 @@ watch(
<v-textarea
v-model="descriptionString"
auto-grow
:label="`${name}${locale != 'zh' ? ' ' : ''}${t('Public.Description')}`"
:label="`${name}${locale != 'zh-cn' ? ' ' : ''}${t('Public.Description')}`"
:error-messages="errorMessages"
/>
</div>

View File

@ -1,16 +1,18 @@
import { createI18n } from "vue-i18n";
import { zh, en } from "@beiming-system/locale";
import { zhCn, en } from "@beiming-system/locale";
const messages = {
en,
zh,
"zh-cn": zhCn,
};
const language =
JSON.parse(localStorage.getItem("vuex") || "{}")?.i18n?.locale ||
(navigator.language || "en").toLocaleLowerCase();
const i18n = createI18n({
legacy: false,
locale: language.split("-")[0] || "en",
locale: language || "en",
fallbackLocale: "en",
messages,
});

View File

@ -2,6 +2,7 @@ import { createApp } from "vue";
import router from "./router";
import App from "./App.vue";
import vuetify from "./plugins/vuetify";
import "./plugins/dayjs";
import store from "./store";
import i18n from "./i18n";

View File

@ -0,0 +1,14 @@
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import UpdateLocale from "dayjs/plugin/updateLocale";
import zhCn from "dayjs/locale/zh-cn";
dayjs.extend(relativeTime);
dayjs.extend(UpdateLocale);
dayjs.updateLocale("zh-cn", zhCn);
const language =
JSON.parse(localStorage.getItem("vuex") || "{}")?.i18n?.locale ||
(navigator.language || "en").toLocaleLowerCase();
dayjs.locale(language);

View File

@ -134,7 +134,7 @@ const Router = createRouter({
},
children: [
{
path: "/language/zh",
path: "/language/zh-cn",
name: "Chinese",
component: (): Promise<Component> => import("../views/ChangeLanguage.vue"),
meta: {

View File

@ -1,4 +1,5 @@
import i18n from "../../i18n";
import dayjs from "dayjs";
interface I18nLocaleState {
locale: string;
@ -6,12 +7,13 @@ interface I18nLocaleState {
const i18nLocale = {
state: {
locale: "cn",
locale: "zh-cn",
},
mutations: {
setLocale(state: I18nLocaleState, locale: string): void {
state.locale = locale;
i18n.global.locale.value = locale;
dayjs.locale(locale);
},
},
getters: {

View File

@ -243,7 +243,7 @@ onMounted(() => {
<style scoped lang="scss">
.search-container {
@apply md: (fixed flex) mx-auto w-1/1;
@apply lg: (fixed flex) mx-auto w-1/1;
height: calc(100% - var(--v-layout-top));
.content {