-
-
{{ $t('search.confirm.filter') }}:
-
- {{ bangumi.filter?.join(', ') || '-' }}
-
+
+
-
-
{{ $t('search.confirm.save_path') }}:
-
- {{ bangumi.save_path || '-' }}
-
+
+
+
+
+
+
+
@@ -275,23 +328,51 @@ function handleConfirm() {
white-space: nowrap;
}
-.bangumi-details {
- display: flex;
- gap: 8px;
+.bangumi-year {
font-size: 13px;
- color: var(--color-text-secondary);
+ color: var(--color-text-muted);
+ margin: 4px 0 0;
+}
- span {
- &:not(:last-child)::after {
- content: '·';
- margin-left: 8px;
- color: var(--color-text-muted);
- }
+// Info Tags
+.info-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-bottom: 16px;
+}
+
+.info-tag {
+ display: inline-flex;
+ align-items: center;
+ padding: 6px 14px;
+ border-radius: var(--radius-full);
+ font-size: 13px;
+ font-weight: 600;
+
+ &--season {
+ background: color-mix(in srgb, var(--color-primary) 12%, transparent);
+ color: var(--color-primary);
+ }
+
+ &--resolution {
+ background: color-mix(in srgb, var(--color-accent) 12%, transparent);
+ color: var(--color-accent);
+ }
+
+ &--subtitle {
+ background: color-mix(in srgb, var(--color-success) 12%, transparent);
+ color: var(--color-success);
+ }
+
+ &--group {
+ background: color-mix(in srgb, var(--color-warning) 12%, transparent);
+ color: var(--color-warning);
}
}
-// Info section
-.info-section {
+// RSS section
+.rss-section {
display: flex;
flex-direction: column;
gap: 12px;
@@ -328,14 +409,6 @@ function handleConfirm() {
text-overflow: ellipsis;
white-space: nowrap;
}
-
- &--code {
- font-family: 'Fira Code', monospace;
- font-size: 12px;
- background: var(--color-surface);
- padding: 4px 8px;
- border-radius: var(--radius-sm);
- }
}
.copy-btn {
@@ -398,6 +471,86 @@ function handleConfirm() {
margin-top: 8px;
}
+.advanced-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ min-height: 32px;
+
+ &--tags {
+ align-items: flex-start;
+ }
+}
+
+.advanced-label {
+ flex-shrink: 0;
+ font-size: 13px;
+ font-weight: 500;
+ color: var(--color-text-secondary);
+ line-height: 32px;
+}
+
+.advanced-control {
+ display: flex;
+ justify-content: flex-end;
+
+ :deep(.n-dynamic-tags) {
+ justify-content: flex-end;
+ min-height: 32px;
+
+ .n-tag {
+ height: 28px;
+ margin: 2px 0 2px 6px !important;
+ }
+
+ .n-button {
+ height: 28px;
+ }
+ }
+}
+
+.offset-controls {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: 8px;
+ height: 32px;
+}
+
+.offset-input {
+ width: 70px;
+ height: 32px;
+ text-align: center;
+}
+
+.detect-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 80px;
+ height: 32px;
+ padding: 0 14px;
+ font-size: 13px;
+ font-family: inherit;
+ font-weight: 500;
+ color: #fff;
+ background: var(--color-primary);
+ border: none;
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ white-space: nowrap;
+ transition: background-color var(--transition-fast);
+
+ &:hover:not(:disabled) {
+ background: var(--color-primary-hover);
+ }
+
+ &:disabled {
+ cursor: wait;
+ }
+}
+
// Expand transition
.expand-enter-active,
.expand-leave-active {
diff --git a/webui/src/components/search/ab-search-modal.vue b/webui/src/components/search/ab-search-modal.vue
index d542458e..01c2a2d7 100644
--- a/webui/src/components/search/ab-search-modal.vue
+++ b/webui/src/components/search/ab-search-modal.vue
@@ -9,9 +9,11 @@ import type { BangumiRule } from '#/bangumi';
const emit = defineEmits<{
(e: 'close'): void;
- (e: 'add-bangumi', bangumi: BangumiRule): void;
}>();
+const message = useMessage();
+const { getAll } = useBangumiStore();
+
const {
providers,
provider,
@@ -35,6 +37,8 @@ const {
clearSelectedResult,
} = useSearchStore();
+const subscribing = ref(false);
+
const showProvider = ref(false);
const searchInputRef = ref
(null);
@@ -64,10 +68,32 @@ function handleCardClick(bangumi: BangumiRule) {
selectResult(bangumi);
}
-function handleConfirm(bangumi: BangumiRule) {
- emit('add-bangumi', bangumi);
- clearSelectedResult();
- emit('close');
+async function handleConfirm(bangumi: BangumiRule) {
+ subscribing.value = true;
+ try {
+ // Create RSS object from bangumi data
+ const rss = {
+ id: 0,
+ name: bangumi.official_title,
+ url: bangumi.rss_link?.[0] || '',
+ aggregate: false,
+ parser: 'mikan',
+ enabled: true,
+ connection_status: null,
+ last_checked_at: null,
+ last_error: null,
+ };
+ await apiDownload.subscribe(bangumi, rss);
+ message.success('订阅成功');
+ getAll();
+ clearSelectedResult();
+ emit('close');
+ } catch (e) {
+ console.error('Subscribe failed:', e);
+ message.error('订阅失败');
+ } finally {
+ subscribing.value = false;
+ }
}
function handleClose() {
@@ -175,7 +201,7 @@ function handleClose() {
:key="result.order"
:bangumi="result.value"
:style="{ '--stagger-index': index }"
- @click="handleCardClick(result.value)"
+ @select="handleCardClick"
/>
diff --git a/webui/src/utils/axios.ts b/webui/src/utils/axios.ts
index 38f06ee3..45589123 100644
--- a/webui/src/utils/axios.ts
+++ b/webui/src/utils/axios.ts
@@ -10,8 +10,8 @@ axios.interceptors.response.use(
(res: AxiosResponse) => res,
(err: AxiosError
) => {
const status = err.response?.status as StatusCode;
- const msg_en = err.response?.data.msg_en ?? '';
- const msg_zh = err.response?.data.msg_zh ?? '';
+ const msg_en = err.response?.data?.msg_en ?? '';
+ const msg_zh = err.response?.data?.msg_zh ?? '';
const message = useMessage();
const { returnUserLangText } = useMyI18n();