/// <summary> /// 根据sql、过滤条件获取数据源,sql必须含有服务名前缀,如: /// Cm:select * from dt_log /// local:select * from letter /// </summary> /// <param name="p_sql">带前缀的sql</param> /// <param name="p_filter"></param> /// <returns></returns> static async Task <Table> GetDataBySql(string p_sql, string p_filter = null) { if (string.IsNullOrEmpty(p_sql)) { return(null); } string[] info = p_sql.Trim().Split(':'); if (info.Length != 2 || string.IsNullOrEmpty(info[0]) || string.IsNullOrEmpty(info[1])) { throw new Exception("Sql格式不正确!" + p_sql); } Table data; string sql = string.IsNullOrEmpty(p_filter) ? info[1] : $"select * from ({info[1]}) a where {p_filter}"; if (info[0].ToLower() == "local") { data = AtState.Query(sql); } else { data = await new UnaryRpc(info[0], "Da.Query", sql, null).Call <Table>(); } return(data); }
/// <summary> /// 设置自启动 /// </summary> /// <param name="p_win"></param> internal static void SetAutoStart(Win p_win) { if (p_win == null) { return; } if (!Kit.IsPhoneUI) { Tabs tabs = (Tabs)p_win.GetValue(Win.MainTabsProperty); if (tabs != null && tabs.Items.Count > 0 && ((Tab)tabs.Items[0]).Content is Win win) { // 设置主区窗口为自启动 p_win = win; } } AutoStartInfo info = new AutoStartInfo(); info.WinType = p_win.GetType().AssemblyQualifiedName; info.Title = p_win.Title; info.Icon = p_win.Icon.ToString(); if (p_win.Params != null) { info.Params = JsonSerializer.Serialize(p_win.Params, JsonOptions.UnsafeSerializer); info.ParamsType = p_win.Params.GetType().AssemblyQualifiedName; } AtState.SaveAutoStart(info); Kit.Msg(string.Format("{0}已设置自启动!", p_win.Title)); }
/// <summary> /// 获取用户可访问的菜单 /// </summary> /// <returns></returns> static async Task <List <long> > GetAllUserMenus() { int cnt = AtState.GetScalar <int>("select count(*) from DataVersion where id='menu'"); if (cnt == 0) { // 查询服务端 Dict dt = await AtCm.GetMenus(Kit.UserID); // 记录版本号 var ver = new DataVersion(ID: "menu", Ver: dt.Str("ver")); await AtState.Save(ver, false); // 清空旧数据 AtState.Exec("delete from UserMenu"); // 插入新数据 var ls = (List <long>)dt["result"]; if (ls != null && ls.Count > 0) { List <Dict> dts = new List <Dict>(); foreach (var id in ls) { dts.Add(new Dict { { "id", id } }); } AtState.BatchExec("insert into UserMenu (id) values (:id)", dts); } return(ls); } return(AtState.FirstCol <long>("select id from UserMenu")); }
void OnUploadFinished(object sender, bool suc) { if (suc) { AtState.SaveCookie("FileTransDemo", _fl.Data); } }
void OnDelMsg(object sender, Mi e) { var l = (Letter)e.DataContext; AtState.Exec($"delete from Letter where ID={l.ID}"); _lv.Data.Remove(l); }
/// <summary> /// 分页加载信息 /// </summary> /// <param name="e"></param> void OnNextPage(PageData e) { int cnt = AtState.GetScalar <int>("select count(*) from Letter where otherid=@otherid and loginid=@loginid", new Dict { { "otherid", OtherID }, { "loginid", Kit.UserID } }); int start = cnt - (e.PageNo + 1) * e.PageSize; int limit = e.PageSize; if (start < 0) { limit = cnt - e.PageNo * e.PageSize; } Nl <Letter> data = new Nl <Letter>(); var ls = AtState.Each <Letter>($"select * from Letter where otherid={OtherID} and loginid={Kit.UserID} order by stime limit {limit} offset {start}"); foreach (var l in ls) { var photo = l.IsReceived ? _other.Photo : Kit.UserPhoto; if (string.IsNullOrEmpty(photo)) { photo = "photo/profilephoto.jpg"; } l.Photo = photo; data.Add(l); } e.LoadPageData(data); }
/// <summary> /// 加载信息 /// </summary> async void LoadMsg() { if (OtherID < 0) { return; } string sql = $"select * from ChatMember where id={OtherID}"; _other = AtState.First <ChatMember>(sql); if (_other == null) { // 初次打开,还未下载好友列表 await FriendMemberList.Refresh(); _other = AtState.First <ChatMember>(sql); // 不在好友列表时,创建虚拟 if (_other == null) { _other = new ChatMember( ID: OtherID, Name: OtherID.ToString(), Photo: "photo/profilephoto.jpg"); } } // 不是好友时无法发送 //_inputBar.Visibility = (_other == null) ? Visibility.Collapsed : Visibility.Visible; LetterManager.ClearUnreadFlag(OtherID); _lv.PageData = new PageData { NextPage = OnNextPage, InsertTop = true }; }
/// <summary> /// 更新好友列表,默认超过10小时需要刷新 /// </summary> /// <returns></returns> public static async Task Refresh() { if (!NeedRefresh()) { return; } // 暂时取所有,后续增加好友功能 var tbl = await new UnaryRpc( "cm", "Da.Query", "select id,name,phone,sex,(case photo when '' then 'photo/profilephoto.jpg' else photo end) as photo, mtime from cm_user" ).Call <Table <ChatMember> >(); // 将新列表缓存到本地库 AtState.Exec("delete from ChatMember"); if (tbl != null && tbl.Count > 0) { foreach (var r in tbl) { r.IsAdded = true; } await AtState.BatchSave(tbl, false); } // 记录刷新时间 AtState.SaveCookie(_refreshKey, Kit.Now.ToString()); }
void LoadHisItems() { var his = AtState.Each <SearchFvHis>($"select * from SearchFvHis where BaseUri='{_baseUri}' order by id desc"); foreach (var item in his) { Grid grid = new Grid(); grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); grid.DataContext = item; Button btn = new Button { Content = item.Content, HorizontalAlignment = HorizontalAlignment.Stretch, HorizontalContentAlignment = HorizontalAlignment.Left }; btn.Click += OnClickHis; grid.Children.Add(btn); btn = new Button { Content = "\uE009", Style = Res.字符按钮 }; btn.Click += OnDelHis; Grid.SetColumn(btn, 1); grid.Children.Add(btn); Items.Add(grid); } }
void OnClearHis(object sender, RoutedEventArgs e) { using (Items.Defer()) { RemoveAllHis(); } AtState.Exec($"delete from SearchFvHis where BaseUri='{_baseUri}'"); }
/// <summary> /// 恢复默认布局 /// 1. 删除状态库的历史布局 /// 2. 加载最初布局 /// </summary> public void LoadDefaultLayout() { if (AllowSaveLayout()) { AtState.Exec($"delete from DockLayout where BaseUri=\"{_owner.BaseUri.AbsolutePath}\""); } ApplyLayout(_default); _owner.AllowResetLayout = false; }
async void OnLocalDel(object sender, Mi e) { if (await Kit.Confirm("确认要删除码?")) { if (await AtState.Delete((ClientLog)_fv1.Data)) { _fv1.Data = null; } } }
static bool NeedRefresh() { // 超过10小时需要刷新 bool refresh = true; string val = AtState.GetCookie(_refreshKey); if (!string.IsNullOrEmpty(val) && DateTime.TryParse(val, out var last)) { refresh = (Kit.Now - last).TotalHours >= 10; } return(refresh); }
async void OnLocalSave(object sender, Mi e) { if (await AtState.Save((ClientLog)_fv1.Data, false)) { _fv1.AcceptChanges(); Kit.Msg("本地库保存成功!"); } else { Kit.Msg("本地库保存失败!"); } }
/// <summary> /// 接收服务器推送的聊天信息 /// </summary> /// <param name="p_letter"></param> internal static async void ReceiveLetter(LetterInfo p_letter) { if (p_letter == null || string.IsNullOrEmpty(p_letter.ID)) { return; } // 撤回消息 if (p_letter.LetterType == LetterType.Undo) { var letter = AtState.First <Letter>("select * from Letter where MsgID=@msgid and LoginID=@loginid and IsReceived=1", new Dict { { "msgid", p_letter.ID }, { "loginid", Kit.UserID } }); if (letter != null) { // 删除 AtState.Exec($"delete from Letter where ID={letter.ID}"); UndoLetter?.Invoke(letter); } return; } // 新消息 Letter l = new Letter( LoginID: Kit.UserID, MsgID: p_letter.ID, OtherID: p_letter.SenderID, OtherName: p_letter.SenderName, LetterType: p_letter.LetterType, Content: p_letter.Content, STime: p_letter.SendTime, IsReceived: true, Unread: true); // 自增主键插入后自动赋值 await AtState.Save(l, false); // 外部可修改 Unread 状态 NewLetter?.Invoke(l); if (l.Unread) { // 外部未读提示 StateChanged?.Invoke(l.OtherID); ShowUnreadNotify(l); } else { // Unread状态被修改 await AtState.Save(l, false); } }
void OnQueryLocal(object sender, Mi e) { Table tbl = AtState.Query("select * from ClientLog limit 1"); if (tbl.Count > 0) { _fv1.Data = tbl[0]; } else { Kit.Msg("本地库无数据!"); } }
/// <summary> /// 注销后重新登录 /// </summary> public async void Logout() { // 先停止接收,再清空用户信息 PushHandler.StopRecvPush(); // 注销时清空用户信息 Kit.ResetUser(); AtState.DeleteCookie("LoginPhone"); AtState.DeleteCookie("LoginPwd"); await Kit.Stub.OnLogout(); Startup.ShowLogin(false); }
public FileListDemo() { InitializeComponent(); var xml = AtState.GetCookie("FileTransDemo"); if (!string.IsNullOrEmpty(xml)) { _fl.Data = xml; } else { // Fsm中的测试文件 _fl.Data = "[[\"photo/1.jpg\",\"1\",\"300 x 300 (.jpg)\",49179,\"daoting\",\"2020-03-13 10:37\"],[\"photo/Logon.wav\",\"Logon\",\"00:04\",384496,\"daoting\",\"2020-03-13 10:37\"],[\"photo/mov.mp4\",\"mov\",\"00:00:10 (320 x 176)\",788493,\"daoting\",\"2020-03-13 10:37\"],[\"photo/profilephoto.jpg\",\"profilephoto\",\"300 x 300 (.jpg)\",17891,\"daoting\",\"2020-03-13 10:37\"],[\"photo/文本文档.txt\",\"文本文档\",\"txt文件\",8,\"daoting\",\"2020-03-13 10:37\"],[\"photo/项目文档.docx\",\"项目文档\",\"docx文件\",13071,\"daoting\",\"2020-03-13 10:37\"],[\"photo/mov.mp4\",\"mov\",\"00:00:10 (320 x 176)\",788493,\"daoting\",\"2020-03-13 10:37\"]]"; } }
async void SaveCookie(string p_text) { _lastText = p_text; // 删除重复 AtState.Exec($"delete from SearchFvHis where BaseUri='{_baseUri}' and Content='{p_text}'"); SearchFvHis his = new SearchFvHis(BaseUri: _baseUri, Content: p_text); await AtState.Save(his, false); using (Items.Defer()) { RemoveAllHis(); LoadHisItems(); } }
/// <summary> /// 保存当前布局 /// </summary> public void SaveCurrentLayout() { // 宽度小时不保存 if (!AllowSaveLayout()) { return; } Kit.RunAsync(() => { DockLayout cookie = new DockLayout(_owner.BaseUri.AbsolutePath, WriteXml()); AtState.Save(cookie, false); _owner.AllowResetLayout = true; }); }
/// <summary> /// Phone模式附加标题右键菜单 /// </summary> /// <param name="p_elem">标题元素</param> /// <param name="p_win">所属窗口</param> public static void OnPhoneTitleTapped(FrameworkElement p_elem, Win p_win) { if (p_elem == null || p_win == null) { return; } p_elem.RightTapped += (s, e) => { if (_menu == null) { _menu = new Menu { IsContextMenu = true, Placement = MenuPosition.BottomLeft }; var item = new Mi { ID = "取消自启动" }; item.Click += (o, a) => Startup.DelAutoStart(); _menu.Items.Add(item); item = new Mi { ID = "设置自启动" }; item.Click += SetAutoStart; _menu.Items.Add(item); item = new Mi { ID = "系统监视" }; item.Click += (o, a) => SysTrace.ShowBox(); _menu.Items.Add(item); } var autoStart = AtState.GetAutoStart(); if (autoStart != null && autoStart.WinType == p_win.GetType().AssemblyQualifiedName && (p_win.Params == null || autoStart.Params == JsonSerializer.Serialize(p_win.Params, JsonOptions.UnsafeSerializer))) { _menu.Items[0].Visibility = Visibility.Visible; _menu.Items[1].Visibility = Visibility.Collapsed; } else { _menu.Items[0].Visibility = Visibility.Collapsed; _menu.Items[1].Visibility = Visibility.Visible; _currentWin = p_win; } _ = _menu.OpenContextMenu(default, p_elem);
public async Task ShowDlg(long p_fromUserID) { if (Kit.IsPhoneUI) { HideTitleBar = true; } else { IsPinned = true; SetSize(600, -60); } _other = AtState.First <ChatMember>($"select * from ChatMember where id={p_fromUserID}"); _tbInfo.Text = $"[{_other.Name}] 邀请您视频通话..."; await ShowAsync(); }
void OnDelHis(object sender, RoutedEventArgs e) { SearchFvHis his = (SearchFvHis)((Button)sender).DataContext; if (AtState.Exec($"delete from SearchFvHis where BaseUri='{_baseUri}' and Content='{his.Content}'") == 1) { for (int i = _hisStart; i < Items.Count; i++) { if (((Button)sender).DataContext == Items[i].DataContext) { Items.RemoveAt(i); break; } } } }
async void OnReset(object sender, Mi e) { int cntFixed = Kit.Stub.FixedMenus == null ? 0 : Kit.Stub.FixedMenus.Count; if (MenuKit.FavMenus.Count > cntFixed) { var cnt = AtState.Exec($"delete from menufav where userid={Kit.UserID}"); if (cnt > 0) { await MenuKit.LoadMenus(); _lv.Data = MenuKit.RootPageMenus; e.Visibility = Visibility.Collapsed; Kit.Msg("重置常用菜单成功!"); } } }
/// <summary> /// 清除和某人的未读消息状态 /// </summary> /// <param name="p_otherid">对方标识</param> public static void ClearUnreadFlag(long p_otherid) { Kit.RunAsync(() => { int cnt = AtState.Exec("update Letter set unread=0 where otherid=@otherid and loginid=@loginid and unread=1", new Dict { { "otherid", p_otherid }, { "loginid", Kit.UserID } }); if (cnt > 0) { StateChanged?.Invoke(p_otherid); } }); }
/// <summary> /// 按默认流程启动: /// 1. 更新打开模型库 /// 2. 已登录过,先自动登录 /// 3. 未登录或登录失败时,根据 p_loginFirst 显示登录页或主页 /// </summary> /// <param name="p_loginFirst">是否强制先登录</param> /// <returns></returns> public static async Task Run(bool p_loginFirst) { // 更新打开模型库 if (!await OpenModelDb()) { return; } string phone = AtState.GetCookie("LoginPhone"); string pwd = AtState.GetCookie("LoginPwd"); if (!string.IsNullOrEmpty(phone) && !string.IsNullOrEmpty(pwd)) { // 自动登录 var result = await new UnaryRpc( _svcName, "Entry.LoginByPwd", phone, pwd ).Call <LoginResult>(); // 登录成功 if (result.IsSuc) { Kit.InitUser(result); // 切换到主页 ShowHome(); // 接收服务器推送 PushHandler.Register(); return; } } // 未登录或登录失败 if (p_loginFirst) { // 强制先登录 ShowLogin(false); } else { // 未登录先显示主页 ShowHome(); } }
/// <summary> /// 打开菜单项窗口,可以由点击菜单项或直接代码构造Menu的方式调用 /// </summary> /// <param name="p_menu">OmMenu实例</param> /// <returns>返回打开的窗口或视图,null表示打开失败</returns> public static object OpenMenu(OmMenu p_menu) { if (p_menu == null) { Kit.Msg("打开菜单项不可为空!"); return(null); } Type tp = Kit.GetViewType(p_menu.ViewName); if (tp == null) { Kit.Msg(string.Format("打开菜单时未找到视图【{0}】!", p_menu.ViewName)); return(null); } Icons icon; Enum.TryParse(p_menu.Icon, out icon); object win = Kit.OpenWin(tp, p_menu.Name, icon, string.IsNullOrEmpty(p_menu.Params) ? null : p_menu.Params); // 保存点击次数,用于确定哪些是收藏菜单 if (win != null) { Task.Run(() => { if (AtModel.GetScalar <int>($"select count(id) from ommenu where id=\"{p_menu.ID}\"") > 0) { // 点击次数保存在客户端 Dict dt = new Dict(); dt["userid"] = Kit.UserID; dt["menuid"] = p_menu.ID; int cnt = AtState.Exec("update menufav set clicks=clicks+1 where userid=:userid and menuid=:menuid", dt); if (cnt == 0) { AtState.Exec("insert into menufav (userid, menuid, clicks) values (:userid, :menuid, 1)", dt); } } // 收集使用频率 //await AtAuth.ClickMenu(p_menu.ID); }); } return(win); }
//************************************************************************** // 响应式设计:三种布局方式对应三种界面宽度 // 1. 界面宽度 <= 640px,PhoneUI模式,4"到6"设备 或 缩小的窗口,只一列面板 // 2. 界面宽度在 641px ~ 1007px,7"到12"设备 或 缩小的窗口,最多两列面板 // 3. 界面宽度 >= 1008px,13"及更大设备,最多三列面板 //************************************************************************** /// <summary> /// Win宽度变化时自动调整 /// </summary> /// <param name="p_width"></param> public void OnWidthChanged(double p_width) { double width = 0; int index = -1; for (int i = 0; i < _colsWidth.Count; i++) { width += _colsWidth[i]; if (width > p_width) { index = i; break; } } if (_fitCols == index) { return; } _fitCols = index; if (_fitCols == -1) { // 宽度足够,加载历史布局或默认布局 DockLayout cookie; if (AllowSaveLayout() && (cookie = AtState.First <DockLayout>($"select * from DockLayout where BaseUri=\"{_owner.BaseUri.AbsolutePath}\"")) != null && ApplyLayout(cookie.Layout)) { _owner.AllowResetLayout = true; } else { ApplyLayout(_default); _owner.AllowResetLayout = false; } } else { // 自动隐藏两侧 ApplyAutoHide(); _owner.AllowResetLayout = false; } }
/// <summary> /// 撤回发出的消息 /// </summary> /// <param name="p_letter">待撤消息</param> /// <returns></returns> public static async Task <bool> SendUndoLetter(Letter p_letter) { if (p_letter == null) { return(false); } LetterInfo li = new LetterInfo { ID = p_letter.MsgID, SenderID = Kit.UserID, SenderName = Kit.UserName, LetterType = LetterType.Undo, SendTime = Kit.Now }; await AtMsg.SendLetter(p_letter.OtherID, li); AtState.Exec($"delete from Letter where ID={p_letter.ID}"); return(true); }
/// <summary> /// 发送聊天信息 /// </summary> /// <param name="p_recvID"></param> /// <param name="p_recvName"></param> /// <param name="p_content"></param> /// <param name="p_type"></param> /// <returns></returns> public static async Task <Letter> SendLetter( long p_recvID, string p_recvName, string p_content, LetterType p_type) { Throw.IfNullOrEmpty(p_content); LetterInfo li = new LetterInfo { ID = Kit.NewGuid, SenderID = Kit.UserID, SenderName = Kit.UserName, LetterType = p_type, Content = p_content, SendTime = Kit.Now }; bool isOnline = await AtMsg.SendLetter(p_recvID, li); // 本地记录 Letter l = new Letter( LoginID: Kit.UserID, MsgID: li.ID, OtherID: p_recvID, OtherName: p_recvName, OtherIsOnline: isOnline, IsReceived: false, Unread: false, LetterType: p_type, Content: p_content, STime: li.SendTime); // 自增主键插入后自动赋值 await AtState.Save(l, false); NewLetter?.Invoke(l); return(l); }