.NetCore登入功能生成验证码

生成验证码

每一个.NetCore Web项目必不可少的就是登入注册功能,通常登入界面都会有一张验证码图片,只有根据图片输入验证码才能登入成功。验证码的主要功能就是验证操作者是人而非机器人,目的就是防止机器人暴力破解。

1、随机验证码

生成验证码,首先验证码的内容肯定是随机的。每次生成的内容都不相同。

.NetCore随机生成验证码代码示例如下:

string Letters = "1,2,3,4,5,6,7,8,9,0,A,B,C,D,E,F,G,H,I,H,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
var array = Letters.Split(",");
var random = new Random();
string code= "";
for(int i = 0; i < 4; i++)
{
    code+= array[random.Next(array.Length)];
}

以上代码是生成字母与数字随机组合的4位验证码,使用的就是Random随机数。

2、验证码画图

获取到随机生成的验证码内容后,就需要根据验证码内容生成图片。而.NetCore数据画图有三种方式。
System.Drawing.Common、SkiaSharp以及ImageSharp

2.1、System.Drawing.Common

使用System.Drawing.Common数据画图代码如下

public byte[] GetCodeImage(string captchaCode)
        {
            //验证码颜色集合
            Color[] c = {Color.MediumAquamarine,Color.MediumBlue,Color.MediumOrchid,Color.MediumPurple,Color.MediumSeaGreen,Color.MediumSlateBlue,
            Color.MediumSpringGreen,Color.Maroon,Color.MediumTurquoise,Color.MidnightBlue,Color.MintCream,Color.MistyRose,
            Color.Moccasin,Color.NavajoWhite,Color.Navy,Color.OldLace,Color.MediumVioletRed,Color.Magenta,Color.Linen,Color.LimeGreen,
            Color.LavenderBlush,Color.LawnGreen,Color.LemonChiffon,Color.LightBlue,Color.LightCoral,Color.LightGoldenrodYellow,
            Color.LightGreen,Color.LightPink,Color.LightSalmon,Color.LightSeaGreen,Color.LightSkyBlue,Color.LightSteelBlue,Color.LightYellow,
            Color.Lime,Color.Olive,Color.OliveDrab,Color.Orange,Color.OrangeRed,Color.Silver,Color.SkyBlue,Color.SlateBlue,
            Color.Snow,Color.SpringGreen,Color.SteelBlue,Color.Tan,Color.Teal,Color.Thistle,Color.Tomato,Color.Transparent,
            Color.Turquoise,Color.Violet,Color.Wheat,Color.White,Color.WhiteSmoke,Color.Sienna,Color.Lavender,Color.SeaShell,
            Color.SandyBrown,Color.Orchid,Color.PaleGoldenrod,Color.PaleGreen,Color.PaleTurquoise,Color.PaleVioletRed,Color.PapayaWhip,
            Color.PeachPuff,Color.Peru,Color.Pink,Color.Plum,Color.PowderBlue,Color.Purple,Color.Red,Color.RosyBrown,Color.RoyalBlue,Color.SaddleBrown,
            Color.Salmon,Color.SeaGreen,Color.Yellow,Color.Khaki,Color.Cyan,Color.DarkMagenta,Color.DarkKhaki,Color.DarkGreen,Color.DarkGoldenrod,
            Color.DarkCyan,Color.DarkBlue,Color.Ivory,Color.Crimson,Color.Cornsilk,Color.CornflowerBlue,Color.Coral,Color.Chocolate,
            Color.DarkOliveGreen,Color.Chartreuse,Color.BurlyWood,Color.Brown,Color.BlueViolet,Color.Blue,Color.BlanchedAlmond,
            Color.Black,Color.Bisque,Color.Beige,Color.Azure,Color.Aquamarine,Color.Aqua,Color.AntiqueWhite,Color.AliceBlue,Color.CadetBlue,
            Color.DarkOrange,Color.YellowGreen,Color.DarkRed,Color.Indigo,Color.IndianRed,Color.DarkOrchid,Color.Honeydew,Color.GreenYellow,
            Color.Green,Color.Goldenrod,Color.Gold,Color.GhostWhite,Color.Gainsboro,Color.Fuchsia,Color.ForestGreen,Color.HotPink,Color.Firebrick,
            Color.FloralWhite,Color.DodgerBlue,Color.DeepSkyBlue,Color.DeepPink,Color.DarkViolet,Color.DarkTurquoise,Color.DarkSlateBlue,
            Color.DarkSeaGreen,Color.DarkSalmon};

            //验证码字体集合
            string[] fonts = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial" };

            //定义图像的大小,生成图像的实例
            var image = new Bitmap(140, 50);
			// 画图
            var g = Graphics.FromImage(image);
            // 背景色
            g.Clear(Color.LightGray);
            // 随机
            var random = new Random();
			// 干扰
            for (var i = 0; i < 6; i++)
            {
            	// 干扰点
                //var x = random.Next(image.Width);
                //var y = random.Next(image.Height);
                //g.DrawRectangle(new Pen(Color.LightGray, 0), x, y, 1, 1);
                
                // 干扰线
                g.DrawLine(new Pen(c[random.Next(c.Length)], 4), new Point(random.Next(140), random.Next(50)), new Point(random.Next(140), random.Next(50)));
            }

            //验证码绘制在g中
            for (var i = 0; i < captchaCode.Length; i++)
            {
                //随机颜色索引值
                var cindex = random.Next(c.Length);

                //随机字体索引值
                var findex = random.Next(fonts.Length);

                //字体
                var f = new Font(fonts[findex], 30, FontStyle.Italic);

                //颜色  
                Brush b = new SolidBrush(c[cindex]);
                //绘制一个验证字符  
                g.DrawString(captchaCode.Substring(i, 1), f, b, i * 32 + 1, 1);
            }

            var ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);

            g.Dispose();
            image.Dispose();
            return ms.ToArray();
        }

