2323 <el-option v-for =" opt in expireOptions" :key =" opt.value" :label =" opt.label" :value =" opt.value" />
2424 </el-select >
2525 </el-form-item >
26- <el-form-item :label =" $t('file.sharePassword')" prop =" password " >
26+ <el-form-item :label =" $t('file.sharePassword')" prop =" sharePassword " >
2727 <el-input
28- v-model =" form.password "
28+ v-model =" form.sharePassword "
2929 type =" password"
3030 show-password
3131 clearable
5454 </div >
5555 </el-form-item >
5656 <el-form-item :label =" $t('file.shareExpiresAt')" >
57- <span >{{ expiresAtText }}</ span >
57+ <el-input :model-value = " expiresAtText" readonly / >
5858 </el-form-item >
5959 </template >
6060 </el-form >
@@ -102,7 +102,7 @@ import i18n from '@/lang';
102102import { GlobalStore } from ' @/store' ;
103103import { buildFileSharePageUrl , buildFileShareQrCodeUrl , copyText , dateFormat as formatDateTime } from ' @/utils/util' ;
104104import type { FormInstance , FormRules } from ' element-plus' ;
105- import { computed , reactive , ref } from ' vue' ;
105+ import { computed , reactive , ref , watch } from ' vue' ;
106106
107107interface ShareProps {
108108 path: string ;
@@ -119,9 +119,12 @@ const expiresAtText = ref('');
119119const qrCodeUrl = ref (' ' );
120120const qrDialogOpen = ref (false );
121121const shareFormRef = ref <FormInstance >();
122+ const syncingPassword = ref (false );
123+ const initialSharePassword = ref (' ' );
124+ const passwordTouched = ref (false );
122125const form = reactive ({
123126 expireMinutes: 1440 ,
124- password : ' ' ,
127+ sharePassword : ' ' ,
125128});
126129
127130const emit = defineEmits ([' close' ]);
@@ -149,9 +152,22 @@ const validatePassword = (_rule, value, callback) => {
149152};
150153
151154const rules = reactive <FormRules >({
152- password : [{ validator: validatePassword , trigger: ' blur' }],
155+ sharePassword : [{ validator: validatePassword , trigger: ' blur' }],
153156});
154157
158+ watch (
159+ () => form .sharePassword ,
160+ (val ) => {
161+ if (syncingPassword .value ) {
162+ return ;
163+ }
164+ if (val === initialSharePassword .value ) {
165+ return ;
166+ }
167+ passwordTouched .value = true ;
168+ },
169+ );
170+
155171const mapExpireMinutes = (info : File .FileShareInfo ) => {
156172 if (info .permanent || info .expiresAt === 0 ) {
157173 return 0 ;
@@ -169,7 +185,11 @@ const applyShareInfo = (info: File.FileShareInfo | null) => {
169185 qrCodeUrl .value = ' ' ;
170186 qrDialogOpen .value = false ;
171187 form .expireMinutes = 1440 ;
172- form .password = ' ' ;
188+ form .sharePassword = ' ' ;
189+ syncingPassword .value = true ;
190+ initialSharePassword .value = ' ' ;
191+ passwordTouched .value = false ;
192+ syncingPassword .value = false ;
173193 return ;
174194 }
175195 shareUrl .value = buildFileSharePageUrl (info .code , globalStore .currentNode );
@@ -178,7 +198,11 @@ const applyShareInfo = (info: File.FileShareInfo | null) => {
178198 ? i18n .global .t (' website.ever' )
179199 : formatDateTime (null , null , info .expiresAt * 1000 );
180200 form .expireMinutes = mapExpireMinutes (info );
181- form .password = ' ' ;
201+ syncingPassword .value = true ;
202+ form .sharePassword = info .password || ' ' ;
203+ initialSharePassword .value = form .sharePassword ;
204+ passwordTouched .value = false ;
205+ syncingPassword .value = false ;
182206};
183207
184208const loadShareDetail = async () => {
@@ -207,12 +231,21 @@ const generate = async () => {
207231 }
208232 loading .value = true ;
209233 try {
210- const pw = form .password .trim ();
211- const res = await createFileShare ( {
234+ const pw = form .sharePassword .trim ();
235+ const payload : File . FileShareCreate = {
212236 path: filePath .value ,
213237 expireMinutes: form .expireMinutes ,
214- ... (pw .length > 0 ? { password: pw } : {}),
215- });
238+ };
239+
240+ // Only send password when user explicitly changes it.
241+ if (passwordTouched .value ) {
242+ payload .password = pw ; // empty string means "clear password"
243+ } else if (! shareInfo .value ?.hasPassword && pw .length > 0 ) {
244+ // New share: allow setting password when it wasn't loaded from server.
245+ payload .password = pw ;
246+ }
247+
248+ const res = await createFileShare (payload );
216249 applyShareInfo (res .data as File .FileShareInfo );
217250 changed .value = true ;
218251 } finally {
@@ -233,7 +266,19 @@ const cancelShare = async () => {
233266
234267const copyLink = () => {
235268 if (shareUrl .value ) {
236- copyText (shareUrl .value );
269+ const password = form .sharePassword .trim ();
270+ const content = password
271+ ? ` ${i18n .global .t (' file.shareLinkLabel' )}:${shareUrl .value },${i18n .global .t (
272+ ' file.sharePassword' ,
273+ )}:${password } `
274+ : ` ${i18n .global .t (' file.shareLinkLabel' )}:${shareUrl .value } ` ;
275+ copyText (content );
276+ }
277+ };
278+
279+ const openShareUrl = () => {
280+ if (shareUrl .value ) {
281+ window .open (shareUrl .value , ' _blank' , ' noopener,noreferrer' );
237282 }
238283};
239284
0 commit comments