diff --git a/frontend/src/views/seller/SellerListingCreateView.css b/frontend/src/views/seller/SellerListingCreateView.css new file mode 100644 index 0000000..3c7b76f --- /dev/null +++ b/frontend/src/views/seller/SellerListingCreateView.css @@ -0,0 +1,677 @@ +.publish-page { + min-width: 0; + color: #20242a; +} + +.publish-layout { + display: grid; + grid-template-columns: minmax(760px, 920px) 300px; + align-items: start; + gap: 18px; + max-width: 1238px; + margin: 0 auto; +} + +.form-column { + display: grid; + min-width: 0; + gap: 18px; +} + +.summary-panel { + border: 1px solid #e6ebf2; + border-radius: 8px; + background: #fff; + box-shadow: 0 12px 34px rgba(20, 34, 56, 0.05); +} + +.field-row { + display: grid; + grid-template-columns: 112px minmax(0, 1fr); + gap: 14px; + align-items: center; + margin-top: 12px; +} + +.panel-field-row, +.panel-input-grid { + padding: 12px; + border-radius: 8px; + background: #f7f9fc; +} + +.panel-input-grid { + align-items: end; +} + +.field-row > label, +.input-block > span { + color: #303743; + font-size: 13px; + font-weight: 800; + line-height: 22px; +} + +.field-row label span, +.input-block b, +.level-row strong span, +.upload-copy strong span { + color: #f04438; +} + +.level-btn, +.region-btn, +.mode-toggle button, +.ratio-mode-btn { + border: 1px solid #d6dce5; + background: #fff; + color: #596474; + font-weight: 800; + cursor: pointer; + transition: border-color 0.16s ease, background 0.16s ease, color 0.16s ease; +} + +.level-btn.active, +.region-btn.active { + border-color: #1477ff; + background: #1477ff; + color: #fff; +} + +.compact-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 16px; + margin-top: 16px; +} + +.compact-grid.two { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.input-block { + display: grid; + min-width: 0; + gap: 8px; +} + +.input-block :deep(.el-input-number), +.input-block :deep(.el-input), +.input-block :deep(.el-date-editor) { + width: 100%; +} + +.input-block :deep(.el-input__wrapper), +.input-block :deep(.el-textarea__inner) { + border-radius: 8px; + box-shadow: 0 0 0 1px #dfe5ee inset; +} + +.level-panel { + display: grid; + gap: 10px; + margin-top: 16px; +} + +.level-row { + display: grid; + grid-template-columns: 72px minmax(0, 1fr); + gap: 12px; + align-items: center; + padding: 10px 12px; + border-radius: 8px; + background: #f7f9fc; +} + +.level-row strong { + font-size: 13px; +} + +.level-options { + display: grid; + grid-template-columns: repeat(7, minmax(0, 1fr)); + gap: 9px; +} + +.level-btn { + height: 30px; + min-width: 0; + border-radius: 15px; +} + +.field-hint { + grid-column: 2; + margin: 0; + color: #7f8895; + font-size: 12px; + line-height: 1.55; +} + +.login-method-row { + padding: 12px; + border-radius: 8px; + background: #f7f9fc; +} + +.login-method-row .field-hint { + margin-top: -2px; +} + +.quantity-table { + display: grid; + gap: 8px; +} + +.quantity-header, +.quantity-item { + display: grid; + grid-template-columns: minmax(160px, 1fr) 90px 112px 112px 92px; + gap: 12px; + align-items: center; +} + +.quantity-header { + min-height: 30px; + padding: 0 12px; + color: #7b8492; + font-size: 12px; + font-weight: 800; +} + +.quantity-item { + min-height: 58px; + padding: 12px; + border-radius: 8px; + background: #f7f9fc; +} + +.quantity-meta { + display: grid; + min-width: 0; + gap: 4px; +} + +.quantity-meta strong { + overflow: hidden; + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.quantity-meta small, +.quantity-price, +.quantity-status, +.upload-copy small, +.region-title span { + color: #7f8895; + font-size: 12px; + font-weight: 700; +} + +.quantity-price, +.quantity-status { + white-space: nowrap; +} + +.quantity-item.disabled { + opacity: 0.62; +} + +.quantity-item :deep(.el-input-number) { + width: 100%; + min-width: 0; +} + +.mode-toggle { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; + min-width: 0; +} + +.mode-toggle button { + height: 30px; + min-width: 0; + border-radius: 8px; + font-size: 12px; + white-space: nowrap; +} + +.mode-toggle button:disabled { + cursor: not-allowed; +} + +.mode-toggle button.active { + border-color: #ff6a00; + background: #fff3ea; + color: #e65f00; +} + +.recommend-button { + flex: 0 0 auto; + height: 32px; + padding: 0 12px; + border: 1px solid #ffba86; + border-radius: 8px; + background: #fff7f0; + color: #e65f00; + font-size: 12px; + font-weight: 800; + cursor: pointer; +} + +.deposit-control { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 8px; + align-items: center; +} + +.deposit-breakdown { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.deposit-breakdown span { + min-height: 24px; + padding: 4px 8px; + border-radius: 12px; + background: #fff7f0; + color: #e65f00; + font-size: 12px; + font-weight: 800; +} + +.skin-groups { + display: grid; + gap: 10px; +} + +.skin-group, +.region-panel, +.ratio-panel { + display: grid; + gap: 10px; + padding: 12px; + border-radius: 8px; + background: #f7f9fc; +} + +.skin-title, +.region-title { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + font-size: 13px; +} + +.skin-group { + border: none; +} + +.skin-title { + min-height: 34px; + margin-bottom: 8px; +} + +.time-preset-panel { + display: grid; + gap: 10px; + margin-top: 16px; +} + +.time-preset-row { + display: grid; + grid-template-columns: 88px minmax(0, 1fr); + gap: 12px; + align-items: start; + padding: 12px; + border-radius: 8px; + background: #f7f9fc; +} + +.time-preset-row strong { + color: #303743; + font-size: 13px; + font-weight: 800; + line-height: 32px; +} + +.time-preset-content { + display: grid; + gap: 8px; + min-width: 0; +} + +.time-input { + width: 118px; +} + +.time-input :deep(.el-input__wrapper) { + border-radius: 8px; + box-shadow: 0 0 0 1px #dfe5ee inset; +} + +.login-region-panel { + margin-top: 18px; +} + +.region-grid { + display: grid; + grid-template-columns: repeat(8, minmax(0, 1fr)); + gap: 8px; +} + +.region-btn { + height: 32px; + min-width: 0; + border-radius: 16px; +} + +.upload-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px; +} + +.upload-item { + display: grid; + grid-template-columns: minmax(0, 1fr) 96px; + gap: 12px; + align-items: center; + min-height: 112px; + padding: 12px; + border: 1px solid #e6ebf2; + border-radius: 8px; + background: #f8fafc; +} + +.upload-copy { + display: grid; + min-width: 0; + gap: 6px; +} + +.upload-copy strong { + color: #232a35; + font-size: 14px; +} + +.upload-copy small { + line-height: 1.45; +} + +.upload-add, +.upload-preview { + width: 96px; + height: 88px; + border-radius: 8px; +} + +.upload-add { + display: grid; + place-items: center; + border: 1px dashed #c7ceda; + background: #fff; + color: #727d8d; + font-size: 12px; + font-weight: 800; + cursor: pointer; +} + +.upload-add:disabled { + cursor: not-allowed; + opacity: 0.58; +} + +.upload-preview { + position: relative; + overflow: hidden; + background: #e8edf4; +} + +.upload-preview img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.upload-preview button { + position: absolute; + right: 6px; + bottom: 6px; + display: grid; + width: 28px; + height: 28px; + place-items: center; + border: none; + border-radius: 8px; + background: rgba(17, 24, 39, 0.72); + color: #fff; + cursor: pointer; +} + +.hidden-file { + display: none; +} + +.ratio-panel { + margin-top: 14px; +} + +.ratio-reference { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 52px; + padding: 12px; + border-radius: 8px; + background: #fff; +} + +.ratio-reference span { + color: #303743; + font-size: 13px; + font-weight: 800; +} + +.ratio-reference strong, +.price-cell strong, +.summary-main strong { + color: #ff6a00; + font-weight: 900; +} + +.ratio-reference strong { + font-size: 22px; +} + +.ratio-panel p { + margin: 0; + color: #7f8895; + font-size: 12px; + line-height: 1.5; +} + +.ratio-mode-grid, +.price-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} + +.ratio-mode-btn { + display: grid; + gap: 6px; + min-height: 72px; + padding: 12px; + border-radius: 8px; + text-align: left; +} + +.ratio-mode-btn span { + color: #7f8895; + font-size: 12px; +} + +.ratio-mode-btn.active { + border-color: #ff6a00; + background: #fff7f0; + color: #ff6a00; +} + +.ratio-mode-btn:disabled { + cursor: not-allowed; + opacity: 0.58; +} + +.price-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + margin-top: 14px; +} + +.price-cell { + display: grid; + gap: 6px; + min-height: 82px; + padding: 14px; + border-radius: 8px; + background: #f7f9fc; +} + +.price-cell span { + color: #6f7a89; + font-size: 12px; + font-weight: 800; +} + +.price-cell strong { + overflow-wrap: anywhere; + font-size: 21px; +} + +.price-cell.accent { + background: #fff7f0; +} + +.remark { + margin-top: 14px; +} + +.summary-column { + min-width: 0; + position: sticky; + top: 76px; + align-self: start; + height: fit-content; +} + +.summary-panel { + padding: 16px; +} + +.summary-main { + display: grid; + gap: 8px; + padding: 16px; + border-radius: 8px; + background: #fff7f0; +} + +.summary-main span, +.summary-list span { + color: #6f7a89; + font-size: 12px; + font-weight: 800; +} + +.summary-main strong { + font-size: 34px; + line-height: 1; +} + +.summary-list { + display: grid; + gap: 10px; + margin: 14px 0; +} + +.summary-list div { + display: flex; + justify-content: space-between; + gap: 12px; + padding-bottom: 10px; + border-bottom: 1px solid #eef2f6; +} + +.summary-list strong { + color: #20242a; + font-size: 13px; + text-align: right; + overflow-wrap: anywhere; +} + +.summary-actions { + display: grid; + gap: 10px; +} + +.summary-actions :deep(.el-button) { + width: 100%; + margin-left: 0; +} + +@media (max-width: 1180px) { + .publish-layout { + grid-template-columns: 1fr; + max-width: 920px; + } + + .summary-column { + display: none; + } +} + +@media (max-width: 860px) { + .field-row, + .compact-grid, + .compact-grid.two, + .upload-grid, + .price-grid { + grid-template-columns: 1fr; + } + + .quantity-header { + display: none; + } + + .field-hint { + grid-column: auto; + } + + .quantity-item, + .upload-item { + grid-template-columns: 1fr; + } + + .deposit-control, + .ratio-mode-grid, + .time-preset-row { + grid-template-columns: 1fr; + } + + .time-input { + width: 140px; + } + + .upload-add, + .upload-preview { + width: 100%; + } + + .region-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } +} diff --git a/frontend/src/views/seller/SellerListingCreateView.vue b/frontend/src/views/seller/SellerListingCreateView.vue index 07b75b5..d2c4761 100644 --- a/frontend/src/views/seller/SellerListingCreateView.vue +++ b/frontend/src/views/seller/SellerListingCreateView.vue @@ -3,6 +3,8 @@ import { Delete, DocumentChecked, Picture, RefreshRight, UploadFilled } from '@e import { ElMessage, ElMessageBox } from 'element-plus' import { usePublishForm } from '@/composables/usePublishForm' +import OptionChips from './components/OptionChips.vue' +import PublishSection from './components/PublishSection.vue' const { commonOnlineTimes, @@ -81,48 +83,29 @@ const { notifyWarning: (message) => ElMessage.warning(message), notifyError: (message) => ElMessage.error(message), }) + +function toggleSkinOption(value: string | number) { + toggleSkin(String(value)) +} + +function selectDailyLoss(value: string | number) { + form.daily_loss_m = Number(value) +} - + diff --git a/frontend/src/views/seller/components/OptionChips.vue b/frontend/src/views/seller/components/OptionChips.vue new file mode 100644 index 0000000..0538941 --- /dev/null +++ b/frontend/src/views/seller/components/OptionChips.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/frontend/src/views/seller/components/PublishSection.vue b/frontend/src/views/seller/components/PublishSection.vue new file mode 100644 index 0000000..ec8ea9f --- /dev/null +++ b/frontend/src/views/seller/components/PublishSection.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 15dd91b..28c21b6 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -3,9 +3,8 @@ "compilerOptions": { "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", "types": ["vite/client"], - "baseUrl": ".", "paths": { - "@/*": ["src/*"] + "@/*": ["./src/*"] } }, "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]