以上代码中captchaCode为随机验证码变量。返回的结果为图片Byte数组。

2.2、SkiaSharp

使用SkiaSharp数据画图代码如下:

        public byte[] GetCodeImage(string captchaText, int width = 140, int height = 50, int lineNum = 4, int lineStrookeWidth = 2)
        {
        	// 颜色集合
        	List<SKColor> colors = new List<SKColor>();
            colors.Add(SKColors.AliceBlue);
            colors.Add(SKColors.PaleGreen);
            colors.Add(SKColors.PaleGoldenrod);
            colors.Add(SKColors.Orchid);
            colors.Add(SKColors.OrangeRed);
            colors.Add(SKColors.Orange);
            colors.Add(SKColors.OliveDrab);
            colors.Add(SKColors.Olive);
            colors.Add(SKColors.OldLace);
            colors.Add(SKColors.Navy);
            colors.Add(SKColors.NavajoWhite);
            colors.Add(SKColors.Moccasin);
            colors.Add(SKColors.MistyRose);
            colors.Add(SKColors.MintCream);
            colors.Add(SKColors.MidnightBlue);
            colors.Add(SKColors.MediumVioletRed);
            colors.Add(SKColors.MediumTurquoise);
            colors.Add(SKColors.MediumSpringGreen);
            colors.Add(SKColors.LightSteelBlue);
            colors.Add(SKColors.LightYellow);
            colors.Add(SKColors.Lime);
            colors.Add(SKColors.LimeGreen);
            colors.Add(SKColors.Linen);
            colors.Add(SKColors.PaleTurquoise);
            colors.Add(SKColors.Magenta);
            colors.Add(SKColors.MediumAquamarine);
            colors.Add(SKColors.MediumBlue);
            colors.Add(SKColors.MediumOrchid);
            colors.Add(SKColors.MediumPurple);
            colors.Add(SKColors.MediumSeaGreen);
            colors.Add(SKColors.MediumSlateBlue);
            colors.Add(SKColors.Maroon);
            colors.Add(SKColors.PaleVioletRed);
            colors.Add(SKColors.PapayaWhip);
            colors.Add(SKColors.PeachPuff);
            colors.Add(SKColors.Snow);
            colors.Add(SKColors.SpringGreen);
            colors.Add(SKColors.SteelBlue);
            colors.Add(SKColors.Tan);
            colors.Add(SKColors.Teal);
            colors.Add(SKColors.Thistle);
            colors.Add(SKColors.Tomato);
            colors.Add(SKColors.Violet);
            colors.Add(SKColors.Wheat);
            colors.Add(SKColors.White);
            colors.Add(SKColors.WhiteSmoke);
            colors.Add(SKColors.Yellow);
            colors.Add(SKColors.YellowGreen);
            colors.Add(SKColors.Turquoise);
            colors.Add(SKColors.LightSkyBlue);
            colors.Add(SKColors.SlateBlue);
            colors.Add(SKColors.Silver);
            colors.Add(SKColors.Peru);
            colors.Add(SKColors.Pink);
            colors.Add(SKColors.Plum);
            colors.Add(SKColors.PowderBlue);
            colors.Add(SKColors.Purple);
            colors.Add(SKColors.Red);
            colors.Add(SKColors.SkyBlue);
            colors.Add(SKColors.RosyBrown);
            colors.Add(SKColors.SaddleBrown);
            colors.Add(SKColors.Salmon);
            colors.Add(SKColors.SandyBrown);
            colors.Add(SKColors.SeaGreen);
            colors.Add(SKColors.SeaShell);
            colors.Add(SKColors.Sienna);
            colors.Add(SKColors.RoyalBlue);
            colors.Add(SKColors.LightSeaGreen);
            colors.Add(SKColors.LightSalmon);
            colors.Add(SKColors.LightPink);
            colors.Add(SKColors.Crimson);
            colors.Add(SKColors.Cyan);
            colors.Add(SKColors.DarkBlue);
            colors.Add(SKColors.DarkCyan);
            colors.Add(SKColors.DarkGoldenrod);
            colors.Add(SKColors.DarkGray);
            colors.Add(SKColors.Cornsilk);
            colors.Add(SKColors.DarkGreen);
            colors.Add(SKColors.DarkMagenta);
            colors.Add(SKColors.DarkOliveGreen);
            colors.Add(SKColors.DarkOrange);
            colors.Add(SKColors.DarkOrchid);
            colors.Add(SKColors.DarkRed);
            colors.Add(SKColors.DarkSalmon);
            colors.Add(SKColors.DarkKhaki);
            colors.Add(SKColors.DarkSeaGreen);
            colors.Add(SKColors.CornflowerBlue);
            colors.Add(SKColors.Chocolate);
            colors.Add(SKColors.AntiqueWhite);
            colors.Add(SKColors.Aqua);
            colors.Add(SKColors.Aquamarine);
            colors.Add(SKColors.Azure);
            colors.Add(SKColors.Beige);
            colors.Add(SKColors.Bisque);
            colors.Add(SKColors.Coral);
            colors.Add(SKColors.Black);
            colors.Add(SKColors.Blue);
            colors.Add(SKColors.BlueViolet);
            colors.Add(SKColors.Brown);
            colors.Add(SKColors.BurlyWood);
            colors.Add(SKColors.CadetBlue);
            colors.Add(SKColors.Chartreuse);
            colors.Add(SKColors.BlanchedAlmond);
            colors.Add(SKColors.Transparent);
            colors.Add(SKColors.DarkSlateBlue);
            colors.Add(SKColors.DarkTurquoise);
            colors.Add(SKColors.IndianRed);
            colors.Add(SKColors.Indigo);
            colors.Add(SKColors.Ivory);
            colors.Add(SKColors.Khaki);
            colors.Add(SKColors.Lavender);
            colors.Add(SKColors.LavenderBlush);
            colors.Add(SKColors.HotPink);
            colors.Add(SKColors.LawnGreen);
            colors.Add(SKColors.LightBlue);
            colors.Add(SKColors.LightCoral);
            colors.Add(SKColors.LightCyan);
            colors.Add(SKColors.LightGoldenrodYellow);
            colors.Add(SKColors.LightGreen);
            colors.Add(SKColors.LemonChiffon);
            colors.Add(SKColors.Honeydew);
            colors.Add(SKColors.Green);
            colors.Add(SKColors.DarkViolet);
            colors.Add(SKColors.DeepPink);
            colors.Add(SKColors.DeepSkyBlue);
            colors.Add(SKColors.DimGray);
            colors.Add(SKColors.DodgerBlue);
            colors.Add(SKColors.Firebrick);
            colors.Add(SKColors.GreenYellow);
            colors.Add(SKColors.FloralWhite);
            colors.Add(SKColors.Fuchsia);
            colors.Add(SKColors.Gainsboro);
            colors.Add(SKColors.GhostWhite);
            colors.Add(SKColors.Gold);
            colors.Add(SKColors.Goldenrod);
            colors.Add(SKColors.ForestGreen);
            //创建bitmap位图
            using (SKBitmap image2d = new SKBitmap(width, height, SKColorType.Bgra8888, SKAlphaType.Premul))
            {
                //创建画笔
                using (SKCanvas canvas = new SKCanvas(image2d))
                {
                    //填充背景颜色
                    canvas.DrawColor(SKColors.LightGray);
                    var array = captchaText.ToArray();
                    Random random = new Random();
                    for(int i = 0; i < array.Length; i++)
                    {
                        //将文字写到画布上
                        using (SKPaint drawStyle = CreatePaint(random.Next(colors.Count), height))
                        {
                            canvas.DrawText(array[i].ToString(), i*32+1, height - 1, drawStyle);
                        }
                    }
                    //画随机干扰线
                    using (SKPaint drawStyle = new SKPaint())
                    {

                        for (int i = 0; i < lineNum; i++)
                        {
                            drawStyle.Color = colors[random.Next(colors.Count)];
                            drawStyle.StrokeWidth = lineStrookeWidth;
                            canvas.DrawLine(random.Next(0, width), random.Next(0, height), random.Next(0, width), random.Next(0, height), drawStyle);
                        }
                    }
                    //返回图片byte
                    using (SKImage img = SKImage.FromBitmap(image2d))
                    {
                        using (SKData p = img.Encode(SKEncodedImageFormat.Jpeg, 100))
                        {
                            return p.ToArray();
                        }
                    }
                }
            }
        }
		// 创建画笔
		private SKPaint CreatePaint(int colorNo, float fontSize)
        {
            SKTypeface font = SKTypeface.FromFamilyName("微软雅黑", 16, 16, SKFontStyleSlant.Italic);
            SKPaint paint = new SKPaint();
            paint.IsAntialias = true;
            paint.Color = colors[colorNo];
            paint.Typeface = font;
            paint.TextSize = fontSize;
            return paint;
        }

