import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import '../../api/oa_client.dart'; import '../../session/session.dart'; import '../desk_theme.dart'; import '../widgets/desk_widgets.dart'; class DeskProfileEditPage extends StatefulWidget { const DeskProfileEditPage({super.key, required this.session, required this.api}); final SessionStore session; final OaClient api; @override State createState() => _DeskProfileEditPageState(); } class _DeskProfileEditPageState extends State { bool _busy = false; Future _refreshMe() async { final me = await widget.api.get('/auth/me'); if (me is Map) await widget.session.patchUser(Map.from(me)); if (mounted) setState(() {}); } Future _pickAvatar() async { final x = await ImagePicker().pickImage(source: ImageSource.gallery, imageQuality: 85, maxWidth: 800); if (x == null) return; setState(() => _busy = true); try { await widget.api.uploadFile( filePath: x.path, filename: x.name.isEmpty ? 'avatar.jpg' : x.name, bizType: 'USER_AVATAR', bizId: widget.session.userId, ); await _refreshMe(); if (mounted) deskToast(context, '头像已更新'); } catch (e) { if (mounted) deskToast(context, '$e', error: true); } finally { if (mounted) setState(() => _busy = false); } } Future _editName() async { final c = TextEditingController(text: widget.session.displayName); final ok = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('修改姓名'), content: TextField(controller: c, decoration: const InputDecoration(labelText: '显示名')), actions: [ TextButton(onPressed: () => Navigator.pop(ctx, false), child: const Text('取消')), FilledButton(onPressed: () => Navigator.pop(ctx, true), child: const Text('保存')), ], ), ); if (ok != true || c.text.trim().isEmpty) return; try { final me = await widget.api.patch('/auth/profile', {'displayName': c.text.trim()}); if (me is Map) await widget.session.patchUser(Map.from(me)); if (mounted) { setState(() {}); deskToast(context, '已保存'); } } catch (e) { if (mounted) deskToast(context, '$e', error: true); } } Future _editPassword() async { final oldC = TextEditingController(); final newC = TextEditingController(); final ok = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('修改密码'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField(controller: oldC, obscureText: true, decoration: const InputDecoration(labelText: '当前密码')), const SizedBox(height: 8), TextField(controller: newC, obscureText: true, decoration: const InputDecoration(labelText: '新密码')), ], ), actions: [ TextButton(onPressed: () => Navigator.pop(ctx, false), child: const Text('取消')), FilledButton(onPressed: () => Navigator.pop(ctx, true), child: const Text('保存')), ], ), ); if (ok != true) return; try { await widget.api.post('/auth/change-password', {'oldPassword': oldC.text, 'newPassword': newC.text}); if (mounted) deskToast(context, '密码已修改'); } catch (e) { if (mounted) deskToast(context, '$e', error: true); } } @override Widget build(BuildContext context) { final s = widget.session; final u = s.user; return ColoredBox( color: kDeskBg, child: Column( children: [ DeskPaneHeader( title: '个人资料', leading: IconButton(icon: const Icon(Icons.arrow_back, size: 20), onPressed: () => Navigator.pop(context)), ), Expanded( child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 480), child: ListView( padding: const EdgeInsets.all(24), children: [ Center( child: Stack( children: [ DeskAvatar(label: s.displayName, fileId: '${u['avatarFileId'] ?? ''}', api: widget.api, size: 80), if (_busy) const Positioned.fill(child: CircularProgressIndicator(strokeWidth: 2, color: kDeskBind)), ], ), ), const SizedBox(height: 12), Center( child: TextButton(onPressed: _busy ? null : _pickAvatar, child: const Text('更换头像')), ), const SizedBox(height: 16), _row('姓名', s.displayName, onTap: _editName), _row('手机', '${u['mobile'] ?? '未填写'}'), _row('邮箱', '${u['email'] ?? '未填写'}'), _row('部门', '${u['department'] ?? ''}'), _row('职位', '${u['title'] ?? ''}'), const SizedBox(height: 16), SizedBox( width: double.infinity, child: OutlinedButton(onPressed: _editPassword, child: const Text('修改密码')), ), ], ), ), ), ), ], ), ); } Widget _row(String k, String v, {VoidCallback? onTap}) { return Material( color: Colors.white, borderRadius: BorderRadius.circular(8), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(8), child: Container( margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), child: Row( children: [ SizedBox(width: 64, child: Text(k, style: const TextStyle(color: kDeskMute, fontSize: 13))), Expanded(child: Text(v, style: const TextStyle(fontSize: 14))), if (onTap != null) const Icon(Icons.chevron_right, size: 18, color: kDeskMute), ], ), ), ), ); } }