Initial commit: 风影 OA 全栈源码(API/Web/Flutter/IM)

含 Phase 1.1 IM seq 排序、断线重连、多端已读同步与微信式语音转文字 UI。
排除 node_modules、构建产物、安装包与 .env 密钥。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-02 10:04:03 +00:00
commit 76f266645d
507 changed files with 99891 additions and 0 deletions
@@ -0,0 +1,65 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import '../api/oa_client.dart';
import '../theme.dart';
class TencentMapThumb extends StatefulWidget {
const TencentMapThumb({
super.key,
required this.api,
required this.lat,
required this.lng,
this.height = 110,
this.width,
});
final OaClient api;
final double lat;
final double lng;
final double height;
final double? width;
@override
State<TencentMapThumb> createState() => _TencentMapThumbState();
}
class _TencentMapThumbState extends State<TencentMapThumb> {
Uint8List? _bytes;
@override
void initState() {
super.initState();
_load();
}
@override
void didUpdateWidget(covariant TencentMapThumb oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.lat != widget.lat || oldWidget.lng != widget.lng) _load();
}
Future<void> _load() async {
final b = await widget.api.getBytes('/office/geo/static-map', query: {
'lat': '${widget.lat}',
'lng': '${widget.lng}',
});
if (!mounted) return;
setState(() => _bytes = b);
}
@override
Widget build(BuildContext context) {
if (_bytes != null) {
return Image.memory(_bytes!, width: widget.width, height: widget.height, fit: BoxFit.cover);
}
return SizedBox(
width: widget.width,
height: widget.height,
child: const ColoredBox(
color: Color(0xFFE8F5E9),
child: Center(child: Icon(Icons.place, color: kWeGreen, size: 32)),
),
);
}
}