SkiaSharp代码与System.Drawing.Common逻辑上一致,所以代码很相似。

2.3、ImageSharp

ImageSharp与SkiaShar一致,使用一个即可。

3、保存与返回

获取到图片的Byte数组后,随机生成一个Key,将Key与验证码内容保存至Redis中。再将Key与Byte数组返回致前端。

随机生成Key可使用当前时间戳与随机字符结合。不重复即可。Guid也可
存入Redis可设置一个有效期,建议有效期单位为分钟。

存入Redis参考代码如下:

			// 从配置文件中读取Redis连接字符串
			RedisHelper redisHelper = new RedisHelper(ConfigHelper.GetConfig("RedisConn"));
			// 设置redis数据库
            redisHelper.SetDb(2);
            // 生成Key
            DateTimeOffset dateTimeOffset = new DateTimeOffset(DateTime.Now);
            long mills = dateTimeOffset.ToUnixTimeMilliseconds();
            Random random = new Random();
            string indeCode = "Identity" + mills + random.Next(10) + random.Next(10) + random.Next(10) + random.Next(10);
            // 存入Redis 有效期5分钟
            bool flag = redisHelper.SetValueMinute(indeCode, code, 5);
            if (flag)
            {
                return indeCode;
            }
            else
            {
                throw new Exception("存入Redis失败");
            }
			

