7777 <textarea v-model =" form.contentMarkdown" class =" textarea" rows =" 10" ></textarea >
7878 </div >
7979
80+ <div class =" field" style =" margin-top : 12px ; max-width : 420px " >
81+ <div class =" label" >发布时间(可选,留空为当前时间;允许早于当前时间)</div >
82+ <input v-model =" publishAtInput" class =" input" type =" datetime-local" />
83+ </div >
84+
8085 <div style =" display : flex ; gap : 12px ; flex-wrap : wrap ; margin-top : 14px " >
8186 <button class =" btn primary" @click =" saveDraft" >保存草稿/更新</button >
8287 <button class =" btn" :disabled =" !selectedId" @click =" publish" :style =" { opacity: selectedId ? 1 : 0.6 }" >
@@ -106,6 +111,7 @@ import {
106111 createDraft ,
107112 updateArticle ,
108113 publishArticle ,
114+ publishArticleWithTime ,
109115 deleteMyArticle
110116} from ' ../api/admin'
111117import { uploadMedia } from ' ../api/media'
@@ -123,6 +129,8 @@ const form = ref({
123129 coverMediaKey: null
124130})
125131
132+ const publishAtInput = ref (' ' )
133+
126134const loadingArticles = ref (false )
127135const loadingDetail = ref (false )
128136const myArticles = ref ([])
@@ -153,6 +161,26 @@ function resetEditor() {
153161 form .value .summary = ' '
154162 form .value .contentMarkdown = ' '
155163 form .value .coverMediaKey = null
164+ publishAtInput .value = ' '
165+ }
166+
167+ function toLocalDatetimeInput (iso ) {
168+ if (! iso) return ' '
169+ try {
170+ const d = new Date (iso)
171+ if (Number .isNaN (d .getTime ())) return ' '
172+ const pad = (n ) => String (n).padStart (2 , ' 0' )
173+ return ` ${ d .getFullYear ()} -${ pad (d .getMonth () + 1 )} -${ pad (d .getDate ())} T${ pad (d .getHours ())} :${ pad (d .getMinutes ())} `
174+ } catch {
175+ return ' '
176+ }
177+ }
178+
179+ function toIsoOrEmpty (v ) {
180+ if (! v || ! String (v).trim ()) return undefined
181+ const d = new Date (v)
182+ if (Number .isNaN (d .getTime ())) return undefined
183+ return d .toISOString ()
156184}
157185
158186async function newDraft () {
@@ -170,6 +198,7 @@ async function loadEditor(id) {
170198 form .value .summary = detail .summary || ' '
171199 form .value .contentMarkdown = detail .contentMarkdown || ' '
172200 form .value .coverMediaKey = detail .coverMediaKey || null
201+ publishAtInput .value = toLocalDatetimeInput (detail .publishedAt )
173202 } finally {
174203 loadingDetail .value = false
175204 }
@@ -216,7 +245,12 @@ async function publish() {
216245 articleError.value = ''
217246 articleSuccess.value = ''
218247 try {
219- await publishArticle(selectedId.value)
248+ const publishedAt = toIsoOrEmpty(publishAtInput.value)
249+ if (publishedAt) {
250+ await publishArticleWithTime(selectedId.value, { publishedAt })
251+ } else {
252+ await publishArticle(selectedId.value)
253+ }
220254 await loadArticles()
221255 articleSuccess.value = '发布成功'
222256 } catch (e) {
0 commit comments