Files
tongxunruanjian/mobile-next/lib/company/ui/add_colleague_page.dart
T
2b2c2d28a4 fix(mobile-next): 把加载、失败、断网接到真实 SDK 与目录请求
会话列表、通讯录、好友申请、添加同事页覆盖 CompanyLoadingView/CompanyFailView;
主页断网横幅跟随 IMSdkStatus.connectionFailed。不伪造状态。

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-08-20 02:52:24 +08:00

241 lines
7.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
import 'package:get/get.dart';
import 'package:openim_common/openim_common.dart';
import '../auth/auth_api.dart';
import '../brand/app_tokens.dart';
import '../directory/directory_api.dart';
import 'state_views.dart';
class AddColleagueLogic extends GetxController {
final staffCtrl = TextEditingController();
final msgCtrl = TextEditingController(text: '你好,我想加你为同事');
final sending = false.obs;
final staffError = RxnString();
final directoryHint = RxnString();
final loading = true.obs;
final loadFailed = false.obs;
final _directory = DirectoryApi();
@override
void onReady() {
reload();
super.onReady();
}
@override
void onClose() {
staffCtrl.dispose();
msgCtrl.dispose();
super.onClose();
}
Future<void> reload() async {
loading.value = true;
loadFailed.value = false;
try {
await _directory.search(keyword: '', limit: 1);
} catch (e) {
loadFailed.value = true;
} finally {
loading.value = false;
}
}
Future<void> lookupDirectory() async {
final id = staffCtrl.text.trim();
if (id.isEmpty) {
directoryHint.value = null;
return;
}
try {
final items = await _directory.search(keyword: id, limit: 5);
final hit = items.where((e) => e.userID == id).toList();
if (hit.isNotEmpty) {
directoryHint.value = hit.first.nickname;
} else if (items.isNotEmpty) {
directoryHint.value =
items.map((e) => '${e.nickname}${e.userID}').join('、');
} else {
directoryHint.value = null;
}
} catch (_) {
directoryHint.value = null;
}
}
Future<void> send() async {
if (sending.value) return;
final id = staffCtrl.text.trim();
if (id.isEmpty) {
staffError.value = '请输入对方工号';
return;
}
staffError.value = null;
sending.value = true;
try {
await OpenIM.iMManager.friendshipManager.addFriend(
userID: id,
reason:
msgCtrl.text.trim().isEmpty ? '你好,我想加你为同事' : msgCtrl.text.trim(),
);
IMViews.showToast('申请已发送,等对方通过');
Get.back();
} on AuthException catch (e) {
IMViews.showToast(e.message);
} catch (_) {
IMViews.showToast('发送失败,请确认工号正确、网络正常');
} finally {
sending.value = false;
}
}
}
class AddColleaguePage extends StatelessWidget {
const AddColleaguePage({super.key});
@override
Widget build(BuildContext context) {
final logic = Get.put(AddColleagueLogic());
return Scaffold(
backgroundColor: AppColors.pageBg,
appBar: AppBar(
title: const Text('添加同事'),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new, size: AppIconSize.md),
onPressed: Get.back,
),
),
body: Obx(() {
if (logic.loading.value) {
return const CompanyLoadingView();
}
if (logic.loadFailed.value) {
return CompanyFailView(onRetry: logic.reload);
}
return Padding(
padding: const EdgeInsets.all(AppGap.x4),
child: Column(
children: [
_box(
controller: logic.staffCtrl,
hint: '请输入对方工号',
height: 48,
error: logic.staffError.value,
enabled: !logic.sending.value,
onChanged: (_) {
logic.staffError.value = null;
logic.lookupDirectory();
},
),
Builder(builder: (_) {
final hint = logic.directoryHint.value;
if (hint == null) return const SizedBox.shrink();
return Padding(
padding: const EdgeInsets.only(top: AppGap.x2),
child: Align(
alignment: Alignment.centerLeft,
child: Text(hint,
style: const TextStyle(
fontSize: AppFont.sub,
color: AppColors.textSecondary)),
),
);
}),
const SizedBox(height: AppGap.x3),
_box(
controller: logic.msgCtrl,
hint: '你好,我想加你为同事',
height: 96,
maxLines: 4,
enabled: !logic.sending.value,
),
const Spacer(),
Builder(builder: (_) {
final busy = logic.sending.value;
return SizedBox(
width: double.infinity,
height: 48,
child: FilledButton(
onPressed: busy ? null : logic.send,
style: FilledButton.styleFrom(
backgroundColor: AppColors.primary,
disabledBackgroundColor:
AppColors.primary.withOpacity(0.4),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(AppRadius.control)),
),
child: busy
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2, color: Colors.white),
)
: const Text('发送申请',
style: TextStyle(
fontSize: AppFont.body, color: Colors.white)),
),
);
}),
const SizedBox(height: AppGap.x4),
],
),
);
}),
);
}
Widget _box({
required TextEditingController controller,
required String hint,
required double height,
int maxLines = 1,
String? error,
bool enabled = true,
ValueChanged<String>? onChanged,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: height,
padding: const EdgeInsets.symmetric(
horizontal: AppGap.x3, vertical: AppGap.x2),
decoration: BoxDecoration(
color: AppColors.searchBg,
borderRadius: BorderRadius.circular(AppRadius.control),
border: Border.all(
color: error != null ? AppColors.danger : Colors.transparent),
),
child: TextField(
controller: controller,
maxLines: maxLines,
enabled: enabled,
onChanged: onChanged,
style: const TextStyle(
fontSize: AppFont.body, color: AppColors.textPrimary),
decoration: InputDecoration(
isDense: true,
border: InputBorder.none,
hintText: hint,
hintStyle: const TextStyle(
fontSize: AppFont.body, color: AppColors.textSecondary),
),
),
),
if (error != null)
Padding(
padding: const EdgeInsets.only(top: AppGap.x1),
child: Text(error,
style: const TextStyle(
fontSize: AppFont.small, color: AppColors.danger)),
),
],
);
}
}