RedisHelper代码:

	public class RedisHelper
    {
        private ConnectionMultiplexer redis { get; set; }
        private IDatabase db { get; set; }
        public RedisHelper(string connection)
        {
            redis = ConnectionMultiplexer.Connect(connection);
        }
        /// <summary>
        /// 修改redis数据库
        /// </summary>
        /// <param name="i"></param>
        public void SetDb(Int32 i)
        {
            db = redis.GetDatabase(i);
        }
        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool SetValue(string key, string value)
        {
            return db.StringSet(key, value);
        }
        /// <summary>
        /// 保存且附带到期时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="min"></param>
        /// <returns></returns>
        public bool SetValueMinute(string key,string value,int min)
        {
            return db.StringSet(key, value, new TimeSpan(TimeSpan.TicksPerMinute * min));
        }
        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetValue(string key)
        {
            return db.StringGet(key);
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteKey(string key)
        {
            return db.KeyDelete(key);
        }
	}

4、登入验证

登入时前端需将Key与前端输入的验证码都传入登入接口,登入接口需从Redis中根据Key查询相应的验证码内容,检查输入的验证码与对应的验证码内容是否匹配,只有匹配才可进行接下来的登入操作。

使用ReidsHelper中的GetValue方法即可。

5、所遇问题

System.Drawing.Common与SkiaSharp所写的代码,本地调试均可成功。

本地调试结果如下:
本地调试结果
转图片如下:
转图片
而将项目部署至Linux的Docker中,则都会出现问题。SkiaSharp所遇问题为之有干扰线,没有验证码内容。
在这里插入图片描述

System.Drawing.Common所遇问题是:
The type initializer for ‘Gdip‘ threw an exception

网上讲解:SkiaSharp遇到的问题是DrawText方法,将Text内容画到图片中,因为设置的Text字体是Windows中的字体,Linux中没有该字体。所以无法将验证码写入图片中。解决办法就是将Windows中的字体导入Linux中,即可。

而System.Drawing.Common遇到的报错原因是System.Drawing.Common是windows版本的动态库,导入该包时也有提醒。该依赖包只可在Windows中使用。解决方案就是在Linux中下载libgdiplus即可。

以上方案均尝试,无法解决对应的问题。
可能因为网络教程的.NetCore版本是3.1。而我使用的版本为5.0。(仅猜测)

而使用System.Drawing.Common的解决方案,可以解决SkiaSharp的问题。因为libgdiplus是附带字体与语言的。

6、部署方案

因为是使用Docker部署的,每次部署都会生成新的容器,而新容器中又没有libgdiplus。所有又需要重新下载libgdiplus。

只需项目运行依赖的netcore镜像中包含libgdiplus即可解决该问题,如何生成一个附带libgdiplus的镜像包。

操作步骤如下:

首先导入一个对应的Netcore基础镜像包。版本3.1或者5.0自定义

docker pull mcr.microsoft.com/dotnet/aspnet:5.0
docker pull mcr.microsoft.com/dotnet/core/aspnet:3.1

镜像
之后运行进入容器内部

docker run -it mcr.microsoft.com/dotnet/aspnet:5.0 /bin/bash
docker run -it mcr.microsoft.com/dotnet/core/aspnet:3.1 /bin/bash

进入容器后使用命令下载libgdiplus,该操作比较耗时

apt-get update -y
apt-get install -y libgdiplus
apt-get clean
ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll

下载完成后退出容器,使用docker ps -a查看容器ID。根据容器DI生成镜像

docker commit -a="simple" -m="added libgdiplus based on .netcore5.0" 容器ID dotnetcore-with-libgdiplus:v5.0

docker commit -a="simple" -m="added libgdiplus based on .netcore3.1" 容器ID dotnetcore-with-libgdiplus:v3.1

生成镜像后修改项目的DockerFile文件 即可

FROM dotnetcore-with-libgdiplus:v5.0 AS base
FROM dotnetcore-with-libgdiplus:v3.1 AS base

相关推荐

工作协作用邮件?易出错还效率低?看看这个工具靠谱吗?

现在技术部门开发了一个新工具,大家可以在上面上传文件和沟通,文件一到就会收到提醒。还可以在线讨论,实时修改内容,甚至轻松管理不同的版本。所有沟通内容和文件和都会自动保存,支持随时查看。找之前的讨论记录和文件要翻半天。这些问题让人既焦虑,又害怕出错。邮件里说的跟文件里写的有出入。还在用邮件进行工作协作?那真是容易出错又低效,哎。工作沟通协作不够及时。

DOCUVIX的博客 510

话说你们维保到期通知都是谁通知的

直接做一个维保合同到期自动提醒的工具。商务说运维部门应该到期给客户发通知,客户有无阅读、意见回复都能够知道。离谱了,公司有个客户维保到期了。可以直接转发到期通知给客户,客户也不愿意给这两个月钱。是为什么2个月都没人发现。现在商务和运维在扯皮,运维说商务到期要续签,说这不是谁通知的问题,

DOCUVIX的博客 328

大家觉得我这个产品点子怎样,能打造出爆品吗

你可以通过这个工具,随时将文件发送给客户、伙伴或同事的手机。各方人员可以针对这些材料进行沟通协作,事项完成后又成为经验与档案,为以后证据需要或员工培训服务,形成闭环。历史经验、模板、材料等各种文件,可以存在公司的共享文件库中。在业务有需要自动提醒你要用哪一些文件或版本。例如:项目经理给客户提供项目方案;维保团队给客户发到期通知;业务员给客户发送报价等等。现在都说B端市场还是蓝海,最近调研了一下,发现好像很少人做“文件收发管存”的产品。我们设想这样一个产品,大家看看能做爆款不?

DOCUVIX的博客 384

不想做报价了,怕报错,怕被同行套报价了?

我可以找IT部门做个工具,把报价模板公式和历史报价都存档进去,业务员直接查来用,然后在线发到客户手机上直接沟通,沟通过程和报价单我都可以线上把关。我公司新来的业务助理,她做报价做了一天。我还以为她在摸鱼😂,过去问她怎么回事。她才说今天加了一个客户,一直用命令式的口气要报价。然后她被催得紧张,又害怕报错,自己捣鼓了半天才做好发出去。但是报完价之后对方一直不回复,才发现已经被删了😂。是不是新人业务员都有害怕报错价,害怕被套价、不熟悉公式之类的问题?她说应该是被同行套价格了,所以也没敢告诉我。

DOCUVIX的博客 408

道可维斯受邀参加2024金蝶佛山生态峰会,助力企业财务共享建设

广州道可维斯借此机会,重点展示了经过长期市场验证的电子影像及会计档案综合解决方案。作为影像及档案管理综合解决方案提供商,广州道可维斯应邀参加了此次盛会。未来,广州道可维斯将继续倾听市场声音,不断优化产品体验,为更多追求稳定、可靠的企业提供值得信赖的解决方案。成熟可靠:道可维斯的影像及会计档案综合解决方案,已经在众多知名企业中长期应用,表现稳定可靠。在当前阶段,许多企业正在寻找既能跟上时代步伐,又不会带来太多风险和困扰的产品。简单易用:操作简便直观,用户友好,减少学习成本,适合各类用户。

DOCUVIX的博客 388

收款业务中的3大合规风险,你知道吗

随着国家政策监管日趋严格,企业合规管理正在受到高度关注。在企业收业务款场景中,银行回单管理容易被忽略,若处理不当,将面临合规风险。

DOCUVIX的博客 586

行政人事的日常丨如何优化企业知识资产管理?

小思能否最终实现成功的,企业知识资产管理呢?

DOCUVIX的博客 339

运维人的日常,不被理解的背后

小春总是尽最大努力在24小时内给客户一个满意的答复,她认为运维就是守护客户业务平稳、顺利进行。

DOCUVIX的博客 294

打破数据孤岛,实现文档数据互通

随着数字经济加速发展,企业数字化转型正向更深层次推进。非结构化数据量也正在飞速增长,这些数据以文档、图片、音频等形式散落在组织内部,这给数据的整理和统一利用增加了难度。由于部门、应用、框架、多云环境等原因形成非结构化数据孤岛。如何使数据规范统一、消除数据孤岛,并利用好这些已形成的数据源,为后续运营提供数据支撑,是多数企业目前亟待解决的问题。

DOCUVIX的博客 461

集团企业内部交易发票查重不通过?解决方法来了!

某地产是全国第一批成立的综合性房地产开发企业之一,目前旗下涵盖多个业务板块,包括住宅开发、物业服务、商业、长租、康养和教育。开启全国化布局后,进驻全国30个一线和强二线城市,开发大型住宅项目200多个,拥有包括广州国际金融中心在内的40多个大型商业物业。在某地产开启全国化布局时期,随着业务规模不断扩大,对企业管理能力要求越来越高,某地产进行数字化转型,并通过财务共享中心建设持续提升管控能力。近期,某地产逐步推进他版块公司财务共享上线,这些公司存在内部交易的情况,存在出现交易双方都上传同一张发票的情况。

DOCUVIX的博客 350

最新政策丨政务服务电子文件归档和电子档案管理办法说了什么?

这一办法的主要要点涵盖了政务服务电子文件的归档和电子档案的全流程管理。重要亮点包括电子档案的定义、归档范围、归档期限、管理要求、安全保障措施等方面。此举旨在通过全面规范政务服务电子档案的管理,推动政府数字化转型,提高政务服务质量。1. 电子档案的界定办法明确,电子档案是以数字化格式进行归档管理的各类政务服务文件,包括在政务服务活动中形成和调用的文字、图片、音视频等。这些电子档案与传统纸质档案一样,具有法律效力,可作为合法凭证。2. 电子档案归档范围。

DOCUVIX的博客 592

合规管理,企业生存之本!这4大方法,助你规避风险

当下,合规管理已成为企业必修的一门学问。无论是上市公司还是民营企业,都面临着日益严苛的监管合规要求。

DOCUVIX的博客 609

广州道可维斯受邀参加首届金蝶暨佛山数字化生态峰会

活动当日,道可维斯的客户成功中心主任梁健,做了以“企业内容管理3.0,助力企业合规成长”为主题的产品解决方案分享。她详细介绍了道可维斯最新推出的数字化产品矩阵,并通过多个客户成功案例解析,让与会者充分了解了道可维斯产品在实现企业数字化转型过程中的强大支撑作用和丰富实施经验。通过这次峰会,我们不仅加深了与行业领先企业的合作关系,也进一步拓展了战略合作网络。此次大会由金蝶软件集团主办,共有超150家软件行业企业莅临参与,共同探讨数字化行业的最新动态和趋势。

DOCUVIX的博客 386

一图读懂数电票丨发票新时代的机遇与挑战

数电票的应用,将有助于彻底解决现有业务流程中的发票管理环节存在的集中化和自动化难题。它将推动对发票的管理与企业的业务流程、法务工作、财务核算、税收管理、资金运作、成本控制、档案管理以及供应链管理等进行深度的数字化整合。这将全面提升企业的经营管理水平和运营效率,降低运营成本,为企业业务的快速发展提供强大支撑。根据数电票的新特性,发票管理、流程制度需要改变、发票相关的合规风险管理需要改变、对接数电票相关的软件需要改变等等,企业需要及时准备,以顺利安全、合规地应用数电票。关注我们,及时获取更多最新资讯。

DOCUVIX的博客 628

企业内容管理升级 3.0:构建生态协同,助力合规成长

企业内容管理3.0基于开放平台与生态理念,连接内外部系统,实现内容共享和协作。它打开了企业边界,释放内容价值,为企业带来机遇与收益。

DOCUVIX的博客 476

费报只是小 case!电子影像系统,工作效率up无限

电子影像系统的应用,使企业拥有强大的“记忆”和“联想”功能,各业务部门可随时调用相关信息,促进业务流程的高效协同。它构建起企业业务“神经网络”,帮助企业在信息海洋中找到自己需求的“记忆”,实现业务的高度智能化和数字化。

DOCUVIX的博客 607

深度解读新档案法①:企业如何提高档案管理规范性?

结合企业实践案例,详细解读档案管理的相关法规,帮助大家加强档案管理的规范性。

DOCUVIX的博客 1196

如何解决企业客户签收回执慢,缩短回款周期?

这意味着企业将面临着货款回收延迟,对企业的运营资金和现金流造成了影响。此外,对客户关系也会产生一定的影响,需要企业与客户进行沟通和协商,以维护客户关系。还给企业的财务管理带来一定的挑战,需要企业加强对账期和货款回收的管理和控制,以保证企业的财务稳健和可持续发展。

DOCUVIX的博客 1325

企业内容管理入门指南:从概念到实践,提升协作效率和质量

企业内容管理是企业信息化建设中非常重要的一环,可以帮助企业更好地管理和利用企业内部的各种数据和信息资源,提高协作效率和质量,降低风险,提升企业核心竞争力

DOCUVIX的博客 907

档案信息化建设,这份法律法规清单,请收好

为了推进档案管理的数字化落地,国家颁布了一系列法律法规和标准规范,当企业在进行档案信息化建设时,应遵循相应的法律法规,保障信息安全、规范档案管理、保障档案使用和保存。DA/T 18-2022 《档案著录规则》 DA/T 92-2022 《电子档案单套制管理一般要求》 DA/T 93-2022 《电子档案移交接收操作规程》针对电子档案和纸质档案要有检索关系,能够快速定位查询的要求,e企档案提供电子档案与纸质档案位置关联,通过搜索电子档案即可找到纸质档案的存放位置。已 经实现数字化的,应当对档案原件妥善保管。

DOCUVIX的博客 1023

PDM入门指南:一文带你了解PDM的基本知识

上一期,我们聊过PLM;这一期,我们接着聊聊PDM。在介绍之前,先回答之前客户提出的问题:上线PLM/PDM后,还需要e企拆图吗?可能需要,原因放在最后,有需要的朋友可直接跳到最后。我们先来聊聊什么是PDM?

DOCUVIX的博客 2778

什么是企业内容管理?

在时间就是金钱的今天,.对于分散在各个位置(邮件、各个业务系统、共享网盘等)、不同类型(业务流程、图纸、纸质文件、音视频等)的企业内容,如何能够在企业各部门之间、企业与供应商之间、企业与客户之间更快、更准确地传递与获得?费用报销解决方案、智能纸电对比解决方案、客户签收回执在线回传解决方案、影像中台解决方案、港口企业计费解决方案、供应商协同对账解决方案、实物收单系统解决方案、电子会计档案解决方案、电子档案借阅系统解决方案、全电子档案解决方案、自动识别图纸生成BOM解决方案。

DOCUVIX的博客 914

解决方案丨票据集中在集团总部处理,如何解决实物票据管理难?

解决实物票据从报销人员到分支机构到共享中心到档案室的全流程监控

DOCUVIX的博客 739

PLM听过很多遍,却依旧不知道是什么?看完这篇你就懂

PLM,是Product Lifecycle Management的缩写,代表的是产品全生命周期管理。产品生命周期最早是由经济领域提出,为了研究产品的市场战略,那时产品生命周期的划分按照产品在市场中的演化过程,分为推广、成长、成熟和衰亡阶段。后期,并行工程首次将产品生命周期的概念从经济管理领域扩展到研制阶段,真正提出了覆盖从产品需求分析、概念设计、详细设计、制造、销售、售后服务,直到产品报废回收全过程的产品生命周期的概念。

DOCUVIX的博客 979

订单交期迟滞,销售回应慢,怎么解决客户问题?

本文首发于“道可维斯”公号,订阅“道可维斯”公号,了解更多聚焦企业业务场景的数字化解决方案)按客户定制产品订单,进行报价和生产的制造企业,有拆解图纸生成物料BOM的工序,通常由企业产品设计部门的拆图员岗位专门负责。

