% 从fduthesis.dtx中抽取的
% 排版论文封面作者信息栏的代码
\documentclass{ctexbook}

% 导言区
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn
% 获取文本长度函数，#1用于保存长度，#2是被检测的文字
\cs_new:Npn \l_get_text_width:Nn #1#2
  {
    % 将文字内容存入变量
    \hbox_set:Nn \l_tmpa_box {#2}
    % 用\box_wd:N函数获取盒子宽度，并存入长度变量
    \dim_set:Nn #1 { \box_wd:N \l_tmpa_box }
  }
% 文本长度函数变体
\cs_generate_variant:Nn \l_get_text_width:Nn { NV }

% 获取clist中各个成员长度是大值，
% #1用于保存长度变量，#2是被检测clist变量
\cs_new:Npn \l_get_max_text_width:NN #1#2
  {
    \group_begin:
      % 将长度初始化为0
      \dim_zero:N #1
      \clist_set_eq:NN \l_tmpa_clist #2
      % 循环检测每个tl的长度，并更新是大值
      \bool_until_do:nn { \clist_if_empty_p:N \l_tmpa_clist }
        {
          \clist_pop:NN \l_tmpa_clist \l_tmpa_tl
          \l_get_text_width:NV \l_tmpa_dim \l_tmpa_tl
          \dim_gset:Nn #1 { \dim_max:nn {#1} { \l_tmpa_dim } }
        }
    \group_end:
  }

% 分散对齐盒子，
% #1是盒子长度变量，#2是需要排版的文字
\cs_new_protected:Npn \l_spread_box:nn #1#2
  {
    \mode_leave_vertical:
    \hbox_to_wd:nn {#1}
      { \tl_map_inline:xn {#2} { ##1 \hfil } \unskip }
  }
% 分散对齐盒子函数变体
\cs_generate_variant:Nn \l_spread_box:nn  { Vn }
\cs_generate_variant:Nn \l_spread_box:nn  { nV }

% 居中对齐盒子，
% #1是盒子长度变量，#2是需要排版的文字
\cs_new_protected:Npn \l_center_box:nn #1#2
  {
    \mode_leave_vertical:
    \dim_set:Nn \l_tmpa_dim {#1}
    \dim_add:Nn \l_tmpa_dim {0.6em}
    \makebox[0cm][l]{\rule[-0.5ex]{\l_tmpa_dim}{0.4 pt}}
      {\hbox_to_wd:nn {\l_tmpa_dim} { \hfil #2 \hfil }}
  }
% 居中对齐盒子函数变体
\cs_generate_variant:Nn \l_center_box:nn { Vn }

% 带下划线左对齐定宽盒子
\cs_new_protected:Npn \l_left_box:nn #1#2
  {
    \mode_leave_vertical:
    \dim_set:Nn \l_tmpa_dim {#1}
    \makebox[0cm][l]{\rule[-0.5ex]{\l_tmpa_dim}{0.4 pt}}
      {\hbox_to_wd:nn {\l_tmpa_dim} { #2 \hfil }}
  }
% 带下划线左对齐定宽盒子变体  
\cs_generate_variant:Nn \l_left_box:nn { Vn }  

% 为文字添加下划线
\cs_new:Npn \l_text_uline:n #1
  {
    \l_get_text_width:Nn \l_tmpa_dim {#1}
    \dim_add:Nn \l_tmpa_dim {0.6em}
    % 将标尺盒子放到宽度为0的左右盒子中实现下划线
    \makebox[0pc][l]{\rule[-0.5ex]{\l_tmpa_dim}{0.4 pt}}
      % 用高度为0的标尺盒子在文字两端添加空白
      \rule{.3em}{0cm}#1\rule{.3em}{0cm}
  }

% 定义需要的tl变量
\clist_map_inline:nn
  {
    % major, researchfield, author, supervisor, cosupervisor, date
    department, major, researchfield, supervisor, author, date
  }
  { \tl_new:c { l_info_ #1 _tl } }

% 设置tl变量值的辅助函数
\cs_new_protected:Npn \__set_info_var:nn #1#2
  { \tl_set:cn { l_info_ #1 _tl } {#2} }
% 循环设置tl变量值
\clist_map_inline:nn
  {
    { department    } { 厚大法考      },
    { major         } { 法学          },
    { researchfield } { 刑法          },
    { supervisor    } { 罗翔 \quad~ 研究员 },
    { author        } { 张三          },
    { date          } { \today        },
  }
  { \__set_info_var:nn #1 }

% 定义tl常量的辅助函数
\cs_new_protected:Npn \__define_name:nn #1#2
  { \tl_const:cn { c_name_ #1 _tl } {#2} }

% 循环定义需要的tl常量
\clist_map_inline:nn
  {
    { department    } { 培养单位 },
    { major         } { 专业     },
    { researchfield } { 研究方向 },
    { supervisor    } { 导师     },
    { author        } { 研究生   },
    { date          } { 完成时间 },
  }
  { \__define_name:nn #1 }

% 排版封面中的作者等信息
\cs_new_protected:Npn \l_cover_info:
{
  \begin{minipage} [ c ] { \textwidth }
    \centering
    % 构造各信息标识名称clist
    \clist_set:Nx \l_tmpa_clist
      {
        \c_name_department_tl,
        \c_name_major_tl,
        \c_name_researchfield_tl,
        \c_name_supervisor_tl,
        \c_name_author_tl,
        \c_name_date_tl,
      }
    % 构造各信息标识值clist
    \clist_set:Nx \l_tmpb_clist
      {
        { \l_info_department_tl    },
        { \l_info_major_tl         },
        { \l_info_researchfield_tl },
        { \l_info_supervisor_tl    },
        { \l_info_author_tl        },
        { \l_info_date_tl          }
      }
    % 计算最大长度
    \l_get_max_text_width:NN \l_tmpb_dim \l_tmpb_clist
    % 循环输出各字段
    \bool_until_do:nn { \clist_if_empty_p:N \l_tmpa_clist }
      {
        \clist_pop:NN \l_tmpa_clist \l_tmpa_tl
        \clist_pop:NN \l_tmpb_clist \l_tmpb_tl
        \heiti
        % 定宽分散对齐
        \l_spread_box:nn {4em} { \l_tmpa_tl }
        ：
        \songti
        % 定宽居中对齐
        \l_center_box:Vn \l_tmpb_dim { \l_tmpb_tl }
        \par
      }
  \end{minipage}
}

% 格式设置
\tl_const:Nn \c_title_name_tl    { 论文题目：~ }
\cs_new:Npn  \l_title_name_format: { \bfseries \Large }
\cs_new:Npn  \l_title_format:      { \sffamily \Large }
\seq_new:N \l_title_seq
\clist_new:N \l_title_clist
\dim_new:N \l_title_width_dim

% 排版封面中的题目
\cs_new_protected:Npn \l_cover_title:
  {
    \begin{center}
      \group_begin:
        \l_title_name_format:
        \tl_use:N \c_title_name_tl
      \group_end:
      \group_begin:
        \l_title_format:
        \l_get_max_text_width:NN \l_title_width_dim \l_title_clist
        \parbox [t] { \l_title_width_dim }
          {
            \seq_map_inline:Nn \l_title_seq
              % 左对齐
              { \l_left_box:Vn \l_title_width_dim { ##1 } \par }
              % 居中对齐
              % { \l_center_box:Vn \l_title_width_dim { ##1 } \par }
          }
      \group_end:
    \end{center}
  }

% 定义用户接口
% 设置标题内容，通过手动添加\&分行
\NewDocumentCommand \settitle {m}
  {
    \seq_set_split:Nnn \l_title_seq { \& } {#1}
    \clist_set_from_seq:NN \l_title_clist \l_title_seq
  }

\NewDocumentCommand \txtuline { m }
  {
    \l_text_uline:n {#1}
  }
\NewDocumentCommand \makecover { }
  {
    \dim_set:Nn \l_tmpa_dim { 7 em }
    \begin{center}    
    \l_cover_title:
    \vfill
    \l_cover_info:
    \vfill
    \end{center}
  }
\ExplSyntaxOff

% 正文区(有且只能有一个)
\begin{document}

  \settitle{这是一个很长很长很长很长\& 很长很长很长很长很长很长\& 的标题}

  \makecover

\end{document}