DOCUVIX的博客 1076

道可维斯|益企行动,点亮星空数字化转型峰会

2023年,“烟火气”回归,但企业挑战仍在继续。找寻企业增长转型的内生动力,仍是中小企业不变的探索话题。如何寻找穿越周期的高成长机会?4月21日,佛山金蝶软件科技有限公司主办的主题为“益企行动,点亮星空”的数字化转型峰会,在佛山千灯湖酒店隆重举办。道可维斯一直深耕企业业务场景数字化,服务超200多家大中型集团企业。作为金蝶14年的战略合作伙伴,道可维斯受邀出席本次峰会活动。此次活动,道可维斯展出了最新产品e企拆图和e企档案解决方案,在展会现场广受欢迎。

DOCUVIX的博客 742

会计凭证管理难,怎么解决?

对于纸质档案,会计电子档案可以关联实物位置,支持业务人员快速检索、调阅,让档案利用更高效。法务在查阅电子材料时,还需要关联实物材料,但实物材料分散保管,法务需要与多个部门沟通,找到关联的纸质档案,沟通成本高,花费时间较长。会计电子档案与实物档案及位置进行关联,财务人员可以通过会计电子档案快速找到关联的电子档案,还可以根据实物关联,快速准确地找到纸质档案,完成审计。会计人员调账比较多,需要找到前置的单据、附件,但系统数据不互通,需要会计人员在不同的应用系统之间切换,耗时较长,效率较低。

DOCUVIX的博客 517

【休息吧,打工人】 让AI代替人工拆解图纸

3天的拆解图纸工作量,1天就完成!

DOCUVIX的博客 262

行业洞察丨非诉讼律师行业数字化转型痛点和解决方案

非诉讼律所如何加入数字化转型,优化企业业务服务,提升客户满意度,提高律所的竞争力?

DOCUVIX的博客 483

行业洞察丨小微企业信息化管理痛点与解决方案

从事商贸和服务业的老板和员工,对通过信息化和软件去管理企业业务的认知比较简单,应用比较离散。

DOCUVIX的博客 717
上一篇: 【ai研发日记】.net登录注册服务对接python进行百度人脸识别api的交互
下一篇: [AI研发日记]Centos安装TensorFlow2.1 cpu版本
道可维斯
道可维斯 广州道可维斯信息技术有限公司官方账号 广州道可维斯信息技术有限公司官方账号
博客等级 码龄8年 28粉丝 92